From d7cf502683aa31a7ada6b55e4ca489faa6e07dd6 Mon Sep 17 00:00:00 2001 From: DerWahreKlinki <102486171+DerWahreKlinki@users.noreply.github.com> Date: Sun, 16 Jun 2024 14:51:25 +0200 Subject: [PATCH 01/37] InfluxDB Edge Timedata: handle persistence priority (#2663) * Ignore channels with a peristence priority less than a configured level * Copy logic from io.openems.edge.timedata.rrd4j.RecordWorker * Modernize & cleanup code --- .../edge/timedata/influxdb/Config.java | 4 + .../influxdb/TimedataInfluxDbImpl.java | 80 +++++++------------ .../edge/timedata/influxdb/MyConfig.java | 12 +++ .../influxdb/TimedataInfluxDbImplTest.java | 2 + 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Config.java b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Config.java index 287aec74cfe..17e01cf4e57 100644 --- a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Config.java +++ b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Config.java @@ -3,6 +3,7 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import io.openems.common.channel.PersistencePriority; import io.openems.shared.influxdb.QueryLanguageConfig; @ObjectClassDefinition(// @@ -46,5 +47,8 @@ @AttributeDefinition(name = "Read-Only mode", description = "Activates the read-only mode. Then no data is written to InfluxDB.") boolean isReadOnly() default false; + @AttributeDefinition(name = "Persistence Priority", description = "Store only Channels with a Persistence Priority above this. Be aware that too many writes can wear-out your flash storage.") + PersistencePriority persistencePriority() default PersistencePriority.MEDIUM; + String webconsole_configurationFactory_nameHint() default "Timedata InfluxDB [{id}]"; } \ No newline at end of file diff --git a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java index 10517dc27a4..22370abb9ef 100644 --- a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java +++ b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/TimedataInfluxDbImpl.java @@ -27,6 +27,7 @@ import com.influxdb.client.domain.WritePrecision; import com.influxdb.client.write.Point; +import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.oem.OpenemsEdgeOem; import io.openems.common.timedata.Resolution; @@ -127,56 +128,37 @@ protected synchronized void collectAndWriteChannelValues() { final var point = Point.measurement(this.config.measurement()).time(timestamp, WritePrecision.MS); final var addedAtLeastOneChannelValue = new AtomicBoolean(false); - this.componentManager.getEnabledComponents().stream().filter(OpenemsComponent::isEnabled) - .forEach(component -> { - component.channels().forEach(channel -> { - switch (channel.channelDoc().getAccessMode()) { - case WRITE_ONLY: - // ignore Write-Only-Channels - return; - case READ_ONLY: - case READ_WRITE: - break; - } - - Optional valueOpt = channel.value().asOptional(); - if (!valueOpt.isPresent()) { - // ignore not available channels - return; - } - Object value = valueOpt.get(); - var address = channel.address().toString(); - try { - switch (channel.getType()) { - case BOOLEAN: - point.addField(address, (Boolean) value ? 1 : 0); - break; - case SHORT: - point.addField(address, (Short) value); - break; - case INTEGER: - point.addField(address, (Integer) value); - break; - case LONG: - point.addField(address, (Long) value); - break; - case FLOAT: - point.addField(address, (Float) value); - break; - case DOUBLE: - point.addField(address, (Double) value); - break; - case STRING: - point.addField(address, (String) value); - break; - } - } catch (IllegalArgumentException e) { - this.log.warn("Unable to add Channel [" + address + "] value [" + value + "]: " - + e.getMessage()); - return; + this.componentManager.getEnabledComponents().stream() // + .flatMap(component -> component.channels().stream()) // + .filter(channel -> { + final var doc = channel.channelDoc(); + return doc.getPersistencePriority().isAtLeast(this.config.persistencePriority()) + && doc.getAccessMode() != AccessMode.WRITE_ONLY; // + }) // + .forEach(channel -> { + Optional valueOpt = channel.value().asOptional(); + if (!valueOpt.isPresent()) { + // ignore not available channels + return; + } + Object value = valueOpt.get(); + var address = channel.address().toString(); + try { + switch (channel.getType()) { + case BOOLEAN -> point.addField(address, (Boolean) value ? 1 : 0); + case SHORT -> point.addField(address, (Short) value); + case INTEGER -> point.addField(address, (Integer) value); + case LONG -> point.addField(address, (Long) value); + case FLOAT -> point.addField(address, (Float) value); + case DOUBLE -> point.addField(address, (Double) value); + case STRING -> point.addField(address, (String) value); } - addedAtLeastOneChannelValue.set(true); - }); + } catch (IllegalArgumentException e) { + this.log.warn( + "Unable to add Channel [" + address + "] value [" + value + "]: " + e.getMessage()); + return; + } + addedAtLeastOneChannelValue.set(true); }); if (addedAtLeastOneChannelValue.get()) { diff --git a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/MyConfig.java b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/MyConfig.java index 37b1713dfd0..b08d4b7666e 100644 --- a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/MyConfig.java +++ b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/MyConfig.java @@ -1,5 +1,6 @@ package io.openems.edge.timedata.influxdb; +import io.openems.common.channel.PersistencePriority; import io.openems.common.test.AbstractComponentConfig; import io.openems.shared.influxdb.QueryLanguageConfig; @@ -17,6 +18,7 @@ protected static class Builder { private String url; private QueryLanguageConfig queryLanguage; private String measurement; + private PersistencePriority persistencePriority; private Builder() { } @@ -71,6 +73,11 @@ public Builder setMeasurement(String measurement) { return this; } + public Builder setPersistencePriority(PersistencePriority persistencePriority) { + this.persistencePriority = persistencePriority; + return this; + } + public MyConfig build() { return new MyConfig(this); } @@ -132,6 +139,11 @@ public boolean isReadOnly() { return this.builder.isReadOnly; } + @Override + public PersistencePriority persistencePriority() { + return this.builder.persistencePriority; + } + @Override public String measurement() { return this.builder.measurement; diff --git a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java index 0810dcdfe68..4c097c21c69 100644 --- a/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java +++ b/io.openems.edge.timedata.influxdb/test/io/openems/edge/timedata/influxdb/TimedataInfluxDbImplTest.java @@ -2,6 +2,7 @@ import org.junit.Test; +import io.openems.common.channel.PersistencePriority; import io.openems.common.oem.DummyOpenemsEdgeOem; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; @@ -30,6 +31,7 @@ public void test() throws Exception { .setNoOfCycles(1) // .setMaxQueueSize(5000) // .setReadOnly(false) // + .setPersistencePriority(PersistencePriority.MEDIUM) .build()) // .next(new TestCase()) // ; From 625122c26170fc1b5bafcda2e0c23d3d9c8ad211 Mon Sep 17 00:00:00 2001 From: Hannes Date: Sun, 16 Jun 2024 17:17:43 +0200 Subject: [PATCH 02/37] Controller.Api.MQTT: reconnect on connection failure (#2602) # Add Reconnection Logic to MQTT Controller This PR introduces reconnection logic to the MQTT Controller, ensuring robustness in the face of connection losses with the MQTT broker. The implementation schedules reconnection attempts with an exponential backoff strategy, aiming to minimize the impact on both the broker and the controller while trying to re-establish a lost connection. # Key Changes: 1. **Scheduled Reconnection Attempts**: Utilizes a single-threaded `ScheduledExecutorService` to manage reconnection attempts, allowing for delayed execution with exponential backoff. 2. **Adaptive Delay Calculation**: Implements an adaptive delay calculation using a base delay, a maximum delay cap, and a multiplier to manage the delay between reconnection attempts, preventing aggressive reconnection attempts. 3. **Integration with Component Lifecycle**: Hooks the reconnection logic into the component's activation process, ensuring attempts to connect or reconnect are made upon activation. Similarly, ensures proper shutdown of the executor service upon deactivation to clean up resources. ## Integration: This implementation ensures that the MQTT Controller attempts to reconnect to the broker following a connection loss, employing an exponential backoff strategy to balance between prompt reconnection and avoiding overwhelming the broker or the network. --- .../api/mqtt/ControllerApiMqttImpl.java | 81 +++++++++++++++++-- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/io.openems.edge.controller.api.mqtt/src/io/openems/edge/controller/api/mqtt/ControllerApiMqttImpl.java b/io.openems.edge.controller.api.mqtt/src/io/openems/edge/controller/api/mqtt/ControllerApiMqttImpl.java index 7707612270a..07e030a0abf 100644 --- a/io.openems.edge.controller.api.mqtt/src/io/openems/edge/controller/api/mqtt/ControllerApiMqttImpl.java +++ b/io.openems.edge.controller.api.mqtt/src/io/openems/edge/controller/api/mqtt/ControllerApiMqttImpl.java @@ -1,6 +1,13 @@ package io.openems.edge.controller.api.mqtt; +import static io.openems.common.utils.ThreadPoolUtils.shutdownAndAwaitTermination; + import java.nio.charset.StandardCharsets; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.paho.mqttv5.client.IMqttClient; import org.eclipse.paho.mqttv5.common.MqttException; @@ -46,21 +53,28 @@ public class ControllerApiMqttImpl extends AbstractOpenemsComponent protected static final String COMPONENT_NAME = "Controller.Api.MQTT"; + private static final long INITIAL_RECONNECT_DELAY_SECONDS = 5; + private static final long MAX_RECONNECT_DELAY_SECONDS = 300; // 5 minutes maximum delay. + private static final double RECONNECT_DELAY_MULTIPLIER = 1.5; + private final Logger log = LoggerFactory.getLogger(ControllerApiMqttImpl.class); + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + private final AtomicInteger reconnectionAttempt = new AtomicInteger(0); private final SendChannelValuesWorker sendChannelValuesWorker = new SendChannelValuesWorker(this); private final MqttConnector mqttConnector = new MqttConnector(); + protected Config config; + + private volatile ScheduledFuture reconnectFuture = null; + private String topicPrefix; + private IMqttClient mqttClient = null; + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) private volatile Timedata timedata = null; @Reference protected ComponentManager componentManager; - protected Config config; - - private String topicPrefix; - private IMqttClient mqttClient = null; - public ControllerApiMqttImpl() { super(// OpenemsComponent.ChannelId.values(), // @@ -82,6 +96,7 @@ private void activate(ComponentContext context, Config config) throws Exception this.mqttClient = client; this.logInfo(this.log, "Connected to MQTT Broker [" + config.uri() + "]"); }); + this.scheduleReconnect(); } /** @@ -113,13 +128,13 @@ protected static String createTopicPrefix(Config config) { @Deactivate protected void deactivate() { super.deactivate(); - this.mqttConnector.deactivate(); - this.sendChannelValuesWorker.deactivate(); + shutdownAndAwaitTermination(this.scheduledExecutorService, 0); + if (this.mqttClient != null) { try { this.mqttClient.close(); } catch (MqttException e) { - this.logWarn(this.log, "Unable to close connection to MQTT brokwer: " + e.getMessage()); + this.logWarn(this.log, "Unable to close connection to MQTT broker: " + e.getMessage()); e.printStackTrace(); } } @@ -159,6 +174,7 @@ public void handleEvent(Event event) { // Trigger sending of all channel values, because a Component might have // disappeared this.sendChannelValuesWorker.sendValuesOfAllChannelsOnce(); + break; } } @@ -199,4 +215,53 @@ protected boolean publish(String subTopic, String message, int qos, boolean reta var msg = new MqttMessage(message.getBytes(StandardCharsets.UTF_8), qos, retained, properties); return this.publish(subTopic, msg); } + + private synchronized void scheduleReconnect() { + if (this.reconnectFuture != null && !this.reconnectFuture.isDone()) { + this.reconnectFuture.cancel(false); + } + + this.attemptConnect(); + } + + private void attemptConnect() { + if (this.mqttClient != null && this.mqttClient.isConnected()) { + return; // Already connected + } + try { + this.mqttConnector + .connect(this.config.uri(), this.config.clientId(), this.config.username(), this.config.password(), + this.config.certPem(), this.config.privateKeyPem(), this.config.trustStorePem()) + .thenAccept(client -> { + this.mqttClient = client; + this.logInfo(this.log, "Connected to MQTT Broker [" + this.config.uri() + "]"); + this.reconnectionAttempt.set(0); // Reset on successful connection. + }) // + .exceptionally(ex -> { + this.log.error("Failed to connect to MQTT broker: " + ex.getMessage(), ex); + this.scheduleNextAttempt(); // Schedule the next attempt with an increased delay. + return null; + }); + } catch (Exception e) { + this.log.error("Error attempting to connect to MQTT broker", e); + this.scheduleNextAttempt(); // Schedule the next attempt with an increased delay. + } + } + + private void scheduleNextAttempt() { + long delay = this.calculateNextDelay(); + // Ensure the executor service is not shut down + if (!this.scheduledExecutorService.isShutdown()) { + this.reconnectFuture = this.scheduledExecutorService.schedule(this::attemptConnect, delay, + TimeUnit.SECONDS); + } + } + + private long calculateNextDelay() { + long delay = (long) (INITIAL_RECONNECT_DELAY_SECONDS + * Math.pow(RECONNECT_DELAY_MULTIPLIER, this.reconnectionAttempt.getAndIncrement())); + delay = Math.min(delay, MAX_RECONNECT_DELAY_SECONDS); // Ensure delay does not exceed maximum + return delay; + } + } \ No newline at end of file From c7ed5d06fc15528dfb304dc827b9744fc717a32f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:33:24 +0200 Subject: [PATCH 03/37] Bump swiper from 11.1.1 to 11.1.4 in /ui (#2659) Bumps [swiper](https://github.com/nolimits4web/Swiper) from 11.1.1 to 11.1.4. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v11.1.1...v11.1.4) --- updated-dependencies: - dependency-name: swiper dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 7 ++++--- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 2042a1d21cd..88dcd29a732 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -36,7 +36,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.1", + "swiper": "11.1.4", "tslib": "^2.6.2", "uuid": "^9.0.1", "zone.js": "~0.13.3" @@ -16151,7 +16151,9 @@ } }, "node_modules/swiper": { - "version": "11.1.1", + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.4.tgz", + "integrity": "sha512-1n7kbYJB2dFEpUHRFszq7gys/ofIBrMNibwTiMvPHwneKND/t9kImnHt6CfGPScMHgI+dWMbGTycCKGMoOO1KA==", "funding": [ { "type": "patreon", @@ -16162,7 +16164,6 @@ "url": "http://opencollective.com/swiper" } ], - "license": "MIT", "engines": { "node": ">= 4.7.0" } diff --git a/ui/package.json b/ui/package.json index a90eca749bc..1254dc7838a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -31,7 +31,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.1", + "swiper": "11.1.4", "tslib": "^2.6.2", "uuid": "^9.0.1", "zone.js": "~0.13.3" From a724c17166de986dcaa45bf5f14a9780db1b1618 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:33:47 +0200 Subject: [PATCH 04/37] Bump typescript-strict-plugin from 2.4.3 to 2.4.4 in /ui (#2665) Bumps [typescript-strict-plugin](https://github.com/allegro/typescript-strict-plugin) from 2.4.3 to 2.4.4. - [Release notes](https://github.com/allegro/typescript-strict-plugin/releases) - [Changelog](https://github.com/allegro/typescript-strict-plugin/blob/master/CHANGELOG.md) - [Commits](https://github.com/allegro/typescript-strict-plugin/commits) --- updated-dependencies: - dependency-name: typescript-strict-plugin dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 8 ++++---- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 88dcd29a732..005acae9472 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -75,7 +75,7 @@ "protractor": "~7.0.0", "ts-node": "^10.9.2", "typescript": "~4.9.5", - "typescript-strict-plugin": "^2.4.3" + "typescript-strict-plugin": "^2.4.4" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -16801,9 +16801,9 @@ } }, "node_modules/typescript-strict-plugin": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.3.tgz", - "integrity": "sha512-xKdyZGKg3Sy4tPU+b0U1DuxsDoCpMbu41iQvibTPiVjdZJvtG7Ou04a9NpEWuV/Dho8Xo3c34WmROtkHZe0pkg==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.4.tgz", + "integrity": "sha512-OXcWHQk+pW9gqEL/Mb1eTgj/Yiqk1oHBERr9v4VInPOYN++p+cXejmQK/h/VlUPGD++FXQ8pgiqVMyEtxU4T6A==", "dev": true, "dependencies": { "chalk": "^3.0.0", diff --git a/ui/package.json b/ui/package.json index 1254dc7838a..717ec9f1837 100644 --- a/ui/package.json +++ b/ui/package.json @@ -70,7 +70,7 @@ "protractor": "~7.0.0", "ts-node": "^10.9.2", "typescript": "~4.9.5", - "typescript-strict-plugin": "^2.4.3" + "typescript-strict-plugin": "^2.4.4" }, "scripts": { "lint": "ng lint", From 7174d772336750bca1c6c81fd2b424722238d4ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:35:15 +0200 Subject: [PATCH 05/37] Bump @ngx-formly/ionic from 6.3.0 to 6.3.4 in /ui (#2667) Bumps [@ngx-formly/ionic](https://github.com/ngx-formly/ngx-formly) from 6.3.0 to 6.3.4. - [Release notes](https://github.com/ngx-formly/ngx-formly/releases) - [Changelog](https://github.com/ngx-formly/ngx-formly/blob/main/CHANGELOG.md) - [Commits](https://github.com/ngx-formly/ngx-formly/compare/v6.3.0...v6.3.4) --- updated-dependencies: - dependency-name: "@ngx-formly/ionic" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 14 ++++++++------ ui/package.json | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 005acae9472..339ca19b9a9 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -19,7 +19,7 @@ "@angular/service-worker": "~16.2.12", "@ionic/angular": "^6.7.5", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.0", + "@ngx-formly/ionic": "^6.3.4", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", @@ -3360,8 +3360,9 @@ } }, "node_modules/@ngx-formly/core": { - "version": "6.3.0", - "license": "MIT", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.4.tgz", + "integrity": "sha512-xpO0FB50gpQI4uDrz6nYNolMvMIOdgP19diflcvAAtDy15I4BS+tzLKOCkM9HmAwmKQ59z3FUyzaODFEu+cuEg==", "dependencies": { "tslib": "^2.0.0" }, @@ -3371,14 +3372,15 @@ } }, "node_modules/@ngx-formly/ionic": { - "version": "6.3.0", - "license": "MIT", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.4.tgz", + "integrity": "sha512-OHFZHe0E2sQoXEfYAzXMtvxt11mED2KZDjIAy0V35HGN0cC03GW1sToyTB2kmzLAyrH/HkhC3V7TurnrMbDSeQ==", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@ionic/angular": "^6.0.0 || ^7.0.0", - "@ngx-formly/core": "6.3.0" + "@ngx-formly/core": "6.3.4" } }, "node_modules/@ngx-formly/schematics": { diff --git a/ui/package.json b/ui/package.json index 717ec9f1837..20cf3b9868f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,7 +14,7 @@ "@angular/service-worker": "~16.2.12", "@ionic/angular": "^6.7.5", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.0", + "@ngx-formly/ionic": "^6.3.4", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", From 623d58b894df4afe020cf8a2628abe19175cfd6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:36:12 +0200 Subject: [PATCH 06/37] Bump uuid from 9.0.1 to 10.0.0 in /ui (#2666) Bumps [uuid](https://github.com/uuidjs/uuid) from 9.0.1 to 10.0.0. - [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md) - [Commits](https://github.com/uuidjs/uuid/compare/v9.0.1...v10.0.0) --- updated-dependencies: - dependency-name: uuid dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 7 ++++--- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 339ca19b9a9..1dc1196fbb4 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -38,7 +38,7 @@ "rxjs": "~6.6.7", "swiper": "11.1.4", "tslib": "^2.6.2", - "uuid": "^9.0.1", + "uuid": "^10.0.0", "zone.js": "~0.13.3" }, "devDependencies": { @@ -17149,12 +17149,13 @@ } }, "node_modules/uuid": { - "version": "9.0.1", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } diff --git a/ui/package.json b/ui/package.json index 20cf3b9868f..e8094c44c0a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -33,7 +33,7 @@ "rxjs": "~6.6.7", "swiper": "11.1.4", "tslib": "^2.6.2", - "uuid": "^9.0.1", + "uuid": "^10.0.0", "zone.js": "~0.13.3" }, "devDependencies": { From cbca0bdb90bc5c2564f39bea1bd42ca0cdc72422 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:01:27 +0200 Subject: [PATCH 07/37] Bump braces from 3.0.2 to 3.0.3 in /ui (#2670) * Bump swiper from 11.1.1 to 11.1.4 in /ui Bumps [swiper](https://github.com/nolimits4web/Swiper) from 11.1.1 to 11.1.4. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v11.1.1...v11.1.4) --- updated-dependencies: - dependency-name: swiper dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump typescript-strict-plugin from 2.4.3 to 2.4.4 in /ui Bumps [typescript-strict-plugin](https://github.com/allegro/typescript-strict-plugin) from 2.4.3 to 2.4.4. - [Release notes](https://github.com/allegro/typescript-strict-plugin/releases) - [Changelog](https://github.com/allegro/typescript-strict-plugin/blob/master/CHANGELOG.md) - [Commits](https://github.com/allegro/typescript-strict-plugin/commits) --- updated-dependencies: - dependency-name: typescript-strict-plugin dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump uuid from 9.0.1 to 10.0.0 in /ui Bumps [uuid](https://github.com/uuidjs/uuid) from 9.0.1 to 10.0.0. - [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md) - [Commits](https://github.com/uuidjs/uuid/compare/v9.0.1...v10.0.0) --- updated-dependencies: - dependency-name: uuid dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump @ngx-formly/ionic from 6.3.0 to 6.3.4 in /ui Bumps [@ngx-formly/ionic](https://github.com/ngx-formly/ngx-formly) from 6.3.0 to 6.3.4. - [Release notes](https://github.com/ngx-formly/ngx-formly/releases) - [Changelog](https://github.com/ngx-formly/ngx-formly/blob/main/CHANGELOG.md) - [Commits](https://github.com/ngx-formly/ngx-formly/compare/v6.3.0...v6.3.4) --- updated-dependencies: - dependency-name: "@ngx-formly/ionic" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump braces from 3.0.2 to 3.0.3 in /ui Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3. - [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3) --- updated-dependencies: - dependency-name: braces dependency-type: indirect ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 1dc1196fbb4..29378316821 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -6263,11 +6263,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "devOptional": true, - "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -9277,9 +9278,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "devOptional": true, - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -10712,8 +10714,9 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "devOptional": true, - "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -16418,8 +16421,9 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "devOptional": true, - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, From dce35842f1dd5bd6cc3950693bee0671bb29ade1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:13:55 +0200 Subject: [PATCH 08/37] Bump chart.js from 4.4.2 to 4.4.3 in /ui (#2643) updated-dependencies: - dependency-name: chart.js dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 7 ++++--- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 29378316821..13cd93805a0 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -23,7 +23,7 @@ "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", - "chart.js": "^4.4.2", + "chart.js": "^4.4.3", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", "classlist.js": "^1.1.20150312", @@ -6519,8 +6519,9 @@ "license": "MIT" }, "node_modules/chart.js": { - "version": "4.4.2", - "license": "MIT", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", "dependencies": { "@kurkle/color": "^0.3.0" }, diff --git a/ui/package.json b/ui/package.json index e8094c44c0a..1aa057eb7bf 100644 --- a/ui/package.json +++ b/ui/package.json @@ -18,7 +18,7 @@ "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", - "chart.js": "^4.4.2", + "chart.js": "^4.4.3", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", "classlist.js": "^1.1.20150312", From dc240a7bad095626c8fa296304d6b910e6f58ce8 Mon Sep 17 00:00:00 2001 From: Hannes Date: Sun, 16 Jun 2024 20:18:35 +0200 Subject: [PATCH 09/37] Implement Samsung SDI ESS System (legacy) (#2638) Implemented components: - ESS - Charger - Grid-Meter --- io.openems.edge.application/EdgeApp.bndrun | 2 + io.openems.edge.ess.samsung/.classpath | 12 + io.openems.edge.ess.samsung/.gitignore | 2 + io.openems.edge.ess.samsung/.project | 23 ++ .../org.eclipse.core.resources.prefs | 2 + io.openems.edge.ess.samsung/bnd.bnd | 19 ++ io.openems.edge.ess.samsung/readme.adoc | 8 + .../edge/ess/samsung/charger/Config.java | 29 +++ .../samsung/charger/SamsungEssCharger.java | 88 +++++++ .../charger/SamsungEssChargerImpl.java | 166 ++++++++++++ .../openems/edge/ess/samsung/ess/Config.java | 32 +++ .../edge/ess/samsung/ess/SamsungEss.java | 197 +++++++++++++++ .../edge/ess/samsung/ess/SamsungEssImpl.java | 236 ++++++++++++++++++ .../edge/ess/samsung/gridmeter/Config.java | 29 +++ .../gridmeter/SamsungEssGridMeter.java | 87 +++++++ .../gridmeter/SamsungEssGridMeterImpl.java | 194 ++++++++++++++ io.openems.edge.ess.samsung/test/.gitignore | 0 .../edge/ess/samsung/charger/MyConfig.java | 62 +++++ .../charger/SamsungEssChargerImplTest.java | 25 ++ .../edge/ess/samsung/ess/MyConfig.java | 73 ++++++ .../ess/samsung/ess/SamsungEssImplTest.java | 26 ++ .../edge/ess/samsung/gridmeter/MyConfig.java | 62 +++++ .../SamsungEssGridMeterImplTest.java | 25 ++ 23 files changed, 1399 insertions(+) create mode 100644 io.openems.edge.ess.samsung/.classpath create mode 100644 io.openems.edge.ess.samsung/.gitignore create mode 100644 io.openems.edge.ess.samsung/.project create mode 100644 io.openems.edge.ess.samsung/.settings/org.eclipse.core.resources.prefs create mode 100644 io.openems.edge.ess.samsung/bnd.bnd create mode 100644 io.openems.edge.ess.samsung/readme.adoc create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/Config.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssCharger.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssChargerImpl.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEss.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/Config.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeter.java create mode 100644 io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImpl.java create mode 100644 io.openems.edge.ess.samsung/test/.gitignore create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/MyConfig.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/SamsungEssChargerImplTest.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/MyConfig.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/SamsungEssImplTest.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/MyConfig.java create mode 100644 io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImplTest.java diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 5b4727c90a7..003fdb945f4 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -113,6 +113,7 @@ bnd.identity;id='io.openems.edge.ess.fenecon.commercial40',\ bnd.identity;id='io.openems.edge.ess.generic',\ bnd.identity;id='io.openems.edge.ess.mr.gridcon',\ + bnd.identity;id='io.openems.edge.ess.samsung',\ bnd.identity;id='io.openems.edge.ess.sma',\ bnd.identity;id='io.openems.edge.evcs.alpitronic.hypercharger',\ bnd.identity;id='io.openems.edge.evcs.cluster',\ @@ -284,6 +285,7 @@ io.openems.edge.ess.fenecon.commercial40;version=snapshot,\ io.openems.edge.ess.generic;version=snapshot,\ io.openems.edge.ess.mr.gridcon;version=snapshot,\ + io.openems.edge.ess.samsung;version=snapshot,\ io.openems.edge.ess.sma;version=snapshot,\ io.openems.edge.evcs.alpitronic.hypercharger;version=snapshot,\ io.openems.edge.evcs.api;version=snapshot,\ diff --git a/io.openems.edge.ess.samsung/.classpath b/io.openems.edge.ess.samsung/.classpath new file mode 100644 index 00000000000..bbfbdbe40e7 --- /dev/null +++ b/io.openems.edge.ess.samsung/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/io.openems.edge.ess.samsung/.gitignore b/io.openems.edge.ess.samsung/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.ess.samsung/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.ess.samsung/.project b/io.openems.edge.ess.samsung/.project new file mode 100644 index 00000000000..eacef3ce5c3 --- /dev/null +++ b/io.openems.edge.ess.samsung/.project @@ -0,0 +1,23 @@ + + + io.openems.edge.ess.samsung + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/io.openems.edge.ess.samsung/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.ess.samsung/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/io.openems.edge.ess.samsung/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/io.openems.edge.ess.samsung/bnd.bnd b/io.openems.edge.ess.samsung/bnd.bnd new file mode 100644 index 00000000000..1858db68e77 --- /dev/null +++ b/io.openems.edge.ess.samsung/bnd.bnd @@ -0,0 +1,19 @@ +Bundle-Name: OpenEMS Edge ESS Samsung +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +-buildpath: \ + ${buildpath},\ + io.openems.common,\ + io.openems.edge.bridge.http,\ + io.openems.edge.common,\ + io.openems.edge.ess.api,\ + io.openems.edge.io.api,\ + io.openems.edge.meter.api,\ + io.openems.edge.pvinverter.api,\ + io.openems.edge.thermometer.api,\ + io.openems.edge.timedata.api,\ + +-testpath: \ + ${testpath} diff --git a/io.openems.edge.ess.samsung/readme.adoc b/io.openems.edge.ess.samsung/readme.adoc new file mode 100644 index 00000000000..7e70818f5a4 --- /dev/null +++ b/io.openems.edge.ess.samsung/readme.adoc @@ -0,0 +1,8 @@ += Samsung ESS + +This bundle implements the Samsung SDI ESS. + +Compatible with +- https://www.photovoltaik4all.de/speicher/samsung/samsung-sdi-lithium-ionen-speicher-3-6-kwh/SA23695 + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.ess.samsung[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/Config.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/Config.java new file mode 100644 index 00000000000..60b745cf475 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/Config.java @@ -0,0 +1,29 @@ +package io.openems.edge.ess.samsung.charger; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; + +@ObjectClassDefinition(// + name = "Samsung ESS Charger", // + description = "Implements the Samsung ESS Charger.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "charger0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the ESS.") + String ip() default ""; + + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.PRODUCTION; + + String webconsole_configurationFactory_nameHint() default "Samsung ESS Charger [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssCharger.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssCharger.java new file mode 100644 index 00000000000..8e526a3f123 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssCharger.java @@ -0,0 +1,88 @@ +package io.openems.edge.ess.samsung.charger; + +import org.osgi.service.event.EventHandler; + +import io.openems.common.channel.Level; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.pvinverter.api.ManagedSymmetricPvInverter; + +public interface SamsungEssCharger + extends ElectricityMeter, OpenemsComponent, EventHandler, ManagedSymmetricPvInverter { + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Warning when one or more Inverters are not reachable. + * + *
    + *
  • Type: State + *
+ */ + COMMUNICATION_FAILED(Doc.of(Level.FAULT) // + .text("Samsung ESS not reachable or wrong output!")), + + /** + * Measures the power produced by photovoltaic (PV) panels. + * + *
    + *
  • Type: Double
  • + *
+ */ + PV_PW(Doc.of(OpenemsType.DOUBLE) // + .text("PV Power")); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setPvPw(double value) { + this.channel(ChannelId.PV_PW).setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssChargerImpl.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssChargerImpl.java new file mode 100644 index 00000000000..8b6af1cabf7 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/charger/SamsungEssChargerImpl.java @@ -0,0 +1,166 @@ +package io.openems.edge.ess.samsung.charger; + +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static java.lang.Math.round; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.pvinverter.api.ManagedSymmetricPvInverter; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Samsung.ESS.Charger", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE) + +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE, // +}) +public class SamsungEssChargerImpl extends AbstractOpenemsComponent implements SamsungEssCharger, ElectricityMeter, + OpenemsComponent, EventHandler, TimedataProvider, ManagedSymmetricPvInverter { + + private final Logger log = LoggerFactory.getLogger(SamsungEssChargerImpl.class); + private final CalculateEnergyFromPower calculateActualEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + + @Reference + protected ConfigurationAdmin cm; + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + private String baseUrl; + private Config config; + + public SamsungEssChargerImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + SamsungEssCharger.ChannelId.values(), // + ManagedSymmetricPvInverter.ChannelId.values() // + ); + ElectricityMeter.calculatePhasesFromActivePower(this); + } + + @Activate + private void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + this.config = config; + + if (!this.isEnabled()) { + return; + } + + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/R3EMSAPP_REAL.ems?file=ESSRealtimeStatus.json", + this::fetchAndUpdateEssRealtimeStatus); + } + + @Override + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: + this.calculateEnergy(); + break; + } + } + + private void fetchAndUpdateEssRealtimeStatus(HttpResponse result, HttpError error) { + Integer pvPower = null; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var response = getAsJsonObject(result.data()); + var essRealtimeStatus = getAsJsonObject(response, "ESSRealtimeStatus"); + + pvPower = round(getAsFloat(essRealtimeStatus, "PvPw") * 1000); + + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + this._setActivePower(pvPower); + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + var actualPower = this.getActivePower().get(); + if (actualPower == null) { + this.calculateActualEnergy.update(null); + } else if (actualPower > 0) { + this.calculateActualEnergy.update(actualPower); + } else { + this.calculateActualEnergy.update(0); + } + } + + @Override + public String debugLog() { + return "L:" + this.getActivePower().asString(); // + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public MeterType getMeterType() { + return this.config.type(); + } + +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java new file mode 100644 index 00000000000..9b96d04d16d --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java @@ -0,0 +1,32 @@ +package io.openems.edge.ess.samsung.ess; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.ess.power.api.Phase; + +@ObjectClassDefinition(// + name = "Samsung ESS", // + description = "Implements the Sasmung ESS Combined System.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "ess0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Phase", description = "Which Phase is this ESS connected to?") + Phase phase() default Phase.L1; + + @AttributeDefinition(name = "Capacity", description = "The Capacity of the ESS in Wh") + int capacity() default 3600; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the ESS.") + String ip() default ""; + + String webconsole_configurationFactory_nameHint() default "Samsung ESS [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEss.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEss.java new file mode 100644 index 00000000000..84d064fe637 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEss.java @@ -0,0 +1,197 @@ +package io.openems.edge.ess.samsung.ess; + +import org.osgi.service.event.EventHandler; + +import io.openems.common.channel.Level; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.api.SymmetricEss; + +public interface SamsungEss extends SymmetricEss, OpenemsComponent, EventHandler { + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Warning when one or more Inverters are not reachable. + * + *
    + *
  • Type: State + *
+ */ + SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT) // + .text("Samsung ESS not reachable!")), + + /** + * Describes the collection time. This represents the timestamp at which data + * was collected or recorded. + * + *
    + *
  • Type: String
  • + *
+ */ + COLEC_TM(Doc.of(OpenemsType.STRING) // + .text("Collection Time")), + + /** + * Measures the power imported from or exported to the grid. + * + *
    + *
  • Type: Double
  • + *
+ */ + GRID_PW(Doc.of(OpenemsType.DOUBLE) // + .text("Grid Power")), + + /** + * Measures the power produced by photovoltaic (PV) panels. + * + *
    + *
  • Type: Double
  • + *
+ */ + PV_PW(Doc.of(OpenemsType.DOUBLE) // + .text("PV Power")), + + /** + * Indicates the absolute discharge power. + * + *
    + *
  • Type: Double
  • + *
+ */ + ABS_DSC_POWER(Doc.of(OpenemsType.DOUBLE) // + .text("Absolute Discharge Power")), + + /** + * Measures the total power consumption of the system or facility. + * + *
    + *
  • Type: Double
  • + *
+ */ + CONS_PW(Doc.of(OpenemsType.DOUBLE) // + .text("Consumption Power")), + + /** + * Reports the current state of charge of the battery. This percentage reflects + * the remaining energy capacity of the battery. + * + *
    + *
  • Type: Integer
  • + *
+ */ + BT_SOC(Doc.of(OpenemsType.INTEGER) // + .text("Battery State of Charge")), + + /** + * Accumulates the total energy consumed actively by the system or facility. + * This parameter is typically measured in kilowatt-hours. + * + *
    + *
  • Type: Integer
  • + *
+ */ + ACTIVE_CONSUMPTION_ENERGY(Doc.of(OpenemsType.INTEGER) // + .text("Active Consumption Energy")), + + /** + * Accumulates the total energy produced actively by the system. This value is + * crucial for calculating the efficiency and output of energy production + * systems. + * + *
    + *
  • Type: Integer
  • + *
+ */ + ACTIVE_PRODUCTION_ENERGY(Doc.of(OpenemsType.INTEGER) // + .text("Active Production Energy")); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setGridPw(double value) { + this.channel(ChannelId.GRID_PW).setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setPvPw(double value) { + this.channel(ChannelId.PV_PW).setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setAbsPcsPw(double value) { + this.channel(ChannelId.ABS_DSC_POWER).setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#CONS_PW} Channel. + * + * @param value the next value + */ + public default void _setConsPw(double value) { + this.channel(ChannelId.CONS_PW).setNextValue(value); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#BT_SOC} Channel. + * + * @param value the next value + */ + public default void _setBtSoc(int value) { + this.channel(ChannelId.BT_SOC).setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java new file mode 100644 index 00000000000..d4e04fd5b95 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java @@ -0,0 +1,236 @@ +package io.openems.edge.ess.samsung.ess; + +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static java.lang.Math.round; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.sum.GridMode; +import io.openems.edge.ess.api.HybridEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.dccharger.api.EssDcCharger; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Samsung.ESS", immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE// +) + +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // +}) +public class SamsungEssImpl extends AbstractOpenemsComponent + implements SamsungEss, SymmetricEss, OpenemsComponent, EventHandler, TimedataProvider, HybridEss { + + private final Logger log = LoggerFactory.getLogger(SamsungEssImpl.class); + private final CalculateEnergyFromPower calculateAcChargeEnergy = new CalculateEnergyFromPower(this, + SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY); + private final CalculateEnergyFromPower calculateAcDischargeEnergy = new CalculateEnergyFromPower(this, + SymmetricEss.ChannelId.ACTIVE_DISCHARGE_ENERGY); + private final CalculateEnergyFromPower calculateDcChargeEnergy = new CalculateEnergyFromPower(this, + HybridEss.ChannelId.DC_CHARGE_ENERGY); + private final CalculateEnergyFromPower calculateDcDischargeEnergy = new CalculateEnergyFromPower(this, + HybridEss.ChannelId.DC_DISCHARGE_ENERGY); + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata = null; + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + private String baseUrl; + private Integer latestGridPw = 0; + private Integer latestPvPw = 0; + private Integer latestPcsPw = 0; + private Integer latestConsPw = 0; + private Integer latestBatteryStatus = -1; + private Integer latestGridStatus = -1; + + public SamsungEssImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + SymmetricEss.ChannelId.values(), // + SamsungEss.ChannelId.values(), // + EssDcCharger.ChannelId.values(), // + HybridEss.ChannelId.values() // + // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + this._setCapacity(config.capacity()); + this._setGridMode(GridMode.ON_GRID); // Has no Backup function + + if (!this.isEnabled()) { + return; + } + + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/R3EMSAPP_REAL.ems?file=ESSRealtimeStatus.json", + this::fetchAndUpdateEssRealtimeStatus); + } + + @Override + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: + this.calculateEnergy(); + break; + } + } + + private void fetchAndUpdateEssRealtimeStatus(HttpResponse result, HttpError error) { + Integer pvPw = null; + Integer pcsPw = null; + Integer gridPw = null; + Integer consPw = null; + Integer batteryStatus = null; + Integer gridStatus = null; + Integer soc = null; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var response = getAsJsonObject(result.data()); + var essRealtimeStatus = getAsJsonObject(response, "ESSRealtimeStatus"); + pvPw = round(getAsFloat(essRealtimeStatus, "PvPw") * 1000); + pcsPw = round(getAsFloat(essRealtimeStatus, "PcsPw")); + gridPw = round(getAsFloat(essRealtimeStatus, "GridPw")); + consPw = round(getAsFloat(essRealtimeStatus, "ConsPw")); + batteryStatus = getAsInt(essRealtimeStatus, "BtStusCd"); + gridStatus = getAsInt(essRealtimeStatus, "GridStusCd"); + soc = round(getAsInt(essRealtimeStatus, "BtSoc")); + + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + var dcDischargePower = switch (batteryStatus) { + // Battery is in Discharge mode + case 0 -> null; + // Battery is in Charge mode + case 1 -> pcsPw; + // Battery is in Idle mode + case 2 -> 0; + // Handle unknown status codes + default -> { + this.logWarn(this.log, "Unknown Battery Status Code: " + batteryStatus); + yield null; + } + }; + + this._setSlaveCommunicationFailed(error != null); + this._setActivePower(pcsPw - pvPw); + this._setDcDischargePower(dcDischargePower); + this._setSoc(soc); + + this.latestPvPw = pvPw; + this.latestPcsPw = pcsPw; + this.latestGridPw = gridPw; + this.latestConsPw = consPw; + this.latestBatteryStatus = batteryStatus; + this.latestGridStatus = gridStatus; + } + + @Override + public String debugLog() { + return "SoC:" + this.getSoc().asString() // + + "|L:" + this.getActivePower().asString(); + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public Integer getSurplusPower() { + // Adjust the sign of gridPw and pcsPw based on the status codes + if (this.latestGridStatus == 1) { + this.latestGridPw = -this.latestGridPw; + } + if (this.latestBatteryStatus == 0) { + this.latestPcsPw = -this.latestPcsPw; + } + + // Calculate surplus power + double surplusPower = (this.latestGridPw + this.latestPvPw) - (this.latestPcsPw + this.latestConsPw); + // Return the surplus power or 'null' if there is no surplus power + return surplusPower > 0 ? (int) surplusPower : null; + } + + private void calculateEnergy() { + // Calculate AC Energy + var activePower = this.getActivePowerChannel().getNextValue().get(); + if (activePower == null) { + // Not available + this.calculateAcChargeEnergy.update(null); + this.calculateAcDischargeEnergy.update(null); + this.calculateDcChargeEnergy.update(null); + this.calculateDcDischargeEnergy.update(null); + } else { + if (activePower > 0) { + // Discharge + this.calculateAcChargeEnergy.update(0); + this.calculateAcDischargeEnergy.update(activePower); + this.calculateDcChargeEnergy.update(0); + this.calculateDcDischargeEnergy.update(activePower); + } else { + // Charge + this.calculateAcChargeEnergy.update(activePower * -1); + this.calculateAcDischargeEnergy.update(0); + this.calculateDcChargeEnergy.update(activePower * -1); + this.calculateDcDischargeEnergy.update(0); + } + } + } + +} diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/Config.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/Config.java new file mode 100644 index 00000000000..23a064d4734 --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/Config.java @@ -0,0 +1,29 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; + +@ObjectClassDefinition(// + name = "Samsung ESS Grid-Meter", // + description = "Implements the Samsung ESS Grid-Meter.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "meter0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the ESS.") + String ip(); + + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.GRID; + + String webconsole_configurationFactory_nameHint() default "Samsung ESS Grid-Meter [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeter.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeter.java new file mode 100644 index 00000000000..169099b62fa --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeter.java @@ -0,0 +1,87 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import org.osgi.service.event.EventHandler; + +import io.openems.common.channel.Level; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.pvinverter.api.ManagedSymmetricPvInverter; + +public interface SamsungEssGridMeter + extends ElectricityMeter, OpenemsComponent, EventHandler, ManagedSymmetricPvInverter { + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Warning when one or more Inverters are not reachable. + * + *
    + *
  • Type: State + *
+ */ + GRID_COMMUNICATION_FAILED(Doc.of(Level.FAULT) // + .text("Samsung Grid Meter not reachable!")), + /** + * Measures the power imported from or exported to the grid. + * + *
    + *
  • Type: Double
  • + *
+ */ + GRID_PW(Doc.of(OpenemsType.DOUBLE) // + .text("PV Power")); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#GRID_PW} Channel. + * + * @param value the next value + */ + public default void _setPvPw(double value) { + this.channel(ChannelId.GRID_PW).setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.GRID_COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImpl.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImpl.java new file mode 100644 index 00000000000..aafac47ce2f --- /dev/null +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImpl.java @@ -0,0 +1,194 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static java.lang.Math.round; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Samsung.ESS.Grid-Meter", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE) + +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // +}) +public class SamsungEssGridMeterImpl extends AbstractOpenemsComponent + implements SamsungEssGridMeter, ElectricityMeter, OpenemsComponent, EventHandler, TimedataProvider { + + private final Logger log = LoggerFactory.getLogger(SamsungEssGridMeterImpl.class); + private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); + + @Reference + protected ConfigurationAdmin cm; + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + private String currentGridStatus = "Unknown"; + private String baseUrl; + private Config config; + + public SamsungEssGridMeterImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + SamsungEssGridMeter.ChannelId.values() // + ); + ElectricityMeter.calculatePhasesFromActivePower(this); + } + + @Activate + private void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + this.config = config; + + if (!this.isEnabled()) { + return; + } + + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/R3EMSAPP_REAL.ems?file=ESSRealtimeStatus.json", + this::fetchAndUpdateEssRealtimeStatus); + } + + @Override + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: + this.calculateEnergy(); // Call the calculateEnergy method here + break; + } + } + + private void fetchAndUpdateEssRealtimeStatus(HttpResponse result, HttpError error) { + Integer gridPw = null; + String currentGridStatus = "Unknown"; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + } else { + try { + + var response = getAsJsonObject(result.data()); + var essRealtimeStatus = getAsJsonObject(response, "ESSRealtimeStatus"); + + gridPw = round(getAsFloat(essRealtimeStatus, "GridPw") * 1000); + var gridStatusCode = getAsInt(essRealtimeStatus, "GridStusCd"); + + switch (gridStatusCode) { + case 0: + // Buy from Grid is positive + currentGridStatus = "Buy from Grid"; + break; + + case 1: + // Sell to Grid is negative + gridPw = -gridPw; + currentGridStatus = "Sell to Grid"; + + break; + default: + // Handle unknown status codes if needed + currentGridStatus = "Unknown"; + gridPw = 0; + + } + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + this._setActivePower(gridPw); + + this.currentGridStatus = currentGridStatus; + } + + private void calculateEnergy() { + Integer activePower = this.getActivePower().orElse(null); + if (activePower == null) { + // Not available + this.calculateProductionEnergy.update(null); + this.calculateConsumptionEnergy.update(null); + } else if (activePower > 0) { + // Buy-From-Grid + this.calculateProductionEnergy.update(activePower); + this.calculateConsumptionEnergy.update(0); + } else { + // Sell-To-Grid + this.calculateProductionEnergy.update(0); + this.calculateConsumptionEnergy.update(-activePower); + } + } + + @Override + public String debugLog() { + return "L:" + this.getActivePower().asString() // + + " |Status: " + this.currentGridStatus; + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public MeterType getMeterType() { + return this.config.type(); + } + +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/.gitignore b/io.openems.edge.ess.samsung/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/MyConfig.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/MyConfig.java new file mode 100644 index 00000000000..643021116ee --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/MyConfig.java @@ -0,0 +1,62 @@ +package io.openems.edge.ess.samsung.charger; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.meter.api.MeterType; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private MeterType type; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public MeterType type() { + return this.builder.type; + } +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/SamsungEssChargerImplTest.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/SamsungEssChargerImplTest.java new file mode 100644 index 00000000000..ba3891b1616 --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/charger/SamsungEssChargerImplTest.java @@ -0,0 +1,25 @@ +package io.openems.edge.ess.samsung.charger; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.meter.api.MeterType; + +public class SamsungEssChargerImplTest { + + private static final String COMPONENT_ID = "charger0"; + + @Test + public void test() throws Exception { + new ComponentTest(new SamsungEssChargerImpl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setType(MeterType.PRODUCTION) // + .build()) // + ; + } + +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/MyConfig.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/MyConfig.java new file mode 100644 index 00000000000..b6bdecba198 --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/MyConfig.java @@ -0,0 +1,73 @@ +package io.openems.edge.ess.samsung.ess; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.ess.power.api.Phase; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private Phase phase; + private int capacity; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setPhase(Phase phase) { + this.phase = phase; + return this; + } + + public Builder setCapacity(int capacity) { + this.capacity = capacity; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public Phase phase() { + return this.builder.phase; + } + + @Override + public int capacity() { + return this.builder.capacity; + } +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/SamsungEssImplTest.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/SamsungEssImplTest.java new file mode 100644 index 00000000000..c67ca193fad --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/ess/SamsungEssImplTest.java @@ -0,0 +1,26 @@ +package io.openems.edge.ess.samsung.ess; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.ess.power.api.Phase; + +public class SamsungEssImplTest { + + private static final String COMPONENT_ID = "charger0"; + + @Test + public void test() throws Exception { + new ComponentTest(new SamsungEssImpl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setPhase(Phase.L1) // + .setCapacity(3600) // + .build()) // + ; + } + +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/MyConfig.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/MyConfig.java new file mode 100644 index 00000000000..fc924bc6e93 --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/MyConfig.java @@ -0,0 +1,62 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.meter.api.MeterType; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private MeterType type; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public MeterType type() { + return this.builder.type; + } +} \ No newline at end of file diff --git a/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImplTest.java b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImplTest.java new file mode 100644 index 00000000000..50d708ab648 --- /dev/null +++ b/io.openems.edge.ess.samsung/test/io/openems/edge/ess/samsung/gridmeter/SamsungEssGridMeterImplTest.java @@ -0,0 +1,25 @@ +package io.openems.edge.ess.samsung.gridmeter; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.meter.api.MeterType; + +public class SamsungEssGridMeterImplTest { + + private static final String COMPONENT_ID = "charger0"; + + @Test + public void test() throws Exception { + new ComponentTest(new SamsungEssGridMeterImpl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setType(MeterType.GRID) // + .build()) // + ; + } + +} \ No newline at end of file From 27eaf50221908899a03186d469ef1ea14d8e2a2d Mon Sep 17 00:00:00 2001 From: Hannes Date: Mon, 17 Jun 2024 14:52:52 +0200 Subject: [PATCH 10/37] UI: fix ion-row css-syntax-error (#2628) --- ui/src/app/shared/footer/footer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/app/shared/footer/footer.ts b/ui/src/app/shared/footer/footer.ts index 38539365640..926db2d72d0 100644 --- a/ui/src/app/shared/footer/footer.ts +++ b/ui/src/app/shared/footer/footer.ts @@ -21,11 +21,11 @@ import { Role } from "../type/role"; width: 100%; font-size: 14px !important; - ion-row { + :is(ion-row) { text-align: center; } - ion-item { + :is(ion-item) { --min-height: initial !important; font-size: inherit; } From 93a384a86a8986a85d083d07cbfbcbdfba85df30 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:56:44 +0200 Subject: [PATCH 11/37] Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.16 to 5.1.20 in /cnf (#2673) * Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.16 to 5.1.20. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 29b68ef06d0..2231de4e1b2 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.16 + 5.1.20 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index e4c9ac0e3c4..03d14f79f83 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -104,7 +104,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.16,5.1.17)',\ + org.apache.felix.http.jetty;version='[5.1.20,5.1.21)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 003fdb945f4..6e383385d34 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -400,7 +400,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.16,5.1.17)',\ + org.apache.felix.http.jetty;version='[5.1.20,5.1.21)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From e51be8db51868ab8ef1e75936ee5d03603d95675 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:09:58 +0200 Subject: [PATCH 12/37] Bump @stylistic/eslint-plugin from 2.1.0 to 2.2.1 in /ui (#2674) Bumps [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin) from 2.1.0 to 2.2.1. - [Release notes](https://github.com/eslint-stylistic/eslint-stylistic/releases) - [Changelog](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint-stylistic/eslint-stylistic/commits/v2.2.1/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@stylistic/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 153 ++++++++++++++++++++++--------------------- ui/package.json | 2 +- 2 files changed, 78 insertions(+), 77 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 13cd93805a0..b6b69c0cf64 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -52,7 +52,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.1.0", + "@stylistic/eslint-plugin": "^2.2.1", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", @@ -3959,15 +3959,15 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.1.0.tgz", - "integrity": "sha512-cBBowKP2u/+uE5CzgH5w8pE9VKqcM7BXdIDPIbGt2rmLJGnA6MJPr9vYGaqgMoJFs7R/FzsMQerMvvEP40g2uw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.2.1.tgz", + "integrity": "sha512-YErqfwWFbRCpkyPtrcVYaJhvEn9aXE4WzxxkZ7Q3OKS4QD9CE6qZjzEw5DhcA2wL3Jo6JbzSB3/stJMNocGMgQ==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "2.1.0", - "@stylistic/eslint-plugin-jsx": "2.1.0", - "@stylistic/eslint-plugin-plus": "2.1.0", - "@stylistic/eslint-plugin-ts": "2.1.0", + "@stylistic/eslint-plugin-js": "2.2.1", + "@stylistic/eslint-plugin-jsx": "2.2.1", + "@stylistic/eslint-plugin-plus": "2.2.1", + "@stylistic/eslint-plugin-ts": "2.2.1", "@types/eslint": "^8.56.10" }, "engines": { @@ -3978,9 +3978,9 @@ } }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.1.0.tgz", - "integrity": "sha512-gdXUjGNSsnY6nPyqxu6lmDTtVrwCOjun4x8PUn0x04d5ucLI74N3MT1Q0UhdcOR9No3bo5PGDyBgXK+KmD787A==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.2.1.tgz", + "integrity": "sha512-M2dQkKw2R4R+b1SJ/xElJ9bDVq/vCI31VpIIxkZD9KXCqbUHvtsGpZH3eO6MzmFWOZj4PfNdEQdP332MtqjCPg==", "dev": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -4008,12 +4008,12 @@ } }, "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", - "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, "dependencies": { - "acorn": "^8.11.3", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.0.0" }, @@ -4025,12 +4025,12 @@ } }, "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.1.0.tgz", - "integrity": "sha512-mMD7S+IndZo2vxmwpHVTCwx2O1VdtE5tmpeNwgaEcXODzWV1WTWpnsc/PECQKIr/mkLPFWiSIqcuYNhQ/3l6AQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.2.1.tgz", + "integrity": "sha512-J/R4tU38v8gVqKPy6Mh22dq8btLSPWK06SuRc/ryOxT8LpW2ZdcSDP4HNvQiOte0Wy9xzgKJHP4JlYauDZ/oVw==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "^2.1.0", + "@stylistic/eslint-plugin-js": "^2.2.1", "@types/eslint": "^8.56.10", "estraverse": "^5.3.0", "picomatch": "^4.0.2" @@ -4064,26 +4064,26 @@ } }, "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.1.0.tgz", - "integrity": "sha512-S5QAlgYXESJaSBFhBSBLZy9o36gXrXQwWSt6QkO+F0SrT9vpV5JF/VKoh+ojO7tHzd8Ckmyouq02TT9Sv2B0zQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.2.1.tgz", + "integrity": "sha512-VGdTcQzZ/cZNcJnvjDos1VLzUerPapvYCVSCQZEhupMtmxt+mbITiJWzLLHYNfqGBnW7ABqViLfob+s3Q2GcKw==", "dev": true, "dependencies": { "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.8.0" + "@typescript-eslint/utils": "^7.12.0" }, "peerDependencies": { "eslint": "*" } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", + "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4094,9 +4094,9 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", + "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4107,13 +4107,13 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", + "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4135,15 +4135,15 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4157,12 +4157,12 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", + "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/types": "7.13.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -4227,14 +4227,14 @@ } }, "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.1.0.tgz", - "integrity": "sha512-2ioFibufHYBALx2TBrU4KXovCkN8qCqcb9yIHc0fyOfTaO5jw4d56WW7YRcF3Zgde6qFyXwAN6z/+w4pnmos1g==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.2.1.tgz", + "integrity": "sha512-2AbpXGGorCEzDryth7RhOMJWlko+sxSs1lxL2tSXB5H/EffmXgLn1tMoMKgwYJW3s6v0BxJRr5BWj9B9JaZTUQ==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "2.1.0", + "@stylistic/eslint-plugin-js": "2.2.1", "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.8.0" + "@typescript-eslint/utils": "^7.12.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4244,13 +4244,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", + "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4261,9 +4261,9 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", + "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4274,13 +4274,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", + "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4302,15 +4302,15 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4324,12 +4324,12 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", + "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/types": "7.13.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -5462,9 +5462,10 @@ } }, "node_modules/acorn": { - "version": "8.11.3", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, diff --git a/ui/package.json b/ui/package.json index 1aa057eb7bf..0d3a435f1cc 100644 --- a/ui/package.json +++ b/ui/package.json @@ -47,7 +47,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.1.0", + "@stylistic/eslint-plugin": "^2.2.1", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", From ce7f4cf79c2935cddea970a89927947255e952d0 Mon Sep 17 00:00:00 2001 From: Hannes Date: Wed, 19 Jun 2024 10:34:50 +0200 Subject: [PATCH 13/37] Implement ShellyPro3Em + fix issue in EdgeConfig (#2567) * ShellyPro3Em Implements Shelly Pro 3 EM 3-Phase Meter. https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1 * EdgeConfig: fix parsing of service components Previously `constains()` would match even partly matching factory IDs. This is fixed by a full string compare for the XML file path. This fixes an issue with "Samsung.ESS" not showing up, because there is also a factory ID "Samsung.ESS.Grid-Meter". --------- Co-authored-by: Stefan Feilmeier --- .../componentmanager/EdgeConfigWorker.java | 4 +- .../openems/edge/ess/samsung/ess/Config.java | 2 +- .../edge/ess/samsung/ess/SamsungEssImpl.java | 4 +- io.openems.edge.io.shelly/readme.adoc | 1 + .../edge/io/shelly/shellypro3em/Config.java | 30 +++ .../shelly/shellypro3em/IoShellyPro3Em.java | 117 ++++++++++ .../shellypro3em/IoShellyPro3EmImpl.java | 219 ++++++++++++++++++ .../shellypro3em/IoShelly3EmImplTest.java | 25 ++ .../edge/io/shelly/shellypro3em/MyConfig.java | 62 +++++ 9 files changed, 459 insertions(+), 5 deletions(-) create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/Config.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/MyConfig.java diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java index 23dbf32ea80..9679cfb5a6a 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/EdgeConfigWorker.java @@ -495,8 +495,8 @@ private String[] getNatures(Bundle bundle, Manifest manifest, String factoryPid) var serviceComponents = serviceComponentsString.split(","); // read Service-Component XML files from OSGI-INF folder - for (String serviceComponent : serviceComponents) { - if (!serviceComponent.contains(factoryPid)) { + for (var serviceComponent : serviceComponents) { + if (!serviceComponent.equals("OSGI-INF/" + factoryPid + ".xml")) { // search for correct XML file continue; } diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java index 9b96d04d16d..02f59e64887 100644 --- a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/Config.java @@ -7,7 +7,7 @@ @ObjectClassDefinition(// name = "Samsung ESS", // - description = "Implements the Sasmung ESS Combined System.") + description = "Implements the Samsung ESS System.") @interface Config { @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") diff --git a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java index d4e04fd5b95..cce31ff8a29 100644 --- a/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java +++ b/io.openems.edge.ess.samsung/src/io/openems/edge/ess/samsung/ess/SamsungEssImpl.java @@ -41,10 +41,10 @@ @Designate(ocd = Config.class, factory = true) @Component(// - name = "Samsung.ESS", immediate = true, // + name = "Samsung.ESS", // + immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE// ) - @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // }) diff --git a/io.openems.edge.io.shelly/readme.adoc b/io.openems.edge.io.shelly/readme.adoc index 16eed94af93..220c84fcbb4 100644 --- a/io.openems.edge.io.shelly/readme.adoc +++ b/io.openems.edge.io.shelly/readme.adoc @@ -7,5 +7,6 @@ Compatible with - https://www.shelly.com/en/products/shop/shelly-3-em[Shelly 3EM] - Shelly Plug S - https://www.shelly.com/de/products/shop/shelly-plus-plug-s-1[Shelly Plus Plug S] +- https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1[Shelly Pro 3EM 3-Phase Meter] https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.io.shelly[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/Config.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/Config.java new file mode 100644 index 00000000000..b594f9b1603 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/Config.java @@ -0,0 +1,30 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; + +@ObjectClassDefinition( + name = "IO Shelly Pro 3EM", // + description = "Implements the Shelly Pro 3EM Energy Meter.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "meter0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Meter-Type", description = "Grid, Production (=default), Consumption") + MeterType type() default MeterType.GRID; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the Shelly device.") + String ip(); + + String webconsole_configurationFactory_nameHint() default "IO Shelly Pro 3EM [{id}]"; + +} \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java new file mode 100644 index 00000000000..c5899305afe --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3Em.java @@ -0,0 +1,117 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import io.openems.common.channel.Level; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.channel.value.Value; + +public interface IoShellyPro3Em extends OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Phase Sequence Error. + * + *

+ * Represents an error indicating if the sequence of zero-crossing events is + * Phase A followed by Phase C followed by Phase B. The regular succession of + * these zero-crossing events is Phase A followed by Phase B followed by Phase + * C. + * + *

    + *
  • Interface: ShellyPlug + *
  • Type: State + *
+ */ + PHASE_SEQUENCE_ERROR(Doc.of(Level.FAULT) // + .text("Incorrect phase sequence. Expected A-B-C but found A-C-B.")), + + /** + * Power Meter Failure. + * + *

+ * Represents a failure in the power meter, potentially leading to inaccurate or + * missing measurements. + * + *

    + *
  • Interface: ShellyPlug + *
  • Type: State + *
+ */ + POWER_METER_FAILURE(Doc.of(Level.FAULT) // + .text("Power meter failure; unable to record or measure power accurately.")), + + /** + * No Load Error. + * + *

+ * Indicates that the power meter is in a no-load condition and is not + * accumulating the registered energies, therefore, the measured values can be + * discarded. + * + *

    + *
  • Interface: ShellyPlug + *
  • Type: State + *
+ */ + NO_LOAD(Doc.of(Level.FAULT) // + .text("No load condition detected; the power meter is not accumulating energy.")), + + /** + * Slave Communication Failed Fault. + * + *

+ * Indicates a failure in communication with a slave device, which might affect + * system operations. + * + *

    + *
  • Interface: ShellyPlug + *
  • Type: State + *
+ */ + SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT) // + .text("Communication with slave device failed.")); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the StateChannel representing communication failure with a slave + * device. + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED); + } + + /** + * Gets the current state of the Slave Communication Failed channel. + * + * @return the Channel {@link Value} indicating whether communication has + * failed. + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value indicating communication failure state. + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java new file mode 100644 index 00000000000..dfa0c2085b4 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java @@ -0,0 +1,219 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.common.utils.JsonUtils.getAsOptionalJsonArray; +import static io.openems.common.utils.JsonUtils.getAsString; +import static java.lang.Math.round; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "IO.Shelly.Pro.3EM", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE, // + EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // +}) +public class IoShellyPro3EmImpl extends AbstractOpenemsComponent + implements IoShellyPro3Em, ElectricityMeter, OpenemsComponent, TimedataProvider, EventHandler { + + private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); + + private final Logger log = LoggerFactory.getLogger(IoShellyPro3EmImpl.class); + + private MeterType meterType = null; + private String baseUrl; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + @Reference() + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + public IoShellyPro3EmImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + IoShellyPro3Em.ChannelId.values() // + ); + + ElectricityMeter.calculateSumActivePowerFromPhases(this); + } + + @Activate + protected void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.meterType = config.type(); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + + if (this.isEnabled()) { + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/rpc/EM.GetStatus?id=0", this::processHttpResult); + } + } + + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public String debugLog() { + return "L:" + this.getActivePower().asString(); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + -> this.calculateEnergy(); + } + } + + private void processHttpResult(HttpResponse result, HttpError error) { + this._setSlaveCommunicationFailed(result == null); + + Integer activePower = null; + Integer activePowerL1 = null; + Integer activePowerL2 = null; + Integer activePowerL3 = null; + Integer voltageL1 = null; + Integer voltageL2 = null; + Integer voltageL3 = null; + Integer currentL1 = null; + Integer currentL2 = null; + Integer currentL3 = null; + boolean phaseSequenceError = false; + boolean powerMeterFailure = false; + boolean noLoadCondition = false; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var response = getAsJsonObject(result.data()); + + // Check for 'errors' and process if present + var errors = getAsOptionalJsonArray(response, "errors"); + if (errors.isPresent()) { + for (var e : errors.get()) { + switch (getAsString(e)) { + case "phase_sequence" -> phaseSequenceError = true; + case "power_meter_failure" -> powerMeterFailure = true; + case "no_load" -> noLoadCondition = true; + } + } + } + + // Total Active Power + activePower = round(getAsFloat(response, "total_act_power")); + + // Extract phase data + activePowerL1 = round(getAsFloat(response, "a_act_power")); + voltageL1 = round(getAsFloat(response, "a_voltage") * 1000); + currentL1 = round(getAsFloat(response, "a_current") * 1000); + + activePowerL2 = round(getAsFloat(response, "b_act_power")); + voltageL2 = round(getAsFloat(response, "b_voltage") * 1000); + currentL2 = round(getAsFloat(response, "b_current") * 1000); + + activePowerL3 = round(getAsFloat(response, "c_act_power")); + voltageL3 = round(getAsFloat(response, "c_voltage") * 1000); + currentL3 = round(getAsFloat(response, "c_current") * 1000); + + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + this._setActivePower(activePower); + this.channel(IoShellyPro3Em.ChannelId.PHASE_SEQUENCE_ERROR).setNextValue(phaseSequenceError); + this.channel(IoShellyPro3Em.ChannelId.NO_LOAD).setNextValue(noLoadCondition); + this.channel(IoShellyPro3Em.ChannelId.POWER_METER_FAILURE).setNextValue(powerMeterFailure); + + this._setActivePowerL1(activePowerL1); + this._setVoltageL1(voltageL1); + this._setCurrentL1(currentL1); + + this._setActivePowerL2(activePowerL2); + this._setVoltageL2(voltageL2); + this._setCurrentL2(currentL2); + + this._setActivePowerL3(activePowerL3); + this._setVoltageL3(voltageL3); + this._setCurrentL3(currentL3); + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + // Calculate Energy + final var activePower = this.getActivePower().get(); + if (activePower == null) { + this.calculateProductionEnergy.update(null); + this.calculateConsumptionEnergy.update(null); + } else if (activePower >= 0) { + this.calculateProductionEnergy.update(activePower); + this.calculateConsumptionEnergy.update(0); + } else { + this.calculateProductionEnergy.update(0); + this.calculateConsumptionEnergy.update(-activePower); + } + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public MeterType getMeterType() { + return this.meterType; + } +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java new file mode 100644 index 00000000000..29b0136a7a6 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/IoShelly3EmImplTest.java @@ -0,0 +1,25 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.meter.api.MeterType; + +public class IoShelly3EmImplTest { + + private static final String COMPONENT_ID = "io0"; + + @Test + public void test() throws Exception { + new ComponentTest(new IoShellyPro3EmImpl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setType(MeterType.CONSUMPTION_METERED) // + .build()) // + ; + } + +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/MyConfig.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/MyConfig.java new file mode 100644 index 00000000000..68261ee3841 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3em/MyConfig.java @@ -0,0 +1,62 @@ +package io.openems.edge.io.shelly.shellypro3em; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.meter.api.MeterType; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private MeterType type; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public MeterType type() { + return this.builder.type; + } +} \ No newline at end of file From 514d5d4e21e492edc5f9b84a1804db637d0e2048 Mon Sep 17 00:00:00 2001 From: Hannes Date: Wed, 19 Jun 2024 11:22:48 +0200 Subject: [PATCH 14/37] Implement ShellyPlus1PM (#2571) --- io.openems.edge.io.shelly/readme.adoc | 3 +- .../edge/io/shelly/shellyplus1pm/Config.java | 33 +++ .../shelly/shellyplus1pm/IoShellyPlus1Pm.java | 144 +++++++++++ .../shellyplus1pm/IoShellyPlus1PmImpl.java | 241 ++++++++++++++++++ .../IoShellyPlus1PmImplTest.java | 159 ++++++++++++ .../io/shelly/shellyplus1pm/MyConfig.java | 74 ++++++ .../shellyplusplugs/IoShellyPlugImplTest.java | 2 +- 7 files changed, 654 insertions(+), 2 deletions(-) create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/Config.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1Pm.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImpl.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/MyConfig.java diff --git a/io.openems.edge.io.shelly/readme.adoc b/io.openems.edge.io.shelly/readme.adoc index 220c84fcbb4..423f94ec0c9 100644 --- a/io.openems.edge.io.shelly/readme.adoc +++ b/io.openems.edge.io.shelly/readme.adoc @@ -1,6 +1,6 @@ = Shelly WiFi Relay Switch -This bundle implements Shelly WiFi Relay Switches. +This bundle implements Shelly WiFi Relay Switches and Meters. Compatible with - https://www.shelly.com/de/products/shop/1xs25[Shelly 2.5] @@ -8,5 +8,6 @@ Compatible with - Shelly Plug S - https://www.shelly.com/de/products/shop/shelly-plus-plug-s-1[Shelly Plus Plug S] - https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1[Shelly Pro 3EM 3-Phase Meter] +- https://www.shelly.com/de/products/shop/shelly-plus-1-pm[Shelly Plus 1PM] https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.io.shelly[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/Config.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/Config.java new file mode 100644 index 00000000000..2de9b0a17f0 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/Config.java @@ -0,0 +1,33 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; + +@ObjectClassDefinition(// + name = "IO Shelly Plus 1PM", // + description = "Implements the Shelly 2ndGen / Plug WiFi Switch.") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "io0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Phase", description = "Which Phase is this Shelly Plug connected to?") + SinglePhase phase() default SinglePhase.L1; + + @AttributeDefinition(name = "IP-Address", description = "The IP address of the Shelly device.") + String ip(); + + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.CONSUMPTION_METERED; + + String webconsole_configurationFactory_nameHint() default "IO Shelly Plus 1PM [{id}]"; +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1Pm.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1Pm.java new file mode 100644 index 00000000000..3fe7bb35bfe --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1Pm.java @@ -0,0 +1,144 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import org.osgi.service.event.EventHandler; + +import io.openems.common.channel.AccessMode; +import io.openems.common.channel.Level; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.BooleanDoc; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.io.api.DigitalOutput; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.SinglePhaseMeter; + +public interface IoShellyPlus1Pm + extends DigitalOutput, SinglePhaseMeter, ElectricityMeter, OpenemsComponent, EventHandler { + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + /** + * Holds writes to Relay Output for debugging. + * + *
    + *
  • Interface: ShellyPlus1PM + *
  • Type: Boolean + *
  • Range: On/Off + *
+ */ + DEBUG_RELAY(Doc.of(OpenemsType.BOOLEAN)), // + /** + * Relay Output. + * + *
    + *
  • Interface: ShellyPlus1PM + *
  • Type: Boolean + *
  • Range: On/Off + *
+ */ + RELAY(new BooleanDoc() // + .accessMode(AccessMode.READ_WRITE) // + .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY)), + /** + * Indicates whether the Shelly needs a restart. + * + *
    + *
  • Interface: ShellyPlus1PM + *
  • Type: Boolean + *
  • Level: WARN + *
+ */ + NEEDS_RESTART(Doc.of(Level.INFO) // + .text("Shelly suggests a restart.")), + /** + * Slave Communication Failed Fault. + * + *
    + *
  • Interface: ShellyPlus1PM + *
  • Type: State + *
+ */ + SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT)); // + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#RELAY}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelayChannel() { + return this.channel(ChannelId.RELAY); + } + + /** + * Gets the Relay Output 1. See {@link ChannelId#RELAY}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay() { + return this.getRelayChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY} Channel. + * + * @param value the next value + */ + public default void _setRelay(Boolean value) { + this.getRelayChannel().setNextValue(value); + } + + /** + * Sets the Relay Output. See {@link ChannelId#RELAY}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay(boolean value) throws OpenemsNamedException { + this.getRelayChannel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImpl.java new file mode 100644 index 00000000000..16bd2cf3af0 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImpl.java @@ -0,0 +1,241 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import static io.openems.common.utils.JsonUtils.getAsBoolean; +import static io.openems.common.utils.JsonUtils.getAsFloat; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.edge.io.shelly.common.Utils.generateDebugLog; +import static java.lang.Math.round; + +import java.util.Objects; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.io.api.DigitalOutput; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; +import io.openems.edge.meter.api.SinglePhaseMeter; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "IO.Shelly.Plus1PM", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE// +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE, // + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // +}) +public class IoShellyPlus1PmImpl extends AbstractOpenemsComponent implements IoShellyPlus1Pm, DigitalOutput, + SinglePhaseMeter, ElectricityMeter, OpenemsComponent, TimedataProvider, EventHandler { + + private final CalculateEnergyFromPower calculateProductionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); + + private final Logger log = LoggerFactory.getLogger(IoShellyPlus1PmImpl.class); + private final BooleanWriteChannel[] digitalOutputChannels; + + private MeterType meterType = null; + private SinglePhase phase = null; + private String baseUrl; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata; + + @Reference(cardinality = ReferenceCardinality.MANDATORY) + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + public IoShellyPlus1PmImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + DigitalOutput.ChannelId.values(), // + IoShellyPlus1Pm.ChannelId.values() // + ); + this.digitalOutputChannels = new BooleanWriteChannel[] { // + this.channel(IoShellyPlus1Pm.ChannelId.RELAY) // + }; + + SinglePhaseMeter.calculateSinglePhaseFromActivePower(this); + SinglePhaseMeter.calculateSinglePhaseFromCurrent(this); + SinglePhaseMeter.calculateSinglePhaseFromVoltage(this); + } + + @Activate + protected void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.meterType = config.type(); + this.phase = config.phase(); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + + if (!this.isEnabled()) { + return; + } + + this.httpBridge.subscribeJsonEveryCycle(this.baseUrl + "/rpc/Shelly.GetStatus", this::processHttpResult); + } + + @Override + @Deactivate + protected void deactivate() { + if (this.httpBridge != null) { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + } + super.deactivate(); + } + + @Override + public BooleanWriteChannel[] digitalOutputChannels() { + return this.digitalOutputChannels; + } + + @Override + public String debugLog() { + return generateDebugLog(this.getRelayChannel(), this.getActivePowerChannel()); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + -> this.calculateEnergy(); + case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // + -> this.executeWrite(this.getRelayChannel(), 0); + } + } + + private void processHttpResult(HttpResponse result, Throwable error) { + this._setSlaveCommunicationFailed(result == null); + + Integer power = null; + Integer voltage = null; + Integer current = null; + Boolean relay0 = null; + boolean restartRequired = false; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var jsonResponse = getAsJsonObject(result.data()); + var switch0 = getAsJsonObject(jsonResponse, "switch:0"); + power = round(getAsFloat(switch0, "apower")); + voltage = round(getAsFloat(switch0, "voltage") * 1000); + current = round(getAsFloat(switch0, "current") * 1000); + relay0 = getAsBoolean(switch0, "output"); + + var sys = getAsJsonObject(jsonResponse, "sys"); + restartRequired = getAsBoolean(sys, "restart_required"); + + } catch (OpenemsNamedException e) { + this.logDebug(this.log, e.getMessage()); + } + } + + this._setRelay(relay0); + this._setActivePower(power); + this._setCurrent(current); + this._setVoltage(voltage); + this.channel(IoShellyPlus1Pm.ChannelId.NEEDS_RESTART).setNextValue(restartRequired); + } + + /** + * Execute on Cycle Event "Execute Write". + * + * @param channel write channel + * @param index index + */ + private void executeWrite(BooleanWriteChannel channel, int index) { + var readValue = channel.value().get(); + var writeValue = channel.getNextWriteValueAndReset(); + if (writeValue.isEmpty()) { + // no write value + return; + } + if (Objects.equals(readValue, writeValue.get())) { + // read value equals write value, so no need to write + return; + } + final String url = this.baseUrl + "/relay/" + index + "?turn=" + (writeValue.get() ? "on" : "off"); + this.httpBridge.get(url).whenComplete((response, error) -> { + if (error != null) { + this.logError(this.log, "HTTP request failed: " + error.getMessage()); + this._setSlaveCommunicationFailed(true); + } else { + // Optionally log success or handle response + this._setSlaveCommunicationFailed(false); + } + }); + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + // Calculate Energy + final var activePower = this.getActivePower().get(); + if (activePower == null) { + this.calculateProductionEnergy.update(null); + this.calculateConsumptionEnergy.update(null); + } else if (activePower >= 0) { + this.calculateProductionEnergy.update(activePower); + this.calculateConsumptionEnergy.update(0); + } else { + this.calculateProductionEnergy.update(0); + this.calculateConsumptionEnergy.update(-activePower); + } + } + + @Override + public MeterType getMeterType() { + return this.meterType; + } + + @Override + public SinglePhase getPhase() { + return this.phase; + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java new file mode 100644 index 00000000000..e3443f8d6b1 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/IoShellyPlus1PmImplTest.java @@ -0,0 +1,159 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import static io.openems.edge.meter.api.MeterType.CONSUMPTION_METERED; +import static io.openems.edge.meter.api.SinglePhase.L1; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import io.openems.common.types.ChannelAddress; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpBundle; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.timedata.test.DummyTimedata; + +public class IoShellyPlus1PmImplTest { + + private static final String COMPONENT_ID = "io0"; + + private static final ChannelAddress ACTIVE_POWER = new ChannelAddress(COMPONENT_ID, "ActivePower"); + private static final ChannelAddress ACTIVE_POWER_L1 = new ChannelAddress(COMPONENT_ID, "ActivePowerL1"); + private static final ChannelAddress ACTIVE_POWER_L2 = new ChannelAddress(COMPONENT_ID, "ActivePowerL2"); + private static final ChannelAddress CURRENT = new ChannelAddress(COMPONENT_ID, "Current"); + private static final ChannelAddress VOLTAGE = new ChannelAddress(COMPONENT_ID, "Voltage"); + private static final ChannelAddress PRODUCTION_ENERGY = new ChannelAddress(COMPONENT_ID, "ActiveProductionEnergy"); + private static final ChannelAddress CONSUMPTION_ENERGY = new ChannelAddress(COMPONENT_ID, + "ActiveConsumptionEnergy"); + + @Test + public void test() throws Exception { + final var httpTestBundle = new DummyBridgeHttpBundle(); + final var sut = new IoShellyPlus1PmImpl(); + + new ComponentTest(sut) // + .addReference("httpBridgeFactory", httpTestBundle.factory()) // + .addReference("timedata", new DummyTimedata("timedata0")) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .setType(CONSUMPTION_METERED) // + .setPhase(L1) // + .build()) // + + .next(new TestCase("Successful read response") // + .onBeforeControllersCallbacks(() -> { + httpTestBundle.forceNextSuccessfulResult(HttpResponse.ok(""" + { + "ble":{ + + }, + "cloud":{ + "connected":true + }, + "input:0":{ + "id":0, + "state":false + }, + "mqtt":{ + "connected":false + }, + "switch:0":{ + "id":0, + "source":"init", + "output":false, + "apower":123.0, + "voltage":231.3, + "current":0.500, + "aenergy":{ + "total":8629.000, + "by_minute":[ + 0.000, + 0.000, + 0.000 + ], + "minute_ts":1708858380 + }, + "temperature":{ + "tC":44.3, + "tF":111.7 + } + }, + "sys":{ + "mac":"80646FE34998", + "restart_required":false, + "time":"11:53", + "unixtime":1708858386, + "uptime":150390, + "ram_size":260364, + "ram_free":115308, + "fs_size":458752, + "fs_free":143360, + "cfg_rev":22, + "kvs_rev":2, + "schedule_rev":0, + "webhook_rev":0, + "available_updates":{ + + }, + "reset_reason":3 + }, + "wifi":{ + "sta_ip":"192.168.178.169", + "status":"got ip", + "ssid":"heizung", + "rssi":-48, + "ap_client_count":0 + }, + "ws":{ + "connected":false + } + } + """)); + httpTestBundle.triggerNextCycle(); + }) // + .output(ACTIVE_POWER, 123) // + .output(ACTIVE_POWER_L1, 123) // + .output(ACTIVE_POWER_L2, null) // + .output(CURRENT, 500) // + .output(VOLTAGE, 231300)) // + + .next(new TestCase("Invalid read response") // + .onBeforeControllersCallbacks(() -> assertEquals("Off|123 W", sut.debugLog())) + + .onBeforeControllersCallbacks(() -> { + httpTestBundle.forceNextFailedResult(HttpError.ResponseError.notFound()); + httpTestBundle.triggerNextCycle(); + }) // + .output(ACTIVE_POWER, null) // + .output(ACTIVE_POWER_L1, null) // + .output(ACTIVE_POWER_L2, null) // + .output(CURRENT, null) // + .output(VOLTAGE, null) // + + .output(PRODUCTION_ENERGY, 0L) // + .output(CONSUMPTION_ENERGY, 0L)) // + + .next(new TestCase("Write") // + .onBeforeControllersCallbacks(() -> assertEquals("Unknown|UNDEFINED", sut.debugLog())) + .onBeforeControllersCallbacks(() -> { + sut.setRelay(true); + }) // + .also(testCase -> { + final var relayTurnedOn = httpTestBundle.expect("http://127.0.0.1/relay/0?turn=on") + .toBeCalled(); + + testCase.onBeforeControllersCallbacks(() -> { + httpTestBundle.triggerNextCycle(); + }); + testCase.onAfterWriteCallbacks(() -> { + assertTrue("Failed to turn on relay", relayTurnedOn.get()); + }); + })) // + + .deactivate(); + } + +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/MyConfig.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/MyConfig.java new file mode 100644 index 00000000000..e653d439747 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplus1pm/MyConfig.java @@ -0,0 +1,74 @@ +package io.openems.edge.io.shelly.shellyplus1pm; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SinglePhase; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + private MeterType type; + private SinglePhase phase; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setPhase(SinglePhase phase) { + this.phase = phase; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public Builder setType(MeterType type) { + this.type = type; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } + + @Override + public MeterType type() { + return this.builder.type; + } + + @Override + public SinglePhase phase() { + return this.builder.phase; + } +} diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java index 9b1a1d50795..c91c4c52720 100644 --- a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellyplusplugs/IoShellyPlugImplTest.java @@ -43,7 +43,7 @@ public void test() throws Exception { .setType(MeterType.PRODUCTION) // .build()) // - .next(new TestCase("Successfull read response") // + .next(new TestCase("Successful read response") // .onBeforeControllersCallbacks(() -> { httpTestBundle.forceNextSuccessfulResult(HttpResponse.ok(""" { From 4cdae0c315e7ba05c6611ba1e13057d3b7a5b634 Mon Sep 17 00:00:00 2001 From: Hannes Date: Wed, 19 Jun 2024 12:03:29 +0200 Subject: [PATCH 15/37] Implement Shelly Pro 3 (#2572) --- io.openems.edge.io.shelly/readme.adoc | 1 + .../openems/edge/io/shelly/common/Utils.java | 26 ++ .../io/shelly/shelly25/IoShelly25Impl.java | 20 +- .../edge/io/shelly/shellypro3/Config.java | 24 ++ .../io/shelly/shellypro3/IoShellyPro3.java | 247 ++++++++++++++++++ .../shelly/shellypro3/IoShellyPro3Impl.java | 167 ++++++++++++ .../shellypro3em/IoShellyPro3EmImpl.java | 2 +- .../shellypro3/IoShellyPro3ImplTest.java | 23 ++ .../edge/io/shelly/shellypro3/MyConfig.java | 50 ++++ 9 files changed, 541 insertions(+), 19 deletions(-) create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/Config.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3.java create mode 100644 io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3Impl.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java create mode 100644 io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/MyConfig.java diff --git a/io.openems.edge.io.shelly/readme.adoc b/io.openems.edge.io.shelly/readme.adoc index 423f94ec0c9..c4a28621bff 100644 --- a/io.openems.edge.io.shelly/readme.adoc +++ b/io.openems.edge.io.shelly/readme.adoc @@ -9,5 +9,6 @@ Compatible with - https://www.shelly.com/de/products/shop/shelly-plus-plug-s-1[Shelly Plus Plug S] - https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1[Shelly Pro 3EM 3-Phase Meter] - https://www.shelly.com/de/products/shop/shelly-plus-1-pm[Shelly Plus 1PM] +- https://www.shelly.com/de/products/shop/shelly-pro-3-1[Shelly Pro 3] https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.io.shelly[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java index 14595f04ea6..ca4ac6ff5b4 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/common/Utils.java @@ -1,5 +1,6 @@ package io.openems.edge.io.shelly.common; +import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.component.OpenemsComponent; @@ -26,4 +27,29 @@ public static String generateDebugLog(Channel relayChannel, Channel + *
  • Interface: Shelly3Pro + *
  • Type: Boolean + *
  • Range: On/Off + * + */ + DEBUG_RELAY_1(Doc.of(OpenemsType.BOOLEAN)), // + /** + * Relay Output 1. + * + *
      + *
    • Interface: Shelly3Pro + *
    • Type: Boolean + *
    • Range: On/Off + *
    + */ + RELAY_1(new BooleanDoc() // + .accessMode(AccessMode.READ_WRITE) // + .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_1)), + /** + * Holds writes to Relay Output 2 for debugging. + * + *
      + *
    • Interface: Shelly3Pro + *
    • Type: Boolean + *
    • Range: On/Off + *
    + */ + DEBUG_RELAY_2(Doc.of(OpenemsType.BOOLEAN)), // + /** + * Relay Output 2. + * + *
      + *
    • Interface: Shelly3Pro + *
    • Type: Boolean + *
    • Range: On/Off + *
    + */ + RELAY_2(new BooleanDoc() // + .accessMode(AccessMode.READ_WRITE) // + .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_2)), + /** + * Holds writes to Relay Output 3 for debugging. + * + *
      + *
    • Interface: Shelly3Pro + *
    • Type: Boolean + *
    • Range: On/Off + *
    + */ + DEBUG_RELAY_3(Doc.of(OpenemsType.BOOLEAN)), // + /** + * Relay Output 3. + * + *
      + *
    • Interface: Shelly3Pro + *
    • Type: Boolean + *
    • Range: On/Off + *
    + */ + RELAY_3(new BooleanDoc() // + .accessMode(AccessMode.READ_WRITE) // + .onChannelSetNextWriteMirrorToDebugChannel(ChannelId.DEBUG_RELAY_3)), + /** + * Slave Communication Failed Fault. + * + *
      + *
    • Interface: Shelly3Pro + *
    • Type: State + *
    + */ + SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT)); // + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#RELAY_1}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay1Channel() { + return this.channel(ChannelId.RELAY_1); + } + + /** + * Gets the Relay Output 1. See {@link ChannelId#RELAY_1}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay1() { + return this.getRelay1Channel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_1} Channel. + * + * @param value the next value + */ + public default void _setRelay1(Boolean value) { + this.getRelay1Channel().setNextValue(value); + } + + /** + * Sets the Relay Output 1. See {@link ChannelId#RELAY_1}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay1(boolean value) throws OpenemsNamedException { + this.getRelay1Channel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#RELAY_2}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay2Channel() { + return this.channel(ChannelId.RELAY_2); + } + + /** + * Gets the Relay Output 2. See {@link ChannelId#RELAY_2}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay2() { + return this.getRelay2Channel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_2} Channel. + * + * @param value the next value + */ + public default void _setRelay2(Boolean value) { + this.getRelay2Channel().setNextValue(value); + } + + /** + * Sets the Relay Output 2. See {@link ChannelId#RELAY_2}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay2(boolean value) throws OpenemsNamedException { + this.getRelay2Channel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#RELAY_3}. + * + * @return the Channel + */ + public default BooleanWriteChannel getRelay3Channel() { + return this.channel(ChannelId.RELAY_3); + } + + /** + * Gets the Relay Output 3. See {@link ChannelId#RELAY_3}. + * + * @return the Channel {@link Value} + */ + public default Value getRelay3() { + return this.getRelay3Channel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#RELAY_3} Channel. + * + * @param value the next value + */ + public default void _setRelay3(Boolean value) { + this.getRelay3Channel().setNextValue(value); + } + + /** + * Sets the Relay Output 3. See {@link ChannelId#RELAY_3}. + * + * @param value the next write value + * @throws OpenemsNamedException on error + */ + public default void setRelay3(boolean value) throws OpenemsNamedException { + this.getRelay3Channel().setNextWriteValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel + */ + public default StateChannel getSlaveCommunicationFailedChannel() { + return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED); + } + + /** + * Gets the Slave Communication Failed State. See + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED}. + * + * @return the Channel {@link Value} + */ + public default Value getSlaveCommunicationFailed() { + return this.getSlaveCommunicationFailedChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel. + * + * @param value the next value + */ + public default void _setSlaveCommunicationFailed(boolean value) { + this.getSlaveCommunicationFailedChannel().setNextValue(value); + } +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3Impl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3Impl.java new file mode 100644 index 00000000000..888ceb58da3 --- /dev/null +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3/IoShellyPro3Impl.java @@ -0,0 +1,167 @@ +package io.openems.edge.io.shelly.shellypro3; + +import static io.openems.common.utils.JsonUtils.getAsBoolean; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.edge.io.shelly.common.Utils.generateDebugLog; + +import java.util.Objects; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; + +import io.openems.edge.bridge.http.api.BridgeHttp; +import io.openems.edge.bridge.http.api.BridgeHttpFactory; +import io.openems.edge.bridge.http.api.HttpError; +import io.openems.edge.bridge.http.api.HttpResponse; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.io.api.DigitalOutput; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "IO.Shelly.Pro3", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // +}) + +public class IoShellyPro3Impl extends AbstractOpenemsComponent + implements IoShellyPro3, DigitalOutput, OpenemsComponent, EventHandler { + + private final Logger log = LoggerFactory.getLogger(IoShellyPro3Impl.class); + private final BooleanWriteChannel[] digitalOutputChannels; + + private String baseUrl; + + @Reference + private BridgeHttpFactory httpBridgeFactory; + private BridgeHttp httpBridge; + + public IoShellyPro3Impl() { + super(// + OpenemsComponent.ChannelId.values(), // + DigitalOutput.ChannelId.values(), // + IoShellyPro3.ChannelId.values() // + ); + this.digitalOutputChannels = new BooleanWriteChannel[] { // + this.channel(IoShellyPro3.ChannelId.RELAY_1), // + this.channel(IoShellyPro3.ChannelId.RELAY_2), // + this.channel(IoShellyPro3.ChannelId.RELAY_3), // + }; + } + + @Activate + protected void activate(ComponentContext context, Config config) { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.baseUrl = "http://" + config.ip(); + this.httpBridge = this.httpBridgeFactory.get(); + + for (int i = 0; i < 3; i++) { + final int relayIndex = i; + String url = this.baseUrl + "/rpc/Switch.GetStatus?id=" + relayIndex; + this.httpBridge.subscribeJsonEveryCycle(url, (result, error) -> { + this.processHttpResult(result, error, relayIndex); + }); + } + } + + @Deactivate + protected void deactivate() { + this.httpBridgeFactory.unget(this.httpBridge); + this.httpBridge = null; + super.deactivate(); + } + + @Override + public BooleanWriteChannel[] digitalOutputChannels() { + return this.digitalOutputChannels; + } + + @Override + public String debugLog() { + return generateDebugLog(this.digitalOutputChannels); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // + -> this.eventExecuteWrite(); + } + } + + // NOTE: this method is called once per each relay + private void processHttpResult(HttpResponse result, HttpError error, int relayIndex) { + this._setSlaveCommunicationFailed(result == null); + + Boolean isOn = null; + + if (error != null) { + this.logDebug(this.log, error.getMessage()); + + } else { + try { + var switchStatus = getAsJsonObject(result.data()); + isOn = getAsBoolean(switchStatus, "output"); + + } catch (Exception e) { + this.logError(this.log, "Error processing HTTP response: " + e.getMessage()); + return; + } + } + + switch (relayIndex) { + case 0 -> this._setRelay1(isOn); + case 1 -> this._setRelay2(isOn); + case 2 -> this._setRelay3(isOn); + } + } + + /** + * Execute on Cycle Event "Execute Write". + */ + private void eventExecuteWrite() { + for (int i = 0; i < this.digitalOutputChannels.length; i++) { + this.executeWrite(this.digitalOutputChannels[i], i); + } + } + + private void executeWrite(BooleanWriteChannel channel, int index) { + var readValue = channel.value().get(); + var writeValue = channel.getNextWriteValueAndReset(); + if (writeValue.isEmpty()) { + return; + } + if (Objects.equals(readValue, writeValue.get())) { + return; + } + final String url = this.baseUrl + "/relay/" + index + "?turn=" + (writeValue.get() ? "on" : "off"); + this.httpBridge.get(url).whenComplete((t, e) -> { + if (e != null) { + this.logError(this.log, "HTTP request failed: " + e.getMessage()); + this._setSlaveCommunicationFailed(true); + } + }); + } + +} diff --git a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java index dfa0c2085b4..15db1dac66f 100644 --- a/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java +++ b/io.openems.edge.io.shelly/src/io/openems/edge/io/shelly/shellypro3em/IoShellyPro3EmImpl.java @@ -40,7 +40,7 @@ @Designate(ocd = Config.class, factory = true) @Component(// - name = "IO.Shelly.Pro.3EM", // + name = "IO.Shelly.Pro3EM", // immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE // ) diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java new file mode 100644 index 00000000000..ed4f8d960b6 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/IoShellyPro3ImplTest.java @@ -0,0 +1,23 @@ +package io.openems.edge.io.shelly.shellypro3; + +import org.junit.Test; + +import io.openems.edge.bridge.http.dummy.DummyBridgeHttpFactory; +import io.openems.edge.common.test.ComponentTest; + +public class IoShellyPro3ImplTest { + + private static final String COMPONENT_ID = "io0"; + + @Test + public void test() throws Exception { + new ComponentTest(new IoShellyPro3Impl()) // + .addReference("httpBridgeFactory", DummyBridgeHttpFactory.ofDummyBridge()) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setIp("127.0.0.1") // + .build()) // + ; + } + +} \ No newline at end of file diff --git a/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/MyConfig.java b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/MyConfig.java new file mode 100644 index 00000000000..3d58882f769 --- /dev/null +++ b/io.openems.edge.io.shelly/test/io/openems/edge/io/shelly/shellypro3/MyConfig.java @@ -0,0 +1,50 @@ +package io.openems.edge.io.shelly.shellypro3; + +import io.openems.common.test.AbstractComponentConfig; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String ip; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setIp(String ip) { + this.ip = ip; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String ip() { + return this.builder.ip; + } +} \ No newline at end of file From 2d8c2a9033a0b745659aaff78ab9597a3594b230 Mon Sep 17 00:00:00 2001 From: Hannes Date: Mon, 24 Jun 2024 10:50:33 +0200 Subject: [PATCH 16/37] UI: improve select channels view (#2599) If no component was selected, it used to be possible to select a channel. This is fixed now. --- ui/src/app/edge/settings/channels/channels.component.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/src/app/edge/settings/channels/channels.component.html b/ui/src/app/edge/settings/channels/channels.component.html index 9640d5ecdb8..8c192b88627 100644 --- a/ui/src/app/edge/settings/channels/channels.component.html +++ b/ui/src/app/edge/settings/channels/channels.component.html @@ -24,8 +24,9 @@ - + From 941bc101044caede0cd0af6e4632894fa16a9f62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:33:50 +0200 Subject: [PATCH 17/37] Bump @types/uuid from 9.0.8 to 10.0.0 in /ui (#2682) Bumps [@types/uuid](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/uuid) from 9.0.8 to 10.0.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/uuid) --- updated-dependencies: - dependency-name: "@types/uuid" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ui/package-lock.json | 9 +++++---- ui/package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index b6b69c0cf64..f39f06c978a 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -56,7 +56,7 @@ "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", - "@types/uuid": "^9.0.8", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "eslint": "^8.57.0", @@ -4696,9 +4696,10 @@ } }, "node_modules/@types/uuid": { - "version": "9.0.8", - "dev": true, - "license": "MIT" + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true }, "node_modules/@types/ws": { "version": "8.5.10", diff --git a/ui/package.json b/ui/package.json index 0d3a435f1cc..2729650ac7d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -51,7 +51,7 @@ "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", - "@types/uuid": "^9.0.8", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "eslint": "^8.57.0", From 66219b4574097cee59999787841bc37c7cd2165f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:40:02 +0200 Subject: [PATCH 18/37] Bump @stylistic/eslint-plugin from 2.2.1 to 2.2.2 in /ui (#2681) Bumps [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin) from 2.2.1 to 2.2.2. - [Release notes](https://github.com/eslint-stylistic/eslint-stylistic/releases) - [Changelog](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint-stylistic/eslint-stylistic/commits/v2.2.2/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@stylistic/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 136 +++++++++++++++++++++---------------------- ui/package.json | 2 +- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index f39f06c978a..77326d2363d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -52,7 +52,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.2.1", + "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", @@ -3959,15 +3959,15 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.2.1.tgz", - "integrity": "sha512-YErqfwWFbRCpkyPtrcVYaJhvEn9aXE4WzxxkZ7Q3OKS4QD9CE6qZjzEw5DhcA2wL3Jo6JbzSB3/stJMNocGMgQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.2.2.tgz", + "integrity": "sha512-GNRtyhhPsc9I9FNTaU2L0V/4LdSPAciQNEdYo6NBRdAz7sdiaxgEJKLNSXeXSQAuO9JBWWjZBs/57+WvrU0Iug==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "2.2.1", - "@stylistic/eslint-plugin-jsx": "2.2.1", - "@stylistic/eslint-plugin-plus": "2.2.1", - "@stylistic/eslint-plugin-ts": "2.2.1", + "@stylistic/eslint-plugin-js": "2.2.2", + "@stylistic/eslint-plugin-jsx": "2.2.2", + "@stylistic/eslint-plugin-plus": "2.2.2", + "@stylistic/eslint-plugin-ts": "2.2.2", "@types/eslint": "^8.56.10" }, "engines": { @@ -3978,9 +3978,9 @@ } }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.2.1.tgz", - "integrity": "sha512-M2dQkKw2R4R+b1SJ/xElJ9bDVq/vCI31VpIIxkZD9KXCqbUHvtsGpZH3eO6MzmFWOZj4PfNdEQdP332MtqjCPg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.2.2.tgz", + "integrity": "sha512-Vj2Q1YHVvJw+ThtOvmk5Yx7wZanVrIBRUTT89horLDb4xdP9GA1um9XOYQC6j67VeUC2gjZQnz5/RVJMzaOhtw==", "dev": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -4025,12 +4025,12 @@ } }, "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.2.1.tgz", - "integrity": "sha512-J/R4tU38v8gVqKPy6Mh22dq8btLSPWK06SuRc/ryOxT8LpW2ZdcSDP4HNvQiOte0Wy9xzgKJHP4JlYauDZ/oVw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.2.2.tgz", + "integrity": "sha512-xfIMdLivoMV1wV+5Tl0PtkLN/oUwjIt7LuIu48vhrZfJ2jCXwjlTGPGSoM7dnLZYD65XjtrHHIFAvPuvvvjlaw==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "^2.2.1", + "@stylistic/eslint-plugin-js": "^2.2.2", "@types/eslint": "^8.56.10", "estraverse": "^5.3.0", "picomatch": "^4.0.2" @@ -4064,9 +4064,9 @@ } }, "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.2.1.tgz", - "integrity": "sha512-VGdTcQzZ/cZNcJnvjDos1VLzUerPapvYCVSCQZEhupMtmxt+mbITiJWzLLHYNfqGBnW7ABqViLfob+s3Q2GcKw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.2.2.tgz", + "integrity": "sha512-oeqPs01yAH4ad4bSchGtx8Jf5XTbxRx++A0joNYiOoq3EBTAUHE/ZB7dVv3BhNuCKiwojOQduLkUCXI5UMHoSw==", "dev": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -4077,13 +4077,13 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", - "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1" + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4094,9 +4094,9 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", - "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4107,13 +4107,13 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", - "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4135,15 +4135,15 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", - "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1" + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4157,12 +4157,12 @@ } }, "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", - "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/types": "7.14.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -4227,12 +4227,12 @@ } }, "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.2.1.tgz", - "integrity": "sha512-2AbpXGGorCEzDryth7RhOMJWlko+sxSs1lxL2tSXB5H/EffmXgLn1tMoMKgwYJW3s6v0BxJRr5BWj9B9JaZTUQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.2.2.tgz", + "integrity": "sha512-n6cYMSWTDDcrQLLxEKIrL/ihQ1lyyq6+gGp0g5VdstBElmImSRsQkCq+g3jRoDJIUo7tGO9lwQtGnuJ7oGB4kg==", "dev": true, "dependencies": { - "@stylistic/eslint-plugin-js": "2.2.1", + "@stylistic/eslint-plugin-js": "2.2.2", "@types/eslint": "^8.56.10", "@typescript-eslint/utils": "^7.12.0" }, @@ -4244,13 +4244,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", - "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1" + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4261,9 +4261,9 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", - "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4274,13 +4274,13 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", - "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4302,15 +4302,15 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", - "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1" + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4324,12 +4324,12 @@ } }, "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", - "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/types": "7.14.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { diff --git a/ui/package.json b/ui/package.json index 2729650ac7d..284fe8a119d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -47,7 +47,7 @@ "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", "@ionic/angular-toolkit": "^11.0.1", - "@stylistic/eslint-plugin": "^2.2.1", + "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/node": "^20.12.6", From f53933045d65bbff74c23899000dfbf567b3e9a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:43:24 +0200 Subject: [PATCH 19/37] Bump @ngx-formly/ionic from 6.3.4 to 6.3.5 in /ui (#2680) Bumps [@ngx-formly/ionic](https://github.com/ngx-formly/ngx-formly) from 6.3.4 to 6.3.5. - [Release notes](https://github.com/ngx-formly/ngx-formly/releases) - [Changelog](https://github.com/ngx-formly/ngx-formly/blob/main/CHANGELOG.md) - [Commits](https://github.com/ngx-formly/ngx-formly/compare/v6.3.4...v6.3.5) --- updated-dependencies: - dependency-name: "@ngx-formly/ionic" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 16 ++++++++-------- ui/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 77326d2363d..68e4c750c74 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -19,7 +19,7 @@ "@angular/service-worker": "~16.2.12", "@ionic/angular": "^6.7.5", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.4", + "@ngx-formly/ionic": "^6.3.5", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", @@ -3360,9 +3360,9 @@ } }, "node_modules/@ngx-formly/core": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.4.tgz", - "integrity": "sha512-xpO0FB50gpQI4uDrz6nYNolMvMIOdgP19diflcvAAtDy15I4BS+tzLKOCkM9HmAwmKQ59z3FUyzaODFEu+cuEg==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.5.tgz", + "integrity": "sha512-9p4yl7fr2Ojmm/uN7/nM1hYezheUxecEC0WZ0YI6jeSoEJR8NYTglVxTmHrpW5had2oolHeO39sAo9ttJNifSA==", "dependencies": { "tslib": "^2.0.0" }, @@ -3372,15 +3372,15 @@ } }, "node_modules/@ngx-formly/ionic": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.4.tgz", - "integrity": "sha512-OHFZHe0E2sQoXEfYAzXMtvxt11mED2KZDjIAy0V35HGN0cC03GW1sToyTB2kmzLAyrH/HkhC3V7TurnrMbDSeQ==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.5.tgz", + "integrity": "sha512-WqcsG9YXr9PZdWOV+DVT++2cHrndMabRNlOOHx+VIf8QXQc1cyxq9UWW3CmBKw5lT1P2cy4cxxuKMk4EzNJV+Q==", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@ionic/angular": "^6.0.0 || ^7.0.0", - "@ngx-formly/core": "6.3.4" + "@ngx-formly/core": "6.3.5" } }, "node_modules/@ngx-formly/schematics": { diff --git a/ui/package.json b/ui/package.json index 284fe8a119d..9790d1c8f7e 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,7 +14,7 @@ "@angular/service-worker": "~16.2.12", "@ionic/angular": "^6.7.5", "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.4", + "@ngx-formly/ionic": "^6.3.5", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", From de0f1c27ec16b313d5e4fd46f6e1df0a01a63755 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:47:28 +0200 Subject: [PATCH 20/37] Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.20 to 5.1.22 in /cnf (#2679) * Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.20 to 5.1.22. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 2231de4e1b2..885dc5f1629 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.20 + 5.1.22 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 03d14f79f83..ce9f9ce5f85 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -104,7 +104,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.20,5.1.21)',\ + org.apache.felix.http.jetty;version='[5.1.22,5.1.23)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 6e383385d34..372ce3104b4 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -400,7 +400,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.20,5.1.21)',\ + org.apache.felix.http.jetty;version='[5.1.22,5.1.23)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From e0bbfcd43c51bf0815f8d5e8c1278ba4a840e836 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:51:55 +0200 Subject: [PATCH 21/37] Bump org.apache.felix:org.apache.felix.webconsole from 5.0.2 to 5.0.4 in /cnf (#2678) * Bump org.apache.felix:org.apache.felix.webconsole in /cnf Bumps org.apache.felix:org.apache.felix.webconsole from 5.0.2 to 5.0.4. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.webconsole dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 885dc5f1629..271f2e7233a 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -237,7 +237,7 @@ org.apache.felix org.apache.felix.webconsole - 5.0.2 + 5.0.4 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index ce9f9ce5f85..3187a198622 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -109,7 +109,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ + org.apache.felix.webconsole;version='[5.0.4,5.0.5)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.jetbrains.kotlin.osgi-bundle;version='[2.0.0,2.0.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 372ce3104b4..f158c0a74bd 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -405,7 +405,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.2,5.0.3)',\ + org.apache.felix.webconsole;version='[5.0.4,5.0.5)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.eclipse.jetty.client;version='[9.4.28,9.4.29)',\ org.eclipse.jetty.http;version='[9.4.28,9.4.29)',\ From 679fe0f3f00e6855566e85cf5f23ea8b14b68c4b Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Wed, 26 Jun 2024 12:52:53 +0200 Subject: [PATCH 22/37] CI: implement codecov (#2685) --- .github/workflows/build.yml | 34 +++--------------------- .github/workflows/comment.yml | 50 ----------------------------------- README.md | 1 + build.gradle | 2 +- codecov.yml | 15 +++++++++++ 5 files changed, 20 insertions(+), 82 deletions(-) delete mode 100644 .github/workflows/comment.yml create mode 100644 codecov.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74fa7fb6190..8211dc2cec2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,41 +34,13 @@ jobs: - name: Validate EdgeApp.bndrun run: git diff --exit-code io.openems.edge.application/EdgeApp.bndrun - # - # Generate Code-coverage-report - # - name: Generate JaCoCo Code-coverage-report run: ./gradlew jacocoTestReport - - - name: Summarize JaCoCo Report - id: jacoco - uses: cicirello/jacoco-badge-generator@v2 - with: - jacoco-csv-file: 'io.openems.*/generated/reports/jacoco/**/*.csv' - generate-coverage-badge: false - - - name: Create JaCoCo Badge - env: - PR_NUMBER: ${{ github.event.number }} - run: | - coverage=$(echo "scale=2; ${{ steps.jacoco.outputs.coverage }} * 100" | bc | cut -c1-4); - - color=red; - if (( $(echo "$coverage > 90" | bc -l) )); then - color=success; - elif (( $(echo "$coverage > 80" | bc -l) )); then - color=green; - elif (( $(echo "$coverage > 60" | bc -l) )); then - color=yellow; - fi; - mkdir -p ./jacoco - echo $PR_NUMBER > ./jacoco/jacoco_report_number - echo '![Code Coverage]'"(https://img.shields.io/badge/Code%20Coverage-${coverage}%25-${color}?style=flat)" > ./jacoco/jacoco_report_badge - - uses: actions/upload-artifact@v4 + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4 with: - name: jacoco_report - path: jacoco/ + token: ${{ secrets.CODECOV_TOKEN }} build-ui: runs-on: ubuntu-latest diff --git a/.github/workflows/comment.yml b/.github/workflows/comment.yml deleted file mode 100644 index f8ce4e26a0f..00000000000 --- a/.github/workflows/comment.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Comment Pull_Request -on: - workflow_run: - workflows: [Build OpenEMS] - types: - - completed - -jobs: - comment_jacoco: - runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} - steps: - - name: 'Download artifact' - uses: actions/github-script@v6 - with: - script: | - let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.payload.workflow_run.id, - }); - let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { - return artifact.name == 'jacoco_report' - })[0]; - let download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: 'zip', - }); - let fs = require('fs'); - fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/jacoco_report.zip`, Buffer.from(download.data)); - - - name: 'Unzip artifact' - run: unzip jacoco_report.zip - - - name: 'Comment on PR' - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - let fs = require('fs'); - let comment = fs.readFileSync('./jacoco_report_badge', { encoding: 'utf8', flag: 'r' }); - let issue_number = Number(fs.readFileSync('./jacoco_report_number')); - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue_number, - body: comment - }); \ No newline at end of file diff --git a/README.md b/README.md index 19a294a511f..09bf75eeaac 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [![Build Status](https://github.com/OpenEMS/openems/actions/workflows/build.yml/badge.svg)](https://github.com/OpenEMS/openems/actions/workflows/build.yml) [![Gitpod live-demo](https://img.shields.io/badge/Gitpod-live--demo-blue?logo=gitpod)](https://gitpod.io/#https://github.com/OpenEMS/openems/tree/main) [![Cite via Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.4440884.svg)](https://doi.org/10.5281/zenodo.4440883) +[![codecov](https://codecov.io/gh/openems/openems/graph/badge.svg?token=xliIughqt1)](https://codecov.io/gh/openems/openems)

    the Feneco - OpenEMS Logo diff --git a/build.gradle b/build.gradle index f616cf7b1e8..a432a1fa395 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ subprojects { jacocoTestReport { reports { xml.required = true - csv.required = true + csv.required = false html.required = false } // Exclude com.dalsemi.onewire diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000000..3ee859df746 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,15 @@ +coverage: + round: up + precision: 2 + status: + project: + default: + target: '60%' + +comment: + layout: "condensed_header, diff" + behavior: default + require_changes: false + require_base: false + require_head: true + hide_project_coverage: true \ No newline at end of file From d54ba1b926c26871da3161c8a385958509aa8e87 Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Wed, 26 Jun 2024 21:39:15 +0200 Subject: [PATCH 23/37] CI: update docs build (#2686) --- doc/build.gradle | 2 +- doc/build/.gitignore | 2 +- doc/build/package.json | 4 ++-- doc/build/uibundle_openems.zip | Bin 280789 -> 580960 bytes settings.gradle | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/build.gradle b/doc/build.gradle index 95939554fd6..4aaf5ee6b5a 100644 --- a/doc/build.gradle +++ b/doc/build.gradle @@ -3,7 +3,7 @@ plugins { } node { - nodeModulesDir = file("${projectDir}/build") + nodeProjectDir = file("${projectDir}/build") } /* diff --git a/doc/build/.gitignore b/doc/build/.gitignore index c712b273a34..45220110096 100644 --- a/doc/build/.gitignore +++ b/doc/build/.gitignore @@ -1,2 +1,2 @@ -/mode_modules/ +/node_modules/ /www/ \ No newline at end of file diff --git a/doc/build/package.json b/doc/build/package.json index b83512c5802..fbf607bbcb4 100644 --- a/doc/build/package.json +++ b/doc/build/package.json @@ -1,7 +1,7 @@ { "name": "openems-doc", "version": "1.0.0", - "dependencies": { - "antora": "^3.1.6" + "devDependencies": { + "antora": "^3.1.8" } } diff --git a/doc/build/uibundle_openems.zip b/doc/build/uibundle_openems.zip index e984c39af21352fee7236c36e1f68bde63266396..2ed7adc83ec03e5b88208014814702f6b9060e07 100644 GIT binary patch delta 375762 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�eQyhyI>(m-?aqLuia87OK? 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 z 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Μ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

    c6BiduX-xXulDvN~O8mlUC*F+9)Rv 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 diff --git a/settings.gradle b/settings.gradle index aa1e1f279aa..8d98e1d0be0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,7 @@ pluginManagement { plugins { id 'biz.aQute.bnd.workspace' version "${bnd_version}" id 'biz.aQute.bnd' version "${bnd_version}" - id 'com.github.node-gradle.node' version "5.0.0" + id 'com.github.node-gradle.node' version "7.0.2" } repositories { maven { From 89db02871164617043a9954908e5038676e76212 Mon Sep 17 00:00:00 2001 From: Hiromasa Ihara Date: Thu, 27 Jun 2024 04:40:35 +0900 Subject: [PATCH 24/37] UI: remove ts-strict-ignore for env files and add typing (#2683) --- ui/src/environments/index.ts | 9 +++++---- ui/src/themes/openems/environments/backend-dev.ts | 1 - ui/src/themes/openems/environments/backend-docker.ts | 9 +++++++-- ui/src/themes/openems/environments/backend-prod.ts | 1 - ui/src/themes/openems/environments/edge-dev.ts | 1 - ui/src/themes/openems/environments/edge-docker.ts | 9 +++++++-- ui/src/themes/openems/environments/edge-prod.ts | 1 - ui/src/themes/openems/environments/gitpod.ts | 1 - 8 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ui/src/environments/index.ts b/ui/src/environments/index.ts index d0180b57ae8..8134ed5feee 100644 --- a/ui/src/environments/index.ts +++ b/ui/src/environments/index.ts @@ -21,7 +21,7 @@ export interface Environment { readonly docsUrlPrefix: string; readonly links: { - readonly COMMON_STORAGE: string, + readonly COMMON_STORAGE: string | null, readonly FORGET_PASSWORD: string, readonly EVCS_KEBA_KECONTACT: string, readonly EVCS_HARDY_BARTH: string, @@ -41,8 +41,9 @@ export interface Environment { readonly CONTROLLER_API_REST_READ: string, readonly CONTROLLER_API_REST_READWRITE: string, - readonly SETTINGS_ALERTING: string, - readonly SETTINGS_NETWORK_CONFIGURATION: string, + readonly SETTINGS_ALERTING: string | null, + readonly SETTINGS_NETWORK_CONFIGURATION: string | null, + readonly EVCS_CLUSTER: string, readonly WARRANTY: { readonly HOME: { @@ -89,5 +90,5 @@ export interface Environment { APP_IMAGE: (language: string, appId: string) => string | null; }, }, - readonly PRODUCT_TYPES: (translate: TranslateService) => Filter + readonly PRODUCT_TYPES: (translate: TranslateService) => Filter | null } diff --git a/ui/src/themes/openems/environments/backend-dev.ts b/ui/src/themes/openems/environments/backend-dev.ts index 0f93f985f5d..f48b00c5e42 100644 --- a/ui/src/themes/openems/environments/backend-dev.ts +++ b/ui/src/themes/openems/environments/backend-dev.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/backend-docker.ts b/ui/src/themes/openems/environments/backend-docker.ts index 5ca08fb74f8..28c03b27713 100644 --- a/ui/src/themes/openems/environments/backend-docker.ts +++ b/ui/src/themes/openems/environments/backend-docker.ts @@ -1,12 +1,17 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; +// In docker test environment variable window.env is injected. +// cf. +// - tools/docker/ui/root/etc/s6-overlay/s6-rc.d/init-nginx/run +// - tools/docker/ui/assets/env.template.js +const window_env = (window as any).env as { [key: string]: string}; + export const environment: Environment = { ...theme, ...{ backend: 'OpenEMS Backend', - url: window["env"]["websocket"], + url: window_env.websocket, production: true, debugMode: false, diff --git a/ui/src/themes/openems/environments/backend-prod.ts b/ui/src/themes/openems/environments/backend-prod.ts index 114c43274f1..ae5bb5eb32f 100644 --- a/ui/src/themes/openems/environments/backend-prod.ts +++ b/ui/src/themes/openems/environments/backend-prod.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/edge-dev.ts b/ui/src/themes/openems/environments/edge-dev.ts index a6fd796b39e..164dd04f34e 100644 --- a/ui/src/themes/openems/environments/edge-dev.ts +++ b/ui/src/themes/openems/environments/edge-dev.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/edge-docker.ts b/ui/src/themes/openems/environments/edge-docker.ts index 80ed1d80a99..479b15e852b 100644 --- a/ui/src/themes/openems/environments/edge-docker.ts +++ b/ui/src/themes/openems/environments/edge-docker.ts @@ -1,12 +1,17 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; +// In docker test environment, variable window.env is injected. +// cf. +// - tools/docker/ui/root/etc/s6-overlay/s6-rc.d/init-nginx/run +// - tools/docker/ui/assets/env.template.js +const window_env = (window as any).env as { [key: string]: string}; + export const environment: Environment = { ...theme, ...{ backend: 'OpenEMS Edge', - url: window["env"]["websocket"], + url: window_env.websocket, production: true, debugMode: false, diff --git a/ui/src/themes/openems/environments/edge-prod.ts b/ui/src/themes/openems/environments/edge-prod.ts index 4f023294025..bcaf40f6901 100644 --- a/ui/src/themes/openems/environments/edge-prod.ts +++ b/ui/src/themes/openems/environments/edge-prod.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; diff --git a/ui/src/themes/openems/environments/gitpod.ts b/ui/src/themes/openems/environments/gitpod.ts index 4b8f7f22ead..1ef2f8ca499 100644 --- a/ui/src/themes/openems/environments/gitpod.ts +++ b/ui/src/themes/openems/environments/gitpod.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Environment } from "src/environments"; import { theme } from "./theme"; From f13032596b609147d5d0dc0ae186618b111a2f0c Mon Sep 17 00:00:00 2001 From: Hiromasa Ihara Date: Thu, 27 Jun 2024 04:42:28 +0900 Subject: [PATCH 25/37] UI: update eslint rules and refactor types (#2676) * fix: ban Object, Function types * fix: snip always option in eol-last. because this is default. * fix: snip always option in semi. because this is default. cf. https://eslint.style/rules/default/semi * fix: reorder eslint rules to clear rule category 1. eslint native rules 2. unused-imports 3. typescript-eslint 4. angular-eslint 5. stylistic --- ui/.eslintrc.json | 24 +++++++------------ .../system/maintenance/maintenance.ts | 2 +- .../system/oe-system-update.component.ts | 2 +- .../modal/modal-button/modal-button.ts | 2 +- .../shared/oe-formly-component.ts | 4 ++-- ui/src/app/shared/service/service.ts | 2 +- 6 files changed, 14 insertions(+), 22 deletions(-) diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 419e1faab58..939db3ad5a0 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -30,15 +30,8 @@ "plugin:@angular-eslint/template/process-inline-templates" ], "rules": { + "curly": "error", "unused-imports/no-unused-imports": "error", - "@stylistic/semi": [ - "error", - "always" - ], - "@stylistic/quote-props": [ - "warn", - "consistent" - ], "@typescript-eslint/explicit-member-accessibility": [ "error", { @@ -67,15 +60,16 @@ "style": "camelCase" } ], - "curly": "error", + "@stylistic/semi": "error", + "@stylistic/quote-props": [ + "warn", + "consistent" + ], "@stylistic/comma-dangle": [ "error", "always-multiline" ], - "@stylistic/eol-last": [ - "error", - "always" - ], + "@stylistic/eol-last": "error", "@stylistic/no-trailing-spaces": "error", "@typescript-eslint/no-unused-vars": [ "error", @@ -90,9 +84,7 @@ { "extendDefaults": true, "types": { - "{}": false, - "Object": false, - "Function": false + "{}": false } } ] diff --git a/ui/src/app/edge/settings/system/maintenance/maintenance.ts b/ui/src/app/edge/settings/system/maintenance/maintenance.ts index 05ffad598c8..cb50d645a98 100644 --- a/ui/src/app/edge/settings/system/maintenance/maintenance.ts +++ b/ui/src/app/edge/settings/system/maintenance/maintenance.ts @@ -45,7 +45,7 @@ export class MaintenanceComponent implements OnInit { protected systemRestartState: BehaviorSubject<{ key: Type, state: SystemRestartState }> = new BehaviorSubject({ key: null, state: SystemRestartState.INITIAL }); protected spinnerId: string = MaintenanceComponent.SELECTOR; protected readonly SystemRestartState = SystemRestartState; - protected confirmationAlert: Function = (type: Type) => presentAlert(this.alertCtrl, this.translate, { + protected confirmationAlert: (type: Type) => void = (type: Type) => presentAlert(this.alertCtrl, this.translate, { message: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_WARNING', { system: environment.edgeShortName }), subHeader: this.translate.instant('SETTINGS.SYSTEM_UPDATE.RESTART_CONFIRMATION', { system: environment.edgeShortName }), buttons: [{ diff --git a/ui/src/app/edge/settings/system/oe-system-update.component.ts b/ui/src/app/edge/settings/system/oe-system-update.component.ts index f76d9d9725f..7b0689beab5 100644 --- a/ui/src/app/edge/settings/system/oe-system-update.component.ts +++ b/ui/src/app/edge/settings/system/oe-system-update.component.ts @@ -21,7 +21,7 @@ export class OeSystemUpdateComponent implements OnInit, OnDestroy { protected executeUpdate: ExecuteSystemUpdate = null; protected isWaiting: boolean; - protected confirmationAlert: Function = () => presentAlert(this.alertCtrl, this.translate, { + protected confirmationAlert: () => void = () => presentAlert(this.alertCtrl, this.translate, { message: this.translate.instant('SETTINGS.SYSTEM_UPDATE.WARNING', { system: environment.edgeShortName }), subHeader: this.translate.instant('SETTINGS.SYSTEM_UPDATE.SUB_HEADER'), buttons: [{ diff --git a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts index 74d01588bb1..0c118509ce9 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts @@ -18,5 +18,5 @@ export type ButtonLabel = { value: string; /** Icons for Button, displayed above the corresponding name */ icons?: Icon; - callback?: Function; + callback?: () => void; }; diff --git a/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts b/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts index 67d6d92e92a..50516a057d5 100644 --- a/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts +++ b/ui/src/app/shared/genericComponents/shared/oe-formly-component.ts @@ -4,7 +4,7 @@ import { FormlyFieldConfig } from "@ngx-formly/core"; import { TranslateService } from "@ngx-translate/core"; import { filter } from "rxjs/operators"; -import { ChannelAddress, EdgeConfig, Service } from "../../shared"; +import { CurrentData, ChannelAddress, EdgeConfig, Service } from "../../shared"; import { SharedModule } from "../../shared.module"; import { Role } from "../../type/role"; import { TextIndentation } from "../modal/modal-line/modal-line"; @@ -99,7 +99,7 @@ export namespace OeFormlyField { export type ValueFromChannelsLine = { type: 'value-from-channels-line', name: string, - value: Function, + value: (data: CurrentData) => string, channelsToSubscribe: ChannelAddress[], indentation?: TextIndentation, filter?: (value: number[] | null) => boolean, diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index 771b140ab6e..64997f0428c 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -126,7 +126,7 @@ export class Service extends AbstractService { // this.notify(notification); } - public setCurrentComponent(currentPageTitle: string | { languageKey: string, interpolateParams?: Object }, activatedRoute: ActivatedRoute): Promise { + public setCurrentComponent(currentPageTitle: string | { languageKey: string, interpolateParams?: {} }, activatedRoute: ActivatedRoute): Promise { return new Promise((resolve, reject) => { // Set the currentPageTitle only once per ActivatedRoute if (this.currentActivatedRoute != activatedRoute) { From f63a533b36f7f05a135ecbbb8565b66c696100f3 Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Fri, 28 Jun 2024 10:49:21 +0200 Subject: [PATCH 26/37] CI: update github-actions using dependabot (#2688) --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index abb98f69b4c..21080d06c45 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,3 +12,9 @@ updates: interval: weekly open-pull-requests-limit: 10 target-branch: develop +- package-ecosystem: "github-actions" + directory: "/.github/workflows" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + target-branch: develop From 7ea3e06953679d2cfee830467ee8d9fa3910fd0c Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 28 Jun 2024 12:26:24 +0200 Subject: [PATCH 27/37] FEMS Backports 2024-06 (2) (#2692) - UI: prepare build for native Android App - SymmetricEss: add Min-/MaxCellVoltage-/Temperature channels to modbus slave table - Added the following register to the Modbus slave table - MIN_CELL_VOLTAGE - MAX_CELL_VOLTAGE - MIN_CELL_TEMPERATURE - MAX_CELL_TEMPERATURE - UI: add footer subnavigation - New subnavigation in /history/production - HeatingElement: added JUnit test - UI: allow SNAPSHOT update for OWNER/INSTALLER - Remove special handling for SNAPSHOT versions in update handler - Tools: add internal tool to convert between JSONRPC and XLSX - UI: add loading screen during authentication - Introduction of loading screen, shown during authentification process - Skip "Login"-screen if a valid authentication token exists - EdgeConfig: remove unused factories & properties - Removed unused factories & factory properties from EdgeConfig - Added separate request to get all factories and properties for component update / installation - UI: fix error messages shown in status.component - fix display of error message in status.component, was showing property channels as well - Apps for DiscovergyMeter and TimeInfluxDb - SunSpec: set persistence priority VERY_LOW - Backend improvements - Add logging for certain commands - Improve Metadata Odoo performance - Improve Postgres performance - reduce update time from 120 to 30 seconds - fix Sum-State update bug - InfluxDB: - extract channel filter to separate class; add unit tests - add configurable channel blacklist - improve FieldTypeConflictHandler; add unit tests - StringUtils: drop matchesIntegerPattern and matchesFloatPattern; replace with Guava - ThreadPoolUtils: fix possible NullPointerException - ComponentManagerImpl: remove Thread Sleep - Remove test thread sleep in "GetChannel" handler - UI: Channels fix setting values - Bug: "Cannot read properties of undefined (reading 'componentId')" when setting a value in the channels view - Debian package: implement apt purge - CI: Improve java build - Debian: fix build ```bash + dpkg-deb -Zxz --build debian /woodpecker/src/git.intranet.fenecon.de/FENECON/fems/build/target/fems.debdpkg-deb: error: maintainer script 'postrm' has bad permissions 644 (must be >=0555 and <=0775) ``` - CI: split build image - Split android sdk into a seperate image. - add bash image to git - Replace StringUtils.matches*Pattern --------- Co-authored-by: Johann Kaufmann <165755282+johannk24@users.noreply.github.com> Co-authored-by: Kai Jeschek <99220919+da-Kai@users.noreply.github.com> Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Manoj-Kumar Varikela <20610573+manojniit@users.noreply.github.com> Co-authored-by: Maximilian Lang <35968713+mlang97@users.noreply.github.com> Co-authored-by: Michael Grill <59126309+michaelgrill@users.noreply.github.com> Co-authored-by: Pooran Chandrashekaraiah <46567310+pooran-c@users.noreply.github.com> Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Co-authored-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> Co-authored-by: Hueseyin Sahutoglu <34771592+huseyinsaht@users.noreply.github.com> --- build.gradle | 4 +- cnf/pom.xml | 9 +- codecov.yml | 4 +- gradle.properties | 2 +- .../BackendApp.bndrun | 6 +- .../EdgeRpcRequestHandler.java | 166 +- .../backend/metadata/odoo/MetadataOdoo.java | 104 +- .../odoo/postgres/PeriodicWriteWorker.java | 124 +- .../aggregatedinflux/AllowedChannels.java | 26 +- .../timedata/influx/ChannelFilter.java | 96 + .../backend/timedata/influx/Config.java | 3 + .../influx/FieldTypeConflictHandler.java | 179 +- .../timedata/influx/TimedataInfluxDb.java | 175 +- .../timedata/influx/ChannelFilterTest.java | 52 + .../influx/FieldTypeConflictHandlerTest.java | 51 + .../timedata/influx/TimedataInfluxDbTest.java | 34 - .../timedata/timescaledb/internal/Type.java | 32 +- .../timescaledb/internal/TypeTest.java | 2 +- .../backend/uiwebsocket/impl/OnRequest.java | 115 +- .../common/oem/DummyOpenemsEdgeOem.java | 2 + .../io/openems/common/types/EdgeConfig.java | 18 +- .../io/openems/common/utils/StringUtils.java | 29 - .../openems/common/utils/ThreadPoolUtils.java | 10 +- .../jsonrpc/response/JsonrpcToXlsxApp.java | 63 + .../jsonrpc/response/XlsxToJsonrpcApp.java | 70 + .../openems/common/utils/StringUtilsTest.java | 5 - io.openems.edge.application/EdgeApp.bndrun | 6 +- .../edge/bridge/modbus/sunspec/Point.java | 6 +- .../edge/bridge/modbus/sunspec/PointTest.java | 29 + .../ControllerHeatingElementImplTest4.java | 95 + .../edge/app/api/TimedataInfluxDb.java | 219 + .../app/integratedsystem/FeneconHome20.java | 1 - .../app/integratedsystem/FeneconHome30.java | 1 - .../edge/app/meter/DiscovergyMeter.java | 229 + .../core/appmanager/OpenemsAppCategory.java | 6 + .../core/appmanager/translation_de.properties | 35 + .../core/appmanager/translation_en.properties | 34 + .../ComponentManagerImpl.java | 37 +- .../jsonrpc/GetAllComponentFactories.java | 66 + .../jsonrpc/GetPropertiesOfFactory.java | 76 + .../io/openems/edge/core/appmanager/Apps.java | 22 + .../core/appmanager/TestTranslations.java | 8 + .../io/openems/edge/ess/api/SymmetricEss.java | 4 + .../common/AbstractChannelManager.java | 12 + .../shared/influxdb/proxy/InfluxQlProxy.java | 64 +- .../influxdb/proxy/InfluxQlProxyTest.java | 10 + io.openems.wrapper/bnd.bnd | 3 +- io.openems.wrapper/fastexcel.bnd | 7 +- tools/build-debian-package.sh | 12 +- tools/debian/DEBIAN/postrm | 16 + tools/drone/openems-android.sh | 37 + tools/drone/openems-bash.sh | 19 + tools/drone/openems-build.sh | 29 + ui/README.md | 36 +- ui/android/.idea/.gitignore | 3 + ui/android/.idea/compiler.xml | 6 + ui/android/.idea/jarRepositories.xml | 30 + ui/android/.idea/misc.xml | 9 + ui/android/app/.gitignore | 2 + ui/android/app/build.gradle | 88 + ui/android/app/capacitor.build.gradle | 24 + ui/android/app/proguard-rules.pro | 21 + .../myapp/ExampleInstrumentedTest.java | 26 + ui/android/app/src/main/AndroidManifest.xml | 39 + .../getcapacitor/myapp/ExampleUnitTest.java | 18 + ui/android/build.gradle | 32 + ui/android/capacitor.settings.gradle | 21 + ui/android/gradle.properties | 22 + ui/android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + ui/android/gradlew | 244 + ui/android/gradlew.bat | 92 + ui/android/keystore.properties | 4 + ui/android/settings.gradle | 5 + ui/android/variables.gradle | 16 + ui/capacitor.config.ts | 47 + ui/ionic.config.json | 6 +- ui/package-lock.json | 10601 +++++++++++----- ui/package.json | 18 +- ui/src/app/app-routing.module.ts | 17 +- ui/src/app/app.component.ts | 6 + ui/src/app/app.module.ts | 2 + ui/src/app/app.service.ts | 154 + .../edge/history/common/energy/flat/flat.ts | 8 + .../common/production/details/chart/chart.ts | 88 + .../production/details/details.overview.html | 6 + .../production/details/details.overview.ts | 24 + .../common/production/overview/overview.html | 1 + .../common/production/overview/overview.ts | 19 +- .../history/common/production/production.ts | 4 + .../app/edge/history/history.component.html | 5 +- ui/src/app/edge/history/history.component.ts | 2 + ui/src/app/edge/history/historydataservice.ts | 6 + ui/src/app/edge/live/live.component.html | 4 + ui/src/app/edge/live/live.component.ts | 4 + ui/src/app/edge/live/livedataservice.ts | 10 + .../settings/channels/channels.component.html | 4 +- .../settings/channels/channels.component.ts | 10 +- .../component/install/index.component.ts | 67 +- .../component/install/install.component.ts | 100 +- .../component/update/index.component.ts | 3 - .../component/update/update.component.ts | 82 +- .../settings/system/executeSystemUpdate.ts | 48 +- ui/src/app/index/index.module.ts | 2 + ui/src/app/index/login.component.html | 2 +- ui/src/app/index/login.component.ts | 4 + ui/src/app/index/shared/loading-screen.html | 5 + ui/src/app/index/shared/loading-screen.ts | 38 + ui/src/app/shared/directive/autofill.ts | 25 + ui/src/app/shared/edge/edge.spec.ts | 53 + ui/src/app/shared/edge/edge.ts | 36 +- ui/src/app/shared/edge/edgeconfig.spec.ts | 56 +- ui/src/app/shared/edge/edgeconfig.ts | 115 +- .../chart/abstracthistorychart.html | 7 +- .../shared/genericComponents/chart/chart.html | 4 +- .../footer-navigation/footerNavigation.html | 48 + .../footer-navigation/footerNavigation.ts | 114 + .../genericComponents/genericComponents.ts | 3 + .../genericComponents/shared/converter.ts | 1 + .../genericComponents/shared/dataservice.ts | 3 + .../request/getPropertiesOfFactoryRequest.ts | 33 + .../getPropertiesOfFactoryResponse.ts | 31 + ui/src/app/shared/service/service.ts | 12 +- ui/src/app/shared/service/utils.ts | 2 +- ui/src/app/shared/service/websocket.ts | 2 +- ui/src/app/shared/shared.ts | 13 + .../status/single/status.component.spec.ts | 2 +- .../shared/status/single/status.component.ts | 6 + ui/src/assets/i18n/de.json | 5 +- ui/src/assets/i18n/en.json | 5 +- 130 files changed, 11325 insertions(+), 3857 deletions(-) create mode 100644 io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java create mode 100644 io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java delete mode 100644 io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/TimedataInfluxDbTest.java create mode 100644 io.openems.common/test/io/openems/common/jsonrpc/response/JsonrpcToXlsxApp.java create mode 100644 io.openems.common/test/io/openems/common/jsonrpc/response/XlsxToJsonrpcApp.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/PointTest.java create mode 100644 io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/api/TimedataInfluxDb.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/meter/DiscovergyMeter.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetAllComponentFactories.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetPropertiesOfFactory.java create mode 100755 tools/debian/DEBIAN/postrm create mode 100755 tools/drone/openems-android.sh create mode 100644 tools/drone/openems-bash.sh create mode 100644 tools/drone/openems-build.sh create mode 100644 ui/android/.idea/.gitignore create mode 100644 ui/android/.idea/compiler.xml create mode 100644 ui/android/.idea/jarRepositories.xml create mode 100644 ui/android/.idea/misc.xml create mode 100644 ui/android/app/.gitignore create mode 100644 ui/android/app/build.gradle create mode 100644 ui/android/app/capacitor.build.gradle create mode 100644 ui/android/app/proguard-rules.pro create mode 100644 ui/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java create mode 100644 ui/android/app/src/main/AndroidManifest.xml create mode 100644 ui/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java create mode 100644 ui/android/build.gradle create mode 100644 ui/android/capacitor.settings.gradle create mode 100644 ui/android/gradle.properties create mode 100644 ui/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 ui/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 ui/android/gradlew create mode 100644 ui/android/gradlew.bat create mode 100644 ui/android/keystore.properties create mode 100644 ui/android/settings.gradle create mode 100644 ui/android/variables.gradle create mode 100644 ui/capacitor.config.ts create mode 100644 ui/src/app/app.service.ts create mode 100644 ui/src/app/edge/history/common/production/details/chart/chart.ts create mode 100644 ui/src/app/edge/history/common/production/details/details.overview.html create mode 100644 ui/src/app/edge/history/common/production/details/details.overview.ts create mode 100644 ui/src/app/index/shared/loading-screen.html create mode 100644 ui/src/app/index/shared/loading-screen.ts create mode 100644 ui/src/app/shared/directive/autofill.ts create mode 100644 ui/src/app/shared/edge/edge.spec.ts create mode 100644 ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.html create mode 100644 ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.ts create mode 100644 ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts create mode 100644 ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts diff --git a/build.gradle b/build.gradle index a432a1fa395..72457c55315 100644 --- a/build.gradle +++ b/build.gradle @@ -80,8 +80,8 @@ subprojects { html.required = false sarif.required = false } - minHeapSize = "256m" - maxHeapSize = "1g" + minHeapSize = "512m" + maxHeapSize = "2048m" // Exclude com.dalsemi.onewire exclude '**/com/dalsemi/onewire/*' } diff --git a/cnf/pom.xml b/cnf/pom.xml index 271f2e7233a..79d3e7d73c3 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -9,8 +9,8 @@ - biz.aQute.bnd.workspace - biz.aQute.bnd.workspace.gradle.plugin + biz.aQute.bnd + biz.aQute.bnd.gradle 7.0.0 @@ -262,6 +262,11 @@ fastexcel 0.18.0 + + org.dhatim + fastexcel-reader + 0.18.0 + org.eclipse.paho diff --git a/codecov.yml b/codecov.yml index 3ee859df746..1f9dcb53ef3 100644 --- a/codecov.yml +++ b/codecov.yml @@ -4,7 +4,7 @@ coverage: status: project: default: - target: '60%' + target: auto #default comment: layout: "condensed_header, diff" @@ -12,4 +12,4 @@ comment: require_changes: false require_base: false require_head: true - hide_project_coverage: true \ No newline at end of file + hide_project_coverage: true diff --git a/gradle.properties b/gradle.properties index 9779ffb8f4e..ac682e37020 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,4 +10,4 @@ maven.repo.local=cnf org.gradle.caching=true org.gradle.parallel=false org.gradle.workers.max=1 -org.gradle.jvmargs=-Xms256m -Xmx512m "-XX:MaxMetaspaceSize=256m" +org.gradle.jvmargs=-Xms512m -Xmx2048m "-XX:MaxMetaspaceSize=512m" diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 3187a198622..e103405ba64 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -60,6 +60,7 @@ -runbundles: \ Java-WebSocket;version='[1.5.4,1.5.5)',\ + com.fasterxml.aalto-xml;version='[1.3.2,1.3.3)',\ com.google.gson;version='[2.11.0,2.11.1)',\ com.google.guava;version='[33.2.1,33.2.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ @@ -100,7 +101,9 @@ io.openems.wrapper.retrofit-converter-scalars;version=snapshot,\ io.openems.wrapper.retrofit2;version=snapshot,\ io.reactivex.rxjava3.rxjava;version='[3.1.8,3.1.9)',\ + org.apache.commons.commons-compress;version='[1.26.1,1.26.2)',\ org.apache.commons.commons-csv;version='[1.10.0,1.10.1)',\ + org.apache.commons.commons-io;version='[2.15.1,2.15.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ @@ -121,4 +124,5 @@ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ org.owasp.encoder;version='[1.2.3,1.2.4)',\ org.postgresql.jdbc;version='[42.7.3,42.7.4)',\ - reactive-streams;version='[1.0.4,1.0.5)' \ No newline at end of file + reactive-streams;version='[1.0.4,1.0.5)',\ + stax2-api;version='[4.2.0,4.2.1)' \ No newline at end of file diff --git a/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java b/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java index dcb7a5a800e..c98e855c17d 100644 --- a/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java +++ b/io.openems.backend.core/src/io/openems/backend/core/jsonrpcrequesthandler/EdgeRpcRequestHandler.java @@ -1,14 +1,23 @@ package io.openems.backend.core.jsonrpcrequesthandler; +import static io.openems.common.utils.JsonUtils.getAsOptionalBoolean; +import static io.openems.common.utils.JsonUtils.getAsOptionalString; +import static io.openems.common.utils.JsonUtils.getAsString; +import static java.util.Collections.emptyMap; + +import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import io.openems.backend.common.metadata.AppCenterHandler; +import io.openems.backend.common.metadata.Metadata.GenericSystemLog; import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.AppCenterRequest; +import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; import io.openems.common.jsonrpc.request.EdgeRpcRequest; import io.openems.common.jsonrpc.request.GetEdgeConfigRequest; import io.openems.common.jsonrpc.request.QueryHistoricTimeseriesDataRequest; @@ -49,39 +58,62 @@ protected CompletableFuture handleRequest(User user, UUID messa } user.assertEdgeRoleIsAtLeast(EdgeRpcRequest.METHOD, edgeRpcRequest.getEdgeId(), Role.GUEST); - CompletableFuture resultFuture; - switch (request.getMethod()) { - case AppCenterRequest.METHOD: - resultFuture = AppCenterHandler.handleUserRequest(this.parent.appCenterMetadata, // - t -> this.handleRequest(user, messageId, t), // - AppCenterRequest.from(request), user, edgeId); - break; - - case QueryHistoricTimeseriesDataRequest.METHOD: - resultFuture = this.handleQueryHistoricDataRequest(edgeId, user, - QueryHistoricTimeseriesDataRequest.from(request)); - break; - - case QueryHistoricTimeseriesEnergyRequest.METHOD: - resultFuture = this.handleQueryHistoricEnergyRequest(edgeId, user, - QueryHistoricTimeseriesEnergyRequest.from(request)); - break; - - case QueryHistoricTimeseriesEnergyPerPeriodRequest.METHOD: - resultFuture = this.handleQueryHistoricEnergyPerPeriodRequest(edgeId, user, - QueryHistoricTimeseriesEnergyPerPeriodRequest.from(request)); - break; - - case QueryHistoricTimeseriesExportXlxsRequest.METHOD: - resultFuture = this.handleQueryHistoricTimeseriesExportXlxsRequest(edgeId, user, - QueryHistoricTimeseriesExportXlxsRequest.from(request)); - break; - - case GetEdgeConfigRequest.METHOD: - resultFuture = this.handleGetEdgeConfigRequest(edgeId, user, GetEdgeConfigRequest.from(request)); - break; - - default: + var resultFuture = switch (request.getMethod()) { + case AppCenterRequest.METHOD -> AppCenterHandler.handleUserRequest(this.parent.appCenterMetadata, // + t -> this.handleRequest(user, messageId, t), // + AppCenterRequest.from(request), user, edgeId); + + case QueryHistoricTimeseriesDataRequest.METHOD -> + this.handleQueryHistoricDataRequest(edgeId, user, QueryHistoricTimeseriesDataRequest.from(request)); + + case QueryHistoricTimeseriesEnergyRequest.METHOD -> + this.handleQueryHistoricEnergyRequest(edgeId, user, QueryHistoricTimeseriesEnergyRequest.from(request)); + + case QueryHistoricTimeseriesEnergyPerPeriodRequest.METHOD -> this.handleQueryHistoricEnergyPerPeriodRequest( + edgeId, user, QueryHistoricTimeseriesEnergyPerPeriodRequest.from(request)); + + case QueryHistoricTimeseriesExportXlxsRequest.METHOD -> this.handleQueryHistoricTimeseriesExportXlxsRequest( + edgeId, user, QueryHistoricTimeseriesExportXlxsRequest.from(request)); + + case GetEdgeConfigRequest.METHOD -> + this.handleGetEdgeConfigRequest(edgeId, user, GetEdgeConfigRequest.from(request)); + + case ComponentJsonApiRequest.METHOD -> { + final var componentRequest = ComponentJsonApiRequest.from(request); + if (!"_host".equals(componentRequest.getComponentId())) { + yield null; + } + switch (componentRequest.getPayload().getMethod()) { + case "executeSystemCommand" -> { + final var executeSystemCommandRequest = componentRequest.getPayload(); + final var p = executeSystemCommandRequest.getParams(); + this.parent.metadata.logGenericSystemLog(new LogSystemExecuteCommend(edgeId, user, // + getAsString(p, "command"), // + getAsOptionalBoolean(p, "sudo").orElse(null), // + getAsOptionalString(p, "username").orElse(null), // + getAsOptionalString(p, "password").orElse(null), // + getAsOptionalBoolean(p, "runInBackground").orElse(null) // + )); + } + case "executeSystemUpdate" -> { + this.parent.metadata.logGenericSystemLog(new LogUpdateSystem(edgeId, user)); + } + case "executeSystemRestart" -> { + final var executeSystemCommandRequest = componentRequest.getPayload(); + final var p = executeSystemCommandRequest.getParams(); + this.parent.metadata.logGenericSystemLog(new LogRestartSystem(edgeId, user, // + getAsOptionalString(p, "type").orElse(null) // + )); + } + } + yield null; + } + + default -> null; + }; + + if (resultFuture == null) { + // Request not handled delegate to edge resultFuture = this.parent.edgeWebsocket.send(edgeId, user, request); } @@ -100,6 +132,74 @@ protected CompletableFuture handleRequest(User user, UUID messa return result; } + private record LogSystemExecuteCommend(// + String edgeId, // non-null + User user, // non-null + String command, // non-null + Boolean sudo, // null-able + String username, // null-able + String password, // null-able + Boolean runInBackground // null-able + ) implements GenericSystemLog { + + @Override + public String teaser() { + return "Systemcommand: " + this.command; + } + + @Override + public Map getValues() { + return Map.of(// + "Sudo", Boolean.toString(Optional.ofNullable(this.sudo()).orElse(false)), // + "Command", this.command(), // + "Username", this.username(), // + "Password", this.password() == null || this.password().isEmpty() ? "[NOT_SET]" : "[SET]", // + "Run in Background", Boolean.toString(Optional.ofNullable(this.runInBackground()).orElse(false)) // + ); + } + + } + + private record LogUpdateSystem(// + String edgeId, // non-null + User user // non-null + ) implements GenericSystemLog { + + @Override + public String teaser() { + return "Systemupdate"; + } + + @Override + public Map getValues() { + return emptyMap(); + } + + } + + private record LogRestartSystem(// + String edgeId, // non-null + User user, // non-null + String type // null-able + ) implements GenericSystemLog { + + @Override + public String teaser() { + return "Systemrestart"; + } + + @Override + public Map getValues() { + if (this.type == null) { + return emptyMap(); + } + return Map.of(// + "type", this.type // + ); + } + + } + /** * Handles a {@link QueryHistoricTimeseriesDataRequest}. * diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java index 1e5e88627ce..6c544232e40 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java @@ -1,19 +1,25 @@ package io.openems.backend.metadata.odoo; +import static io.openems.common.utils.JsonUtils.getAsBoolean; +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.getAsJsonArray; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.common.utils.JsonUtils.getAsOptionalJsonArray; +import static io.openems.common.utils.JsonUtils.getAsOptionalString; +import static io.openems.common.utils.JsonUtils.getAsString; import static io.openems.common.utils.ThreadPoolUtils.shutdownAndAwaitTermination; +import static java.util.stream.Collectors.toUnmodifiableMap; import java.sql.SQLException; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; @@ -95,8 +101,7 @@ public class MetadataOdoo extends AbstractMetadata implements AppCenterMetadata, private final ConcurrentHashMap users = new ConcurrentHashMap<>(); private final ConcurrentHashMap activeTasks = new ConcurrentHashMap<>(100); - private ThreadPoolExecutor defaultExecutor = null; - private ThreadPoolExecutor edgeConfigExecutor = null; + private ThreadPoolExecutor executor = null; private final ConcurrentHashMap pendingEdgeConfigIds = new ConcurrentHashMap<>(); @Reference @@ -125,10 +130,8 @@ private void activate(Config config) throws SQLException { + "Database [" + config.database() + "]"); this.debugMode = config.debugMode(); - this.defaultExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(config.poolSize() / 2, - new ThreadFactoryBuilder().setNameFormat("Metadata.Odoo.Default-%d").build()); - this.edgeConfigExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(config.poolSize() / 2, - new ThreadFactoryBuilder().setNameFormat("Metadata.Odoo.EdgeConfig-%d").build()); + this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(config.poolSize(), + new ThreadFactoryBuilder().setNameFormat("Metadata.Odoo-%d").build()); this.odooHandler = new OdooHandler(this, this.edgeCache, config); this.postgresHandler = new PostgresHandler(this, this.edgeCache, config, () -> { this.setInitialized(); @@ -138,8 +141,7 @@ private void activate(Config config) throws SQLException { @Deactivate private void deactivate() { this.logInfo(this.log, "Deactivate"); - shutdownAndAwaitTermination(this.defaultExecutor, 5); - shutdownAndAwaitTermination(this.edgeConfigExecutor, 5); + shutdownAndAwaitTermination(this.executor, 5); if (this.postgresHandler != null) { this.postgresHandler.deactivate(); } @@ -162,15 +164,15 @@ public User authenticate(String sessionId) throws OpenemsNamedException { var result = this.odooHandler.authenticateSession(sessionId); // Parse Result - var jUser = JsonUtils.getAsJsonObject(result, "user"); - var odooUserId = JsonUtils.getAsInt(jUser, "id"); - var login = JsonUtils.getAsString(jUser, "login"); - var name = JsonUtils.getAsString(jUser, "name"); - var language = Language.from(JsonUtils.getAsString(jUser, "language")); - var globalRole = Role.getRole(JsonUtils.getAsString(jUser, "global_role")); - var hasMultipleEdges = JsonUtils.getAsBoolean(jUser, "has_multiple_edges"); - - final var settings = JsonUtils.getAsOptionalString(jUser, "settings") // + var jUser = getAsJsonObject(result, "user"); + var odooUserId = getAsInt(jUser, "id"); + var login = getAsString(jUser, "login"); + var name = getAsString(jUser, "name"); + var language = Language.from(getAsString(jUser, "language")); + var globalRole = Role.getRole(getAsString(jUser, "global_role")); + var hasMultipleEdges = getAsBoolean(jUser, "has_multiple_edges"); + + final var settings = getAsOptionalString(jUser, "settings") // .flatMap(JsonUtils::parseOptional) // .flatMap(JsonUtils::getAsOptionalJsonObject) // .orElse(new JsonObject()); @@ -293,7 +295,7 @@ public int submitSetupProtocol(User user, JsonObject jsonObject) throws OpenemsN public void registerUser(JsonObject jsonObject, String oem) throws OpenemsNamedException { final OdooUserRole role; - var roleOpt = JsonUtils.getAsOptionalString(jsonObject, "role"); + var roleOpt = getAsOptionalString(jsonObject, "role"); if (roleOpt.isPresent()) { role = OdooUserRole.getRole(roleOpt.get()); } else { @@ -365,7 +367,7 @@ public void handleEvent(Event event) { var edge = (MyEdge) reader.getProperty(Edge.Events.OnSetProducttype.EDGE); var producttype = reader.getString(Edge.Events.OnSetProducttype.PRODUCTTYPE); // Set Producttype in Odoo/Postgres - this.execute(this.defaultExecutor, "OnSetProducttype", () -> { + this.execute("OnSetProducttype", () -> { try { this.postgresHandler.edge.updateProductType(edge.getOdooId(), producttype); } catch (SQLException | OpenemsNamedException e) { @@ -381,7 +383,7 @@ public void handleEvent(Event event) { @Override public void logGenericSystemLog(GenericSystemLog systemLog) { - this.execute(this.defaultExecutor, "LogGenericSystemLog", () -> { + this.execute("LogGenericSystemLog", () -> { try { final var edge = (MyEdge) this.getEdgeOrError(systemLog.edgeId()); this.postgresHandler.edge.insertGenericSystemLog(edge.getOdooId(), systemLog); @@ -401,7 +403,7 @@ private void onSetConfigEvent(EventReader reader) { return; } - this.execute(this.edgeConfigExecutor, "OnSetConfig", () -> { + this.execute("OnSetConfig", () -> { try { var newConfig = (EdgeConfig) reader.getProperty(Edge.Events.OnSetConfig.CONFIG); @@ -496,7 +498,7 @@ public void sendAddUnregisterKeyHistory(String edgeId, String appId, String key, @Override public JsonArray sendGetRegisteredKeys(String edgeId, String appId) throws OpenemsNamedException { var response = this.odooHandler.getRegisteredKeys(edgeId, appId); - return JsonUtils.getAsOptionalJsonArray(response, "keys") // + return getAsOptionalJsonArray(response, "keys") // .orElse(new JsonArray()) // ; } @@ -504,7 +506,7 @@ public JsonArray sendGetRegisteredKeys(String edgeId, String appId) throws Opene @Override public JsonArray sendGetPossibleApps(String key, String edgeId) throws OpenemsNamedException { var response = this.odooHandler.getPossibleApps(key, edgeId); - return JsonUtils.getAsJsonArray(response, "bundles"); + return getAsJsonArray(response, "bundles"); } @Override @@ -574,7 +576,7 @@ public List getPageDevice(// final PaginationOptions paginationOptions // ) throws OpenemsNamedException { var result = this.odooHandler.getEdges((MyUser) user, paginationOptions); - final var jsonArray = JsonUtils.getAsJsonArray(result, "devices"); + final var jsonArray = getAsJsonArray(result, "devices"); final var resultMetadata = new ArrayList(jsonArray.size()); for (var jElement : jsonArray) { resultMetadata.add(this.convertToEdgeMetadata(user, jElement)); @@ -588,7 +590,7 @@ public EdgeMetadata getEdgeMetadataForUser(User user, String edgeId) throws Open } private EdgeMetadata convertToEdgeMetadata(User user, JsonElement jDevice) throws OpenemsNamedException { - final var edgeId = JsonUtils.getAsString(jDevice, "name"); + final var edgeId = getAsString(jDevice, "name"); // TODO remove cached edge final var cachedEdge = this.getEdge(edgeId).orElse(null); @@ -596,23 +598,23 @@ private EdgeMetadata convertToEdgeMetadata(User user, JsonElement jDevice) throw throw new OpenemsException("Unable to find edge with id [" + edgeId + "]"); } - final var role = Role.getRole(JsonUtils.getAsString(jDevice, "role")); + final var role = Role.getRole(getAsString(jDevice, "role")); user.setRole(edgeId, role); - final var sumState = JsonUtils.getAsOptionalString(jDevice, "openems_sum_state_level") // + final var sumState = getAsOptionalString(jDevice, "openems_sum_state_level") // .map(String::toUpperCase) // .map(Level::valueOf) // .orElse(Level.OK); final var commment = this.oem.anonymizeEdgeComment(user, // - JsonUtils.getAsOptionalString(jDevice, "comment").orElse(""), // + getAsOptionalString(jDevice, "comment").orElse(""), // edgeId); - final var producttype = JsonUtils.getAsOptionalString(jDevice, "producttype").orElse(""); - final var firstSetupProtocol = JsonUtils.getAsOptionalString(jDevice, "first_setup_protocol_date") + final var producttype = getAsOptionalString(jDevice, "producttype").orElse(""); + final var firstSetupProtocol = getAsOptionalString(jDevice, "first_setup_protocol_date") .map(DateTime::stringToDateTime) // .orElse(null); - final var lastmessage = JsonUtils.getAsOptionalString(jDevice, "lastmessage") // + final var lastmessage = getAsOptionalString(jDevice, "lastmessage") // .map(DateTime::stringToDateTime) // .orElse(null); @@ -649,18 +651,17 @@ public void updateUserSettings(User user, JsonObject settings) throws OpenemsNam /** * Execute a {@link Runnable} using the shared {@link ExecutorService}. * - * @param executor the {@link Executor} - * @param id the identifier for this type of command - * @param command the {@link Runnable} + * @param id the identifier for this type of command + * @param command the {@link Runnable} */ - private void execute(Executor executor, String id, Runnable command) { - if (executor == null) { + private void execute(String id, Runnable command) { + if (this.executor == null) { return; } if (this.debugMode.isAtLeast(DebugMode.DETAILED)) { this.activeTasks.computeIfAbsent(id, ATOMIC_INTEGER_PROVIDER).incrementAndGet(); - executor.execute(() -> { + this.executor.execute(() -> { try { command.run(); } catch (Throwable t) { @@ -670,17 +671,15 @@ private void execute(Executor executor, String id, Runnable command) { } }); } else { - executor.execute(command); + this.executor.execute(command); } } @Override public String debugLog() { var b = new StringBuilder("[").append(this.getName()).append("] [monitor] ") // - .append("Default: ") // - .append(ThreadPoolUtils.debugLog(this.defaultExecutor)) // - .append(", EdgeConfig: ") // - .append(ThreadPoolUtils.debugLog(this.edgeConfigExecutor)); + .append("Executor: ") // + .append(ThreadPoolUtils.debugLog(this.executor)); if (this.debugMode.isAtLeast(DebugMode.DETAILED)) { b.append(", Tasks: "); @@ -697,18 +696,11 @@ public String debugLog() { @Override public Map debugMetrics() { - // TODO implement getId() - final var metrics = new HashMap(); - var defaultExecutorMetrics = ThreadPoolUtils.debugMetrics(this.defaultExecutor); - var edgeConfigExecutorMetrics = ThreadPoolUtils.debugMetrics(this.edgeConfigExecutor); - defaultExecutorMetrics.forEach((key, value) -> { - var value2 = edgeConfigExecutorMetrics.get(key); - if (value2 != null) { - value += value2; - } - metrics.put("metadata0/" + key, new JsonPrimitive(value)); - }); - return metrics; + return ThreadPoolUtils.debugMetrics(this.executor).entrySet().stream() // + .collect(toUnmodifiableMap(// + // TODO implement getId() + e -> "metadata0/" + e.getKey(), // + e -> new JsonPrimitive(e.getValue()))); } } diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/postgres/PeriodicWriteWorker.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/postgres/PeriodicWriteWorker.java index aa9707fface..feade9c8c5c 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/postgres/PeriodicWriteWorker.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/postgres/PeriodicWriteWorker.java @@ -1,16 +1,28 @@ package io.openems.backend.metadata.odoo.postgres; +import static java.util.Collections.emptySet; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toSet; + import java.sql.SQLException; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; +import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +45,7 @@ public class PeriodicWriteWorker { */ private static final boolean DEBUG_MODE = true; - private static final int UPDATE_INTERVAL_IN_SECONDS = 120; + private static final int UPDATE_INTERVAL_IN_SECONDS = 30; private final Logger log = LoggerFactory.getLogger(PeriodicWriteWorker.class); private final PostgresHandler parent; @@ -58,7 +70,7 @@ public PeriodicWriteWorker(PostgresHandler parent) { */ public synchronized void start() { this.future = this.executor.scheduleWithFixedDelay(// - () -> this.task.accept(this.parent.edge), // + this::applyChanges, // PeriodicWriteWorker.UPDATE_INTERVAL_IN_SECONDS, PeriodicWriteWorker.UPDATE_INTERVAL_IN_SECONDS, TimeUnit.SECONDS); } @@ -76,14 +88,13 @@ public synchronized void stop() { } private final LinkedBlockingQueue lastMessageOdooIds = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue isOnlineOdooIds = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue isOfflineOdooIds = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue sumStateOk = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue sumStateInfo = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue sumStateWarning = new LinkedBlockingQueue<>(); - private final LinkedBlockingQueue sumStateFault = new LinkedBlockingQueue<>(); - - private final Consumer task = edge -> { + private ExchangableObject> connectionStatesToUpdate = new ExchangableObject<>( + new ConcurrentHashMap<>()); + private ExchangableObject> sumStatesToUpdate = new ExchangableObject<>( + new ConcurrentHashMap<>()); + + private final void applyChanges() { + final var edge = this.parent.edge; if (PeriodicWriteWorker.DEBUG_MODE) { this.debugLog(); } @@ -93,19 +104,37 @@ public synchronized void stop() { edge.updateLastMessage(drainToSet(this.lastMessageOdooIds)); // Online/Offline - edge.updateOpenemsIsConnected(drainToSet(this.isOfflineOdooIds), false); - edge.updateOpenemsIsConnected(drainToSet(this.isOnlineOdooIds), true); + final var connectionToUpdate = this.connectionStatesToUpdate.exchange(new ConcurrentHashMap<>()); + final var edgesByConnection = connectionToUpdate.entrySet().stream() // + .collect(groupingBy(Entry::getValue, mapping(Entry::getKey, toSet()))); + edge.updateOpenemsIsConnected(edgesByConnection.getOrDefault(false, emptySet()), false); + edge.updateOpenemsIsConnected(edgesByConnection.getOrDefault(true, emptySet()), true); + if (PeriodicWriteWorker.DEBUG_MODE) { + this.parent.logInfo(this.log, + "Update Edge connection states online[" + + edgesByConnection.getOrDefault(true, emptySet()).size() + "] offline[" + + edgesByConnection.getOrDefault(false, emptySet()).size() + "]"); + } // Sum-State - edge.updateSumState(drainToSet(this.sumStateOk), Level.OK); - edge.updateSumState(drainToSet(this.sumStateInfo), Level.INFO); - edge.updateSumState(drainToSet(this.sumStateWarning), Level.WARNING); - edge.updateSumState(drainToSet(this.sumStateFault), Level.FAULT); + final var statesToUpdate = this.sumStatesToUpdate.exchange(new ConcurrentHashMap<>()); + final var edgesByState = statesToUpdate.entrySet().stream() + .collect(groupingBy(Entry::getValue, mapping(Entry::getKey, toSet()))); + for (var stateEntry : edgesByState.entrySet()) { + edge.updateSumState(stateEntry.getValue(), stateEntry.getKey()); + } + if (PeriodicWriteWorker.DEBUG_MODE) { + this.parent.logInfo(this.log, "Update Edge sum states " + Stream.of(Level.values()) // + .map(level -> { + final var itemsToUpdate = edgesByState.getOrDefault(level, emptySet()); + return level.getName() + "[" + itemsToUpdate.size() + "]"; + }).collect(joining(" "))); + } } catch (SQLException e) { this.log.error("Unable to execute WriteWorker task: " + e.getMessage()); } - }; + } /** * Called on {@link Edge.Events#ON_SET_LAST_MESSAGE_TIMESTAMP} event. @@ -123,12 +152,10 @@ public void onLastMessage(MyEdge edge) { * @param isOnline true if online, false if offline */ public void onSetOnline(MyEdge edge, boolean isOnline) { - var odooId = edge.getOdooId(); - if (isOnline) { - this.isOnlineOdooIds.add(odooId); - } else { - this.isOfflineOdooIds.add(odooId); - } + final var odooId = edge.getOdooId(); + this.connectionStatesToUpdate.lockReading(t -> { + t.put(odooId, isOnline); + }); } /** @@ -138,21 +165,10 @@ public void onSetOnline(MyEdge edge, boolean isOnline) { * @param sumState Sum-State {@link Level} */ public void onSetSumState(MyEdge edge, Level sumState) { - var odooId = edge.getOdooId(); - switch (sumState) { - case OK: - this.sumStateOk.add(odooId); - break; - case INFO: - this.sumStateInfo.add(odooId); - break; - case WARNING: - this.sumStateWarning.add(odooId); - break; - case FAULT: - this.sumStateFault.add(odooId); - break; - } + final var odooId = edge.getOdooId(); + this.sumStatesToUpdate.lockReading(t -> { + t.put(odooId, sumState); + }); } /** @@ -182,4 +198,36 @@ private synchronized void debugLog() { } this.lastExecute = now; } + + private static class ExchangableObject { + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private volatile T currentObject; + + public ExchangableObject(T currentObject) { + super(); + this.currentObject = currentObject; + } + + public T exchange(T newObject) { + this.lock.writeLock().lock(); + try { + final var prev = this.currentObject; + this.currentObject = newObject; + return prev; + } finally { + this.lock.writeLock().unlock(); + } + } + + public void lockReading(Consumer block) { + this.lock.readLock().lock(); + try { + block.accept(this.currentObject); + } finally { + this.lock.readLock().unlock(); + } + } + + } + } diff --git a/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java b/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java index f7d8fc2813d..4a85a09cf1e 100644 --- a/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java +++ b/io.openems.backend.timedata.aggregatedinflux/src/io/openems/backend/timedata/aggregatedinflux/AllowedChannels.java @@ -46,12 +46,13 @@ private AllowedChannels() { .putAll(multiChannels("ess", 0, 17, "ReactivePower", DataType.LONG)) // .put("ctrlIoHeatingElement0/Level", DataType.LONG) // .put("ctrlGridOptimizedCharge0/DelayChargeMaximumChargeLimit", DataType.LONG) // - .putAll(multiChannels("charger", 0, 10, "ActualPower", DataType.LONG)) // + .putAll(multiChannels("charger", 0, 20, "ActualPower", DataType.LONG)) // .put("ctrlEmergencyCapacityReserve0/ActualReserveSoc", DataType.LONG) // .put("ctrlGridOptimizedCharge0/_PropertyMaximumSellToGridPower", DataType.LONG) // .putAll(multiChannels("meter", 0, 10, "ActivePower", DataType.LONG)) // .putAll(multiChannels("meter", 0, 10, "ActivePowerL", 1, 4, DataType.LONG)) // .putAll(multiChannels("pvInverter", 0, 10, "ActivePower", DataType.LONG)) // + .putAll(multiChannels("pvInverter", 0, 10, "ActivePowerL", 1, 4, DataType.LONG)) // .put("_sum/EssDischargePower", DataType.LONG) // used for xlsx export .put("ctrlGridOptimizedCharge0/SellToGridLimitMinimumChargeLimit", DataType.LONG) // .put("ctrlEssTimeOfUseTariff0/QuarterlyPrices", DataType.DOUBLE) // @@ -87,10 +88,13 @@ private AllowedChannels() { .put("ctrlEssTimeOfUseTariff0/ChargedTime", DataType.LONG) // .putAll(multiChannels("evcs", 0, 10, "ActiveConsumptionEnergy", DataType.LONG)) // .putAll(multiChannels("meter", 0, 10, "ActiveProductionEnergy", DataType.LONG)) // + .putAll(multiChannels("meter", 0, 10, "ActiveProductionEnergyL", 1, 4, DataType.LONG)) // .putAll(multiChannels("meter", 0, 10, "ActiveConsumptionEnergy", DataType.LONG)) // + .putAll(multiChannels("meter", 0, 10, "ActiveConsumptionEnergyL", 1, 4, DataType.LONG)) // .putAll(multiChannels("io", 0, 10, "ActiveProductionEnergy", DataType.LONG)) // .putAll(multiChannels("pvInverter", 0, 10, "ActiveProductionEnergy", DataType.LONG)) // - .putAll(multiChannels("charger", 0, 10, "ActualEnergy", DataType.LONG)) // + .putAll(multiChannels("pvInverter", 0, 10, "ActiveProductionEnergyL", 1, 4, DataType.LONG)) // + .putAll(multiChannels("charger", 0, 20, "ActualEnergy", DataType.LONG)) // .put("ctrlGridOptimizedCharge0/AvoidLowChargingTime", DataType.LONG) // .put("ctrlGridOptimizedCharge0/NoLimitationTime", DataType.LONG) // .put("ctrlGridOptimizedCharge0/SellToGridLimitTime", DataType.LONG) // @@ -170,16 +174,18 @@ public static boolean addWithSpecificChannelType(Point builder, String field, Js if (type == null) { return false; } - final var number = value.getAsNumber(); + + var number = value.getAsNumber(); + + if (number.getClass().getName().equals("com.google.gson.internal.LazilyParsedNumber")) { + number = number.doubleValue(); + } + switch (type) { - case DOUBLE: - builder.addField(field, number.doubleValue()); - return true; - case LONG: - builder.addField(field, number.longValue()); - return true; + case DOUBLE -> builder.addField(field, number.doubleValue()); + case LONG -> builder.addField(field, number.longValue()); } - return false; + return true; } protected static enum DataType { diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java new file mode 100644 index 00000000000..3bdeef18022 --- /dev/null +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/ChannelFilter.java @@ -0,0 +1,96 @@ +package io.openems.backend.timedata.influx; + +import static java.util.stream.Collectors.toUnmodifiableSet; + +import java.util.Arrays; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +public class ChannelFilter { + + private static final Predicate SUNSPEC_PATTERN = // + Pattern.compile("^S[0-9]+[A-Z][a-zA-Z0-9]*$").asPredicate(); + + /** + * Pattern for Component-IDs. + * + *

    + * Either: + * + *

    + * + *

    + * Or: + *

      + *
    • starts with underscore (by convention for singleton Components) + *
    • continues with lower case letter + *
    • contains only ASCII letters and numbers + *
    • ends with a letter + *
    + */ + // TODO move to io.openems.common and validate pattern on Edge + private static final Predicate COMPONENT_ID_PATTERN = // + Pattern.compile("^([a-z][a-zA-Z0-9]+[0-9]+|_[a-z][a-zA-Z0-9]+[a-zA-Z])$").asPredicate(); + + /** + * Creates a new {@link ChannelFilter} from the provided arguments. + * + * @param blacklistedChannels a array of the blacklisted channels + * @return the created {@link ChannelFilter} + */ + public static ChannelFilter from(String[] blacklistedChannels) { + return new ChannelFilter(Arrays.stream(blacklistedChannels) // + .collect(toUnmodifiableSet())); + } + + private final Set blacklistedChannels; + + private ChannelFilter(Set blacklistedChannels) { + super(); + this.blacklistedChannels = blacklistedChannels; + } + + /** + * Checks if the provided channel is valid or not. + * + * @param channelAddress the channel to check with the format + * "component0/Channel" + * @return true if the channel is valid; else false + */ + public boolean isValid(String channelAddress) { + if (channelAddress == null) { + return false; + } + + if (this.blacklistedChannels.contains(channelAddress)) { + return false; + } + + final var c = channelAddress.split("/"); + if (c.length != 2) { + return false; + } + + // Valid Component-ID + final var componentId = c[0]; + if (!COMPONENT_ID_PATTERN.test(componentId)) { + return false; + } + + // Valid Channel-ID + final var channelId = c[1]; + if (SUNSPEC_PATTERN.test(channelId)) { + // SunSpec Channels + return false; + } + + return true; + } + + +} diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Config.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Config.java index 5bcef3e9e7e..ac7bd5783b1 100644 --- a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Config.java +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Config.java @@ -46,6 +46,9 @@ @AttributeDefinition(name = "Number of max scheduled tasks", description = "Max-Size of Queued tasks.") int maxQueueSize() default 5000; + @AttributeDefinition(name = "List of blacklisted channels", description = "Blacklisted channels which are not saved by this influx. e.g. \"kacoCore0/Serialnumber\"") + String[] blacklistedChannels() default {}; + String webconsole_configurationFactory_nameHint() default "Timedata InfluxDB"; } diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/FieldTypeConflictHandler.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/FieldTypeConflictHandler.java index 39bd1b07e67..8bb057dfaf9 100644 --- a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/FieldTypeConflictHandler.java +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/FieldTypeConflictHandler.java @@ -7,10 +7,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.primitives.Doubles; +import com.google.common.primitives.Longs; import com.google.gson.JsonElement; import com.influxdb.client.write.Point; import com.influxdb.exceptions.InfluxException; +import io.openems.common.utils.JsonUtils; + /** * Handles Influx FieldTypeConflictExceptions. This helper provides conversion * functions to provide the correct field types for InfluxDB. @@ -54,18 +58,13 @@ protected synchronized boolean handleExceptionMessage(String message) return false; } - var handler = this.createAndAddHandler(field, requiredType); + this.specialCaseFieldHandlers.computeIfAbsent(field, t -> this.createHandler(t, requiredType)); - if (handler == null) { - this.parent.logWarn(this.log, "Unable to add special field handler for [" + field + "] from [" + thisType - + "] to [" + requiredType.name().toLowerCase() + "]"); - } this.parent.logInfo(this.log, "Add handler for [" + field + "] from [" + thisType + "] to [" + requiredType.name().toLowerCase() + "]\n" // + "Add predefined FieldTypeConflictHandler: this.createAndAddHandler(\"" + field + "\", RequiredType." + requiredType.name() + ");"); - ; return true; } @@ -74,15 +73,6 @@ private static enum RequiredType { STRING, INTEGER, FLOAT; } - private BiConsumer createAndAddHandler(String field, RequiredType requiredType) - throws IllegalStateException { - var handler = this.createHandler(field, requiredType); - if (this.specialCaseFieldHandlers.put(field, handler) != null) { - throw new IllegalStateException("Handler for field [" + field + "] was already existing"); - } - return handler; - } - /** * Creates a Handler for the given field, to convert a Point to a * 'requiredType'. @@ -91,51 +81,35 @@ private BiConsumer createAndAddHandler(String field, Require * @param requiredType the {@link RequiredType} * @return the Handler */ - private BiConsumer createHandler(String field, RequiredType requiredType) { - switch (requiredType) { - case STRING: - return (builder, jValue) -> { - var value = getAsFieldTypeString(jValue); - if (value != null) { - builder.addField(field, value); - } - }; - - case INTEGER: - return (builder, jValue) -> { - try { - var value = getAsFieldTypeNumber(jValue); - if (value != null) { - builder.addField(field, value); - } - } catch (NumberFormatException e1) { - try { - // Failed -> try conversion to float and then to int - var value = getAsFieldTypeFloat(jValue); - if (value != null) { - builder.addField(field, Math.round(value)); - } - } catch (NumberFormatException e2) { - this.parent.logWarn(this.log, "Unable to convert field [" + field + "] value [" + jValue - + "] to integer: " + e2.getMessage()); - } - } - }; - - case FLOAT: - return (builder, jValue) -> { - try { - var value = getAsFieldTypeFloat(jValue); - if (value != null) { - builder.addField(field, value); - } - } catch (NumberFormatException e1) { - this.parent.logInfo(this.log, "Unable to convert field [" + field + "] value [" + jValue - + "] to float: " + e1.getMessage()); - } - }; - } - return null; // can never happen + protected BiConsumer createHandler(String field, RequiredType requiredType) { + return switch (requiredType) { + case STRING -> (builder, jValue) -> { + var value = getAsFieldTypeString(jValue); + if (value != null) { + builder.addField(field, value); + } + }; + + case INTEGER -> (builder, jValue) -> { + final var value = getAsFieldTypeLong(jValue); + if (value == null) { + this.parent.logWarn(this.log, + "Unable to convert field [" + field + "] value [" + jValue + "] to integer"); + return; + } + builder.addField(field, value); + }; + + case FLOAT -> (builder, jValue) -> { + final var value = getAsFieldTypeDouble(jValue); + if (value == null) { + this.parent.logWarn(this.log, + "Unable to convert field [" + field + "] value [" + jValue + "] to float"); + return; + } + builder.addField(field, value); + }; + }; } /** @@ -144,7 +118,7 @@ private BiConsumer createHandler(String field, RequiredType * @param jValue the value * @return the value as String; null if value represents null */ - private static String getAsFieldTypeString(JsonElement jValue) { + protected static String getAsFieldTypeString(JsonElement jValue) { if (jValue.isJsonNull()) { return null; } @@ -152,49 +126,80 @@ private static String getAsFieldTypeString(JsonElement jValue) { } /** - * Convert JsonElement to Number. + * Convert JsonElement to Long. * * @param jValue the value - * @return the value as Number; null if value represents null - * @throws NumberFormatException on error + * @return the value as Long; null if value represents null */ - private static Number getAsFieldTypeNumber(JsonElement jValue) throws NumberFormatException { - if (jValue.isJsonNull()) { + protected static Long getAsFieldTypeLong(JsonElement jValue) { + if (!jValue.isJsonPrimitive()) { return null; } - var value = jValue.toString().replace("\"", ""); - if (value.isEmpty()) { - return null; + if (JsonUtils.isNumber(jValue)) { + return jValue.getAsNumber().longValue(); } - try { - return Long.parseLong(value); - } catch (NumberFormatException e1) { - if (value.equalsIgnoreCase("false")) { - return 0L; - } else if (value.equalsIgnoreCase("true")) { - return 1L; - } else { - throw e1; - } + final var string = jValue.getAsString().replace("\"", ""); + + final var longValue = Longs.tryParse(string); + if (longValue != null) { + return longValue; + } + + final var doubleValue = Doubles.tryParse(string); + if (doubleValue != null) { + return doubleValue.longValue(); } + + final var bool = tryParseToBooleanNumber(string); + if (bool != null) { + return bool.longValue(); + } + + return null; } /** - * Convert JsonElement to Float. + * Convert JsonElement to Double. * * @param jValue the value - * @return the value as Float; null if value represents null - * @throws NumberFormatException on error + * @return the value as Double; null if value represents null */ - private static Float getAsFieldTypeFloat(JsonElement jValue) throws NumberFormatException { - if (jValue.isJsonNull()) { + protected static Double getAsFieldTypeDouble(JsonElement jValue) { + if (!jValue.isJsonPrimitive()) { return null; } - var value = jValue.toString().replace("\"", ""); - if (value.isEmpty()) { + if (JsonUtils.isNumber(jValue)) { + return jValue.getAsNumber().doubleValue(); + } + final var string = jValue.getAsString().replace("\"", ""); + + final var doubleValue = Doubles.tryParse(string); + if (doubleValue != null) { + return doubleValue; + } + + final var bool = tryParseToBooleanNumber(string); + if (bool != null) { + return bool.doubleValue(); + } + + return null; + } + + private static Boolean tryParseBoolean(String value) { + return switch (value) { + case "true" -> true; + case "false" -> false; + default -> null; + }; + } + + private static Integer tryParseToBooleanNumber(String value) { + final var bool = tryParseBoolean(value); + if (bool == null) { return null; } - return Float.parseFloat(value); + return bool ? 1 : 0; } /** diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/TimedataInfluxDb.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/TimedataInfluxDb.java index 678ef6f3b6c..d3c957f38dc 100644 --- a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/TimedataInfluxDb.java +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/TimedataInfluxDb.java @@ -7,8 +7,6 @@ import java.util.Set; import java.util.SortedMap; import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.regex.Pattern; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -24,6 +22,8 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import com.google.common.primitives.Doubles; +import com.google.common.primitives.Longs; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.influxdb.client.domain.WritePrecision; @@ -44,7 +44,6 @@ import io.openems.common.oem.OpenemsBackendOem; import io.openems.common.timedata.Resolution; import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.StringUtils; import io.openems.shared.influxdb.InfluxConnector; @Designate(ocd = Config.class, factory = true) @@ -70,6 +69,7 @@ public class TimedataInfluxDb extends AbstractOpenemsBackendComponent implements private Config config; private InfluxConnector influxConnector = null; private TimeFilter timeFilter; + private ChannelFilter channelFilter; // edgeId, channelIds which are timestamped channels private final Multimap timestampedChannelsForEdge = HashMultimap.create(); @@ -83,6 +83,7 @@ public TimedataInfluxDb() { private void activate(Config config) throws OpenemsException, IllegalArgumentException { this.config = config; this.timeFilter = TimeFilter.from(config.startDate(), config.endDate()); + this.channelFilter = ChannelFilter.from(config.blacklistedChannels()); this.logInfo(this.log, "Activate [" // + "url=" + config.url() + ";"// @@ -223,6 +224,9 @@ private void writeData(// if (!shouldWriteValue.apply(influxEdgeId, channelEntry.getKey())) { continue; } + if (!this.channelFilter.isValid(channelEntry.getKey())) { + continue; + } this.addValue(// point, // channelEntry.getKey(), // @@ -284,69 +288,75 @@ public SortedMap> queryHis */ private void addValue(Point builder, String field, JsonElement element) { if (element == null || element.isJsonNull() // - || !isAllowed(field) // Channel-Address is not allowed/blacklisted - // already handled by special case handling - || this.specialCaseFieldHandling(builder, field, element)) { + || this.specialCaseFieldHandling(builder, field, element)) { // already handled by special case handling return; } - if (element.isJsonPrimitive()) { - var p = (JsonPrimitive) element; - if (p.isNumber()) { - // Numbers can be directly converted - var n = p.getAsNumber(); - if (n.getClass().getName().equals("com.google.gson.internal.LazilyParsedNumber")) { - // Avoid 'discouraged access' - // LazilyParsedNumber stores value internally as String - if (StringUtils.matchesFloatPattern(n.toString())) { - builder.addField(field, n.doubleValue()); - return; - } - builder.addField(field, n.longValue()); - return; + if (!element.isJsonPrimitive()) { + // Non-Primitives are ignored + this.logWarn(this.log, "Ignoring non-primitive Field [" + field + "] Value [" + element + "]"); + return; + } - } else if (n instanceof Integer || n instanceof Long || n instanceof Short || n instanceof Byte) { - builder.addField(field, n.longValue()); + final var p = (JsonPrimitive) element; + if (p.isNumber()) { + // Numbers can be directly converted + final var n = p.getAsNumber(); + if (n.getClass().getName().equals("com.google.gson.internal.LazilyParsedNumber")) { + // Avoid 'discouraged access' + // LazilyParsedNumber stores value internally as String + final var s = n.toString(); + + final var longValue = Longs.tryParse(s); + if (longValue != null) { + builder.addField(field, longValue); return; + } + final var doubleValue = Doubles.tryParse(s); + if (doubleValue != null) { + builder.addField(field, doubleValue); + return; } - builder.addField(field, n.doubleValue()); - return; - } else if (p.isBoolean()) { - // Booleans are converted to integer (0/1) - builder.addField(field, p.getAsBoolean()); + // unable to parse lazy number return; + } - } else if (p.isString()) { - // Strings are parsed if they start with a number or minus - var s = p.getAsString(); - if (StringUtils.matchesFloatPattern(s)) { - try { - builder.addField(field, Double.parseDouble(s)); // try parsing to Double - return; - } catch (NumberFormatException e) { - builder.addField(field, s); - return; - } - - } else if (StringUtils.matchesIntegerPattern(s)) { - try { - builder.addField(field, Long.parseLong(s)); // try parsing to Long - return; - } catch (NumberFormatException e) { - builder.addField(field, s); - return; - } - } - builder.addField(field, s); + if (n instanceof Integer || n instanceof Long || n instanceof Short || n instanceof Byte) { + builder.addField(field, n.longValue()); return; } - } else { - builder.addField(field, element.toString()); + builder.addField(field, n.doubleValue()); return; } + + if (p.isBoolean()) { + // Booleans are converted to integer (0/1) + builder.addField(field, p.getAsBoolean()); + return; + } + + if (p.isString()) { + // Strings are parsed if they start with a number or minus + final var s = p.getAsString(); + + // try to save string value as numbers + final var longValue = Longs.tryParse(s); + if (longValue != null) { + builder.addField(field, longValue); + return; + } + + final var doubleValue = Doubles.tryParse(s); + if (doubleValue != null) { + builder.addField(field, doubleValue); + return; + } + + // string not can not be parsed to any number => currently not saved + } } /** @@ -367,8 +377,13 @@ private boolean specialCaseFieldHandling(Point builder, String field, JsonElemen // no special handling exists for this field return false; } - // call special handler - handler.accept(builder, value); + try { + // call special handler + handler.accept(builder, value); + } catch (RuntimeException e) { + this.logError(this.log, + "Unexpected error in special case field handler for Field [" + field + "] Value [" + value + "]"); + } return true; } @@ -387,60 +402,6 @@ public String id() { return this.config.id(); } - private static final Predicate SUNSPEC_PATTERN = // - Pattern.compile("^S[0-9]+[A-Z][a-zA-Z0-9]*$").asPredicate(); - - /** - * Pattern for Component-IDs. - * - *

    - * Either: - * - *

      - *
    • starts with lower case letter - *
    • contains only ASCII letters and numbers - *
    • ends with a number - *
    - * - *

    - * Or: - *

      - *
    • starts with underscore (by convention for singleton Components) - *
    • continues with lower case letter - *
    • contains only ASCII letters and numbers - *
    • ends with a letter - *
    - */ - // TODO move to io.openems.common and validate pattern on Edge - private static final Predicate COMPONENT_ID_PATTERN = // - Pattern.compile("^([a-z][a-zA-Z0-9]+[0-9]+|_[a-z][a-zA-Z0-9]+[a-zA-Z])$").asPredicate(); - - protected static boolean isAllowed(String channelAddress) { - if (channelAddress == null) { - return false; - } - - var c = channelAddress.split("/"); - if (c.length != 2) { - return false; - } - - // Valid Component-ID - var componentId = c[0]; - if (!COMPONENT_ID_PATTERN.test(componentId)) { - return false; - } - - // Valid Channel-ID - var channelId = c[1]; - if (SUNSPEC_PATTERN.test(channelId)) { - // SunSpec Channels - return false; - } - - return true; - } - @Override public String debugLog() { return "[" + this.getName() + "] " + this.config.id() + " " + this.influxConnector.debugLog(); diff --git a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java new file mode 100644 index 00000000000..0f473a6d56d --- /dev/null +++ b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/ChannelFilterTest.java @@ -0,0 +1,52 @@ +package io.openems.backend.timedata.influx; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class ChannelFilterTest { + + @Test + public void testFromDuplicatedChannel() { + final var filter = ChannelFilter.from(new String[] { // + "component0/Channel", // + "component0/Channel", // + }); + + assertNotNull(filter); + } + + @Test + public void testIsValid() { + final var filter = ChannelFilter.from(new String[] { // + "component0/Channel", // + }); + + assertFalse(filter.isValid("component0/Channel")); + assertTrue(filter.isValid("component0/SomeOtherChannel")); + + assertFalse(filter.isValid(null)); + assertFalse(filter.isValid("invalid")); + assertFalse(filter.isValid("in/va/lid")); + + // Channel-ID + assertTrue(filter.isValid("ess0/ActivePower")); + assertTrue(filter.isValid("_sum/EssActivePower")); + assertTrue(filter.isValid("_cycle/MeasuredCycleTime")); + + assertFalse(filter.isValid("ess/ActivePower")); + assertFalse(filter.isValid("Ess1/ActivePower")); + assertFalse(filter.isValid("cycle/MeasuredCycleTime")); + assertFalse(filter.isValid("_cycle1/MeasuredCycleTime")); + assertFalse(filter.isValid("My Heat-Pump/Status")); + assertFalse(filter.isValid("äöü/Status")); + assertFalse(filter.isValid("äöü0/Status")); + + // SunSpec + assertFalse(filter.isValid("pvInverter0/S1Evt")); + assertFalse(filter.isValid("pvInverter0/S111A")); + } + +} diff --git a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/FieldTypeConflictHandlerTest.java b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/FieldTypeConflictHandlerTest.java index 82ed6467f87..32cde5dfa15 100644 --- a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/FieldTypeConflictHandlerTest.java +++ b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/FieldTypeConflictHandlerTest.java @@ -1,9 +1,15 @@ package io.openems.backend.timedata.influx; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.Test; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + public class FieldTypeConflictHandlerTest { @Test @@ -16,4 +22,49 @@ public void testHandleExceptionMessage() { already exists as type float dropped=2""")); } + @Test + public void testGetAsFieldTypeString() throws Exception { + assertEquals("123", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive(123))); + assertEquals("123", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("123"))); + assertEquals("123.5", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive(123.5))); + assertEquals("123.5", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("123.5"))); + assertEquals("string", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("string"))); + assertEquals("{}", FieldTypeConflictHandler.getAsFieldTypeString(new JsonObject())); + assertNull(FieldTypeConflictHandler.getAsFieldTypeString(JsonNull.INSTANCE)); + assertEquals("true", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive(true))); + assertEquals("true", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("true"))); + assertEquals("false", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive(false))); + assertEquals("false", FieldTypeConflictHandler.getAsFieldTypeString(new JsonPrimitive("false"))); + } + + @Test + public void testGetAsFieldTypeLong() throws Exception { + assertEquals((Long) 123L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive(123))); + assertEquals((Long) 123L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("123"))); + assertEquals((Long) 123L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive(123.5))); + assertEquals((Long) 123L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("123.5"))); + assertNull(FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("string"))); + assertNull(FieldTypeConflictHandler.getAsFieldTypeLong(new JsonObject())); + assertNull(FieldTypeConflictHandler.getAsFieldTypeLong(JsonNull.INSTANCE)); + assertEquals((Long) 1L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive(true))); + assertEquals((Long) 1L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("true"))); + assertEquals((Long) 0L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive(false))); + assertEquals((Long) 0L, FieldTypeConflictHandler.getAsFieldTypeLong(new JsonPrimitive("false"))); + } + + @Test + public void testGetAsFieldTypeDouble() throws Exception { + assertEquals((Double) 123D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive(123))); + assertEquals((Double) 123D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("123"))); + assertEquals((Double) 123.5, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive(123.5))); + assertEquals((Double) 123.5, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("123.5"))); + assertNull(FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("string"))); + assertNull(FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonObject())); + assertNull(FieldTypeConflictHandler.getAsFieldTypeDouble(JsonNull.INSTANCE)); + assertEquals((Double) 1D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive(true))); + assertEquals((Double) 1D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("true"))); + assertEquals((Double) 0D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive(false))); + assertEquals((Double) 0D, FieldTypeConflictHandler.getAsFieldTypeDouble(new JsonPrimitive("false"))); + } + } diff --git a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/TimedataInfluxDbTest.java b/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/TimedataInfluxDbTest.java deleted file mode 100644 index 707f19f9340..00000000000 --- a/io.openems.backend.timedata.influx/test/io/openems/backend/timedata/influx/TimedataInfluxDbTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.openems.backend.timedata.influx; - -import static io.openems.backend.timedata.influx.TimedataInfluxDb.isAllowed; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -public class TimedataInfluxDbTest { - - @Test - public void testIsAllowed() { - assertFalse(isAllowed(null)); - assertFalse(isAllowed("invalid")); - assertFalse(isAllowed("in/va/lid")); - - // Channel-ID - assertTrue(isAllowed("ess0/ActivePower")); - assertTrue(isAllowed("_sum/EssActivePower")); - assertTrue(isAllowed("_cycle/MeasuredCycleTime")); - - assertFalse(isAllowed("ess/ActivePower")); - assertFalse(isAllowed("Ess1/ActivePower")); - assertFalse(isAllowed("cycle/MeasuredCycleTime")); - assertFalse(isAllowed("_cycle1/MeasuredCycleTime")); - assertFalse(isAllowed("My Heat-Pump/Status")); - assertFalse(isAllowed("äöü/Status")); - - // SunSpec - assertFalse(isAllowed("pvInverter0/S1Evt")); - assertFalse(isAllowed("pvInverter0/S111A")); - } - -} diff --git a/io.openems.backend.timedata.timescaledb/src/io/openems/backend/timedata/timescaledb/internal/Type.java b/io.openems.backend.timedata.timescaledb/src/io/openems/backend/timedata/timescaledb/internal/Type.java index 925d52ad8b4..d9cd35eccf9 100644 --- a/io.openems.backend.timedata.timescaledb/src/io/openems/backend/timedata/timescaledb/internal/Type.java +++ b/io.openems.backend.timedata.timescaledb/src/io/openems/backend/timedata/timescaledb/internal/Type.java @@ -6,6 +6,8 @@ import java.util.Map; import java.util.function.Consumer; +import com.google.common.primitives.Doubles; +import com.google.common.primitives.Longs; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonPrimitive; @@ -17,7 +19,6 @@ import io.openems.common.function.ThrowingBiFunction; import io.openems.common.types.OpenemsType; import io.openems.common.utils.JsonUtils; -import io.openems.common.utils.StringUtils; public enum Type { INTEGER(1, "data_integer", "bigint" /* 8 bytes; covers Java byte, int and long */, // @@ -151,7 +152,8 @@ public static Type detect(JsonElement value) { if (n.getClass().getName().equals("com.google.gson.internal.LazilyParsedNumber")) { // Avoid 'discouraged access' // LazilyParsedNumber stores value internally as String - if (StringUtils.matchesFloatPattern(n.toString())) { + final var doubleValue = Doubles.tryParse(n.toString()); + if (doubleValue != null) { return Type.FLOAT; } return Type.INTEGER; @@ -168,24 +170,18 @@ public static Type detect(JsonElement value) { } else if (p.isString()) { // Strings are parsed if they start with a number or minus - var s = p.getAsString(); - if (StringUtils.matchesFloatPattern(s)) { - try { - Double.parseDouble(s); // try parsing to Double - return Type.FLOAT; - } catch (NumberFormatException e) { - return Type.STRING; - } + final var s = p.getAsString(); - } else if (StringUtils.matchesIntegerPattern(s)) { - try { - Long.parseLong(s); // try parsing to Long - return Type.INTEGER; - } catch (NumberFormatException e) { - return Type.STRING; - } + // try to save string value as numbers + final var longValue = Longs.tryParse(s); + if (longValue != null) { + return Type.INTEGER; + } + + final var doubleValue = Doubles.tryParse(s); + if (doubleValue != null) { + return Type.FLOAT; } - return Type.STRING; } } // TODO parse JsonObject and JsonArray diff --git a/io.openems.backend.timedata.timescaledb/test/io/openems/backend/timedata/timescaledb/internal/TypeTest.java b/io.openems.backend.timedata.timescaledb/test/io/openems/backend/timedata/timescaledb/internal/TypeTest.java index 88815512917..db6f7eadd90 100644 --- a/io.openems.backend.timedata.timescaledb/test/io/openems/backend/timedata/timescaledb/internal/TypeTest.java +++ b/io.openems.backend.timedata.timescaledb/test/io/openems/backend/timedata/timescaledb/internal/TypeTest.java @@ -20,7 +20,7 @@ public void testDetect() throws OpenemsNamedException { assertEquals((Long) 101180500005L, JsonUtils.getAsType(OpenemsType.LONG, j)); } { - var j = new JsonPrimitive("519100001009210611000019"); + var j = new JsonPrimitive("X519100001009210611000019"); assertEquals(Type.STRING, Type.detect(j)); assertEquals(j.getAsString(), JsonUtils.getAsType(OpenemsType.STRING, j)); } diff --git a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java index f30098586d3..9883cf030ac 100644 --- a/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java +++ b/io.openems.backend.uiwebsocket/src/io/openems/backend/uiwebsocket/impl/OnRequest.java @@ -1,15 +1,13 @@ package io.openems.backend.uiwebsocket.impl; -import static java.util.Collections.emptyMap; - import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import org.java_websocket.WebSocket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import io.openems.backend.common.alerting.UserAlertingSettings; import io.openems.backend.common.jsonrpc.request.AddEdgeToUserRequest; @@ -26,7 +24,6 @@ import io.openems.backend.common.jsonrpc.response.AddEdgeToUserResponse; import io.openems.backend.common.jsonrpc.response.GetUserAlertingConfigsResponse; import io.openems.backend.common.jsonrpc.response.GetUserInformationResponse; -import io.openems.backend.common.metadata.Metadata.GenericSystemLog; import io.openems.backend.common.metadata.User; import io.openems.common.exceptions.OpenemsError; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; @@ -36,7 +33,6 @@ import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.AuthenticateWithPasswordRequest; import io.openems.common.jsonrpc.request.AuthenticateWithTokenRequest; -import io.openems.common.jsonrpc.request.ComponentJsonApiRequest; import io.openems.common.jsonrpc.request.EdgeRpcRequest; import io.openems.common.jsonrpc.request.GetEdgeRequest; import io.openems.common.jsonrpc.request.GetEdgesRequest; @@ -55,6 +51,8 @@ public class OnRequest implements io.openems.common.websocket.OnRequest { + private final Logger log = LoggerFactory.getLogger(OnRequest.class); + private final UiWebsocketImpl parent; public OnRequest(UiWebsocketImpl parent) { @@ -218,6 +216,12 @@ private CompletableFuture handleEdgeRpcRequest(WsData wsData, U EdgeRpcRequest edgeRpcRequest) throws OpenemsNamedException { var edgeId = edgeRpcRequest.getEdgeId(); var request = edgeRpcRequest.getPayload(); + + // TODO still not the best to check the access => should be separate service + if (user.getRole(edgeId).isEmpty()) { + this.parent.metadata.getEdgeMetadataForUser(user, edgeId); + this.parent.logInfo(this.log, "Role was not defined for user=" + user.getId() + ", edge=" + edgeId); + } user.assertEdgeRoleIsAtLeast(EdgeRpcRequest.METHOD, edgeId, Role.GUEST); CompletableFuture resultFuture = switch (request.getMethod()) { @@ -227,37 +231,6 @@ private CompletableFuture handleEdgeRpcRequest(WsData wsData, U this.handleSubscribeSystemLogRequest(wsData, edgeId, user, SubscribeSystemLogRequest.from(request)); case SimulationRequest.METHOD -> this.handleSimulationRequest(edgeId, user, SimulationRequest.from(request)); - case ComponentJsonApiRequest.METHOD -> { - final var componentRequest = ComponentJsonApiRequest.from(request); - if (!"_host".equals(componentRequest.getComponentId())) { - yield null; - } - switch (componentRequest.getPayload().getMethod()) { - case "executeSystemCommand" -> { - final var executeSystemCommandRequest = componentRequest.getPayload(); - final var p = executeSystemCommandRequest.getParams(); - this.parent.metadata.logGenericSystemLog(new LogSystemExecuteCommend(edgeId, user, // - JsonUtils.getAsString(p, "command"), // - JsonUtils.getAsOptionalBoolean(p, "sudo").orElse(null), // - JsonUtils.getAsOptionalString(p, "username").orElse(null), // - JsonUtils.getAsOptionalString(p, "password").orElse(null), // - JsonUtils.getAsOptionalBoolean(p, "runInBackground").orElse(null) // - )); - } - case "executeSystemUpdate" -> { - this.parent.metadata.logGenericSystemLog(new LogUpdateSystem(edgeId, user)); - } - case "executeSystemRestart" -> { - final var executeSystemCommandRequest = componentRequest.getPayload(); - final var p = executeSystemCommandRequest.getParams(); - this.parent.metadata.logGenericSystemLog(new LogRestartSystem(edgeId, user, // - JsonUtils.getAsOptionalString(p, "type").orElse(null) // - )); - } - } - - yield null; - } default -> { // unable to handle; try generic handler yield null; @@ -303,74 +276,6 @@ private CompletableFuture handleSimulationRequest(String return simulation.handleRequest(edgeId, user, request); } - private record LogSystemExecuteCommend(// - String edgeId, // non-null - User user, // non-null - String command, // non-null - Boolean sudo, // null-able - String username, // null-able - String password, // null-able - Boolean runInBackground // null-able - ) implements GenericSystemLog { - - @Override - public String teaser() { - return "Systemcommand: " + this.command; - } - - @Override - public Map getValues() { - return Map.of(// - "Sudo", Boolean.toString(Optional.ofNullable(this.sudo()).orElse(false)), // - "Command", this.command(), // - "Username", this.username(), // - "Password", this.password() == null || this.password().isEmpty() ? "[NOT_SET]" : "[SET]", // - "Run in Background", Boolean.toString(Optional.ofNullable(this.runInBackground()).orElse(false)) // - ); - } - - } - - private record LogUpdateSystem(// - String edgeId, // non-null - User user // non-null - ) implements GenericSystemLog { - - @Override - public String teaser() { - return "Systemupdate"; - } - - @Override - public Map getValues() { - return emptyMap(); - } - - } - - private record LogRestartSystem(// - String edgeId, // non-null - User user, // non-null - String type // null-able - ) implements GenericSystemLog { - - @Override - public String teaser() { - return "Systemrestart"; - } - - @Override - public Map getValues() { - if (this.type == null) { - return emptyMap(); - } - return Map.of(// - "type", this.type // - ); - } - - } - /** * Handles a {@link SubscribeChannelsRequest}. * diff --git a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java index 9a75699e20a..4b0aabf35b8 100644 --- a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java +++ b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java @@ -74,6 +74,7 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.Api.ModbusTcp.ReadWrite", "") // .put("App.Api.RestJson.ReadOnly", "") // .put("App.Api.RestJson.ReadWrite", "") // + .put("App.Timedata.InfluxDb", "")// .put("App.Evcs.HardyBarth", "") // .put("App.Evcs.Keba", "") // .put("App.Evcs.IesKeywatt", "") // @@ -92,6 +93,7 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.Meter.Socomec", "") // .put("App.Meter.CarloGavazzi", "") // .put("App.Meter.Janitza", "") // + .put("App.Meter.Discovergy", "")// .put("App.PvInverter.Fronius", "") // .put("App.PvInverter.Kaco", "") // .put("App.PvInverter.Kostal", "") // diff --git a/io.openems.common/src/io/openems/common/types/EdgeConfig.java b/io.openems.common/src/io/openems/common/types/EdgeConfig.java index 0c54d0334eb..1a7ad131b23 100644 --- a/io.openems.common/src/io/openems/common/types/EdgeConfig.java +++ b/io.openems.common/src/io/openems/common/types/EdgeConfig.java @@ -9,6 +9,7 @@ import java.util.SortedMap; import java.util.TreeMap; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.osgi.service.metatype.AttributeDefinition; import org.osgi.service.metatype.ObjectClassDefinition; @@ -1060,19 +1061,12 @@ public String[] getNatureIds() { * @return configuration as a JSON Object */ public JsonObject toJson() { - var natureIds = new JsonArray(); - for (String naturId : this.getNatureIds()) { - natureIds.add(naturId); - } - var properties = new JsonArray(); - for (Property property : this.getProperties()) { - properties.add(property.toJson()); - } return JsonUtils.buildJsonObject() // .addProperty("name", this.name) // .addProperty("description", this.description) // - .add("natureIds", natureIds) // - .add("properties", properties) // + .add("natureIds", Stream.of(this.getNatureIds()) // + .map(JsonPrimitive::new) // + .collect(JsonUtils.toJsonArray())) // .build(); } @@ -1431,6 +1425,10 @@ public JsonObject componentsToJson(JsonFormat jsonFormat) { public JsonObject factoriesToJson() { var b = JsonUtils.buildJsonObject(); for (Entry entry : this.getFactories().entrySet()) { + if (!this.getComponents().values().stream() // + .anyMatch(c -> c.factoryId.equals(entry.getKey()))) { + continue; + } b.add(entry.getKey(), entry.getValue().toJson()); } return b.build(); diff --git a/io.openems.common/src/io/openems/common/utils/StringUtils.java b/io.openems.common/src/io/openems/common/utils/StringUtils.java index 1402944d8d8..13bc4a34e1a 100644 --- a/io.openems.common/src/io/openems/common/utils/StringUtils.java +++ b/io.openems.common/src/io/openems/common/utils/StringUtils.java @@ -1,7 +1,6 @@ package io.openems.common.utils; import java.util.OptionalInt; -import java.util.function.Predicate; import java.util.regex.Pattern; import com.google.gson.JsonElement; @@ -90,36 +89,8 @@ public static int matchWildcard(String source, String pattern) { } } - private static final Predicate DETECT_INTEGER_PATTERN = // - Pattern.compile("^[-+]?[0-9]+$").asPredicate(); - - private static final Predicate DETECT_FLOAT_PATTERN = // - Pattern.compile("^[-+]?[0-9]*\\.[0-9]+$").asPredicate(); - private static final Pattern NAME_NUMBER_PATTERN = Pattern.compile("[^0-9]+([0-9]+)$"); - /** - * Checks if the given string matches an Integer pattern, i.e. if could be - * parsed to Integer/Long. - * - * @param string a string - * @return true if it matches Integer - */ - public static boolean matchesIntegerPattern(String string) { - return DETECT_INTEGER_PATTERN.test(string); - } - - /** - * Checks if the given string matches an Float pattern, i.e. if could be parsed - * to Float/Double. - * - * @param string a string - * @return true if it matches Float - */ - public static boolean matchesFloatPattern(String string) { - return DETECT_FLOAT_PATTERN.test(string); - } - /** * Causes this character sequence to be replaced by the reverse of the sequence. * diff --git a/io.openems.common/src/io/openems/common/utils/ThreadPoolUtils.java b/io.openems.common/src/io/openems/common/utils/ThreadPoolUtils.java index 1d875582b70..1167c401294 100644 --- a/io.openems.common/src/io/openems/common/utils/ThreadPoolUtils.java +++ b/io.openems.common/src/io/openems/common/utils/ThreadPoolUtils.java @@ -56,6 +56,10 @@ public static void shutdownAndAwaitTermination(ExecutorService pool, int timeout * @return a String */ public static String debugLog(ThreadPoolExecutor executor) { + if (executor == null) { + return "UNDEFINED"; + } + var activeCount = executor.getActiveCount(); var b = new StringBuilder() // .append("Pool: ").append(executor.getPoolSize()).append("/").append(executor.getMaximumPoolSize()) // @@ -75,7 +79,11 @@ public static String debugLog(ThreadPoolExecutor executor) { * @return a Map of key to value */ public static Map debugMetrics(ThreadPoolExecutor executor) { - return Map.of(// + if (executor == null) { + return Map.of(); + } + + return Map.of(// "PoolSize", Long.valueOf(executor.getPoolSize()), // "MaxPoolSize", Long.valueOf(executor.getMaximumPoolSize()), // "Active", Long.valueOf(executor.getActiveCount()), // diff --git a/io.openems.common/test/io/openems/common/jsonrpc/response/JsonrpcToXlsxApp.java b/io.openems.common/test/io/openems/common/jsonrpc/response/JsonrpcToXlsxApp.java new file mode 100644 index 00000000000..154dcbdf4b4 --- /dev/null +++ b/io.openems.common/test/io/openems/common/jsonrpc/response/JsonrpcToXlsxApp.java @@ -0,0 +1,63 @@ +package io.openems.common.jsonrpc.response; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZonedDateTime; + +import org.dhatim.fastexcel.Workbook; + +import com.google.gson.JsonParser; + +public class JsonrpcToXlsxApp { + + private static final String PATH = ""; + private static final String FILE_IN = "file.json"; + private static final String FILE_OUT = "file.xlsx"; + + /** + * Tool to convert from JSONRPC to XLSX. + * + * @param args arguments + * @throws IOException on error + */ + public static void main(String[] args) throws IOException { + var json = JsonParser.parseString(// + String.join("", // + Files.readAllLines(Path.of(PATH, FILE_IN)))) + .getAsJsonObject(); + if (json.has("result")) { + // handle full JSONRPC-Response and UI log output object + json = json.getAsJsonObject("result"); + } + var timestamps = json.getAsJsonArray("timestamps"); + var data = json.getAsJsonObject("data"); + + try (// + var os = new FileOutputStream(Path.of(PATH, FILE_OUT).toFile()); + var wb = new Workbook(os, "", null) // + ) { + var ws = wb.newWorksheet(FILE_IN); + var cols = data.keySet().toArray(String[]::new); + + // Header + ws.value(0, 0, "Timestamp"); + for (var i = 0; i < cols.length; i++) { + ws.value(0, i + 1, cols[i]); + } + + // Data + for (var i = 0; i < timestamps.size(); i++) { + var timestamp = ZonedDateTime.parse(timestamps.get(i).getAsString()); + ws.value(i + 1, 0, timestamp); + ws.style(i + 1, 0).format("yyyy-MM-dd H:mm:ss").set(); + for (var j = 0; j < cols.length; j++) { + var d = data.get(cols[j]).getAsJsonArray().get(i); + ws.value(i + 1, j + 1, d.isJsonNull() ? null : d.getAsNumber()); + } + } + } + } + +} diff --git a/io.openems.common/test/io/openems/common/jsonrpc/response/XlsxToJsonrpcApp.java b/io.openems.common/test/io/openems/common/jsonrpc/response/XlsxToJsonrpcApp.java new file mode 100644 index 00000000000..e7a34d5c98a --- /dev/null +++ b/io.openems.common/test/io/openems/common/jsonrpc/response/XlsxToJsonrpcApp.java @@ -0,0 +1,70 @@ +package io.openems.common.jsonrpc.response; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.dhatim.fastexcel.reader.Cell; +import org.dhatim.fastexcel.reader.ReadableWorkbook; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +public class XlsxToJsonrpcApp { + + private static final String PATH = ""; + private static final String FILE_IN = "file.xlsx"; + private static final String FILE_OUT = "file.json"; + + /** + * Tool to convert from XLSX to JSONRPC. + * + * @param args arguments + * @throws IOException on error + */ + public static void main(String[] args) throws IOException { + var timestamps = new JsonArray(); + var data = new JsonObject(); + + try (// + var is = new FileInputStream(Path.of(PATH, FILE_IN).toFile()); + var wb = new ReadableWorkbook(is) // + ) { + var ws = wb.getFirstSheet(); + var rows = ws.read(); + var cols = rows.get(0).stream() // + .skip(1) // + .map(Cell::asString) // + .toArray(String[]::new); + for (var col : cols) { + data.add(col, new JsonArray()); + } + for (var i = 1; i < rows.size(); i++) { + var row = rows.get(i); + timestamps.add(row.getCell(0).asDate().toString() + ":00Z"); + for (var j = 0; j < cols.length; j++) { + var cell = row.getCell(j + 1); + if (cell == null) { + continue; + } + data.get(cols[j]).getAsJsonArray()// + .add(cell.asNumber()); + } + } + + var result = new JsonObject(); + result.add("timestamps", timestamps); + result.add("data", data); + var json = new JsonObject(); + json.addProperty("jsonrpc", "2.0"); + json.addProperty("id", ""); + json.add("result", result); + + Files.writeString(Path.of(PATH, FILE_OUT), + new GsonBuilder().setPrettyPrinting().serializeNulls().create().toJson(json)); + } + } + +} diff --git a/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java b/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java index 2b5fa1ce8af..2203d0de5b8 100644 --- a/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java +++ b/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java @@ -50,11 +50,6 @@ public void testMatchWildcard() { assertEquals(-1, StringUtils.matchWildcard(activePower, foobar)); } - @Test - public void testMatchesFloatPattern() { - assertTrue(StringUtils.matchesFloatPattern("208.6")); - } - @Test public void testDefinedOrElse() { assertEquals("foo", definedOrElse("foo", "bar")); diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index f158c0a74bd..addfe0c17f4 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -196,6 +196,7 @@ bcpkix;version='[1.70.0,1.70.1)',\ bcprov;version='[1.70.0,1.70.1)',\ bcutil;version='[1.70.0,1.70.1)',\ + com.fasterxml.aalto-xml;version='[1.3.2,1.3.3)',\ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ com.google.gson;version='[2.11.0,2.11.1)',\ @@ -395,7 +396,9 @@ io.reactivex.rxjava3.rxjava;version='[3.1.8,3.1.9)',\ javax.jmdns;version='[3.4.1,3.4.2)',\ javax.xml.soap-api;version='[1.4.0,1.4.1)',\ + org.apache.commons.commons-compress;version='[1.26.1,1.26.2)',\ org.apache.commons.commons-csv;version='[1.10.0,1.10.1)',\ + org.apache.commons.commons-io;version='[2.15.1,2.15.2)',\ org.apache.commons.math3;version='[3.6.1,3.6.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ @@ -424,4 +427,5 @@ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ org.owasp.encoder;version='[1.2.3,1.2.4)',\ reactive-streams;version='[1.0.4,1.0.5)',\ - rrd4j;version='[3.9.0,3.9.1)' \ No newline at end of file + rrd4j;version='[3.9.0,3.9.1)',\ + stax2-api;version='[4.2.0,4.2.1)' \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java index 3ea9dc3bbdd..9f43d5aadcb 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/Point.java @@ -9,6 +9,7 @@ import io.openems.common.channel.AccessMode; import io.openems.common.channel.Level; +import io.openems.common.channel.PersistencePriority; import io.openems.common.channel.Unit; import io.openems.common.types.OpenemsType; import io.openems.common.types.OptionsEnum; @@ -34,6 +35,8 @@ */ public abstract sealed class Point { + private static final PersistencePriority DEFAULT_PERSISTENCE_PRIORITY = PersistencePriority.VERY_LOW; + /** * A Point that relates to a {@link ModbusElement}. */ @@ -69,7 +72,7 @@ public static sealed interface Type { public final boolean mandatory; public final AccessMode accessMode; - public Point(String name, String label, String description, Point.Type type, boolean mandatory, + protected Point(String name, String label, String description, Point.Type type, boolean mandatory, AccessMode accessMode) { this.name = name; this.description = description; @@ -110,6 +113,7 @@ private ChannelIdPoint(String name, String label, String description, Point.Type doc.text(description); } doc.accessMode(accessMode); + doc.persistencePriority(DEFAULT_PERSISTENCE_PRIORITY); this.channelId = new SunSChannelId<>(name, doc); } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/PointTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/PointTest.java new file mode 100644 index 00000000000..8e62fa932a5 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/PointTest.java @@ -0,0 +1,29 @@ +package io.openems.edge.bridge.modbus.sunspec; + +import static io.openems.common.channel.AccessMode.READ_ONLY; +import static io.openems.common.channel.ChannelCategory.OPENEMS_TYPE; +import static io.openems.common.channel.PersistencePriority.VERY_LOW; +import static io.openems.common.channel.Unit.AMPERE; +import static io.openems.common.types.OpenemsType.INTEGER; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.openems.edge.bridge.modbus.sunspec.Point.ChannelIdPoint; + +public class PointTest { + + @Test + public void testChannelIdPoint() { + var point = (ChannelIdPoint) DefaultSunSpecModel.S111.A.get(); + var channelId = point.channelId; + var doc = channelId.doc(); + assertEquals(READ_ONLY, doc.getAccessMode()); + assertEquals(OPENEMS_TYPE, doc.getChannelCategory()); + assertEquals(VERY_LOW, doc.getPersistencePriority()); + assertEquals("Amps. AC Current", doc.getText()); + assertEquals(INTEGER, doc.getType()); + assertEquals(AMPERE, doc.getUnit()); + } + +} diff --git a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java new file mode 100644 index 00000000000..854d4f90087 --- /dev/null +++ b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java @@ -0,0 +1,95 @@ +package io.openems.edge.controller.io.heatingelement; + +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.test.TimeLeapClock; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.sum.DummySum; +import io.openems.edge.common.sum.Sum; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.controller.io.heatingelement.enums.Level; +import io.openems.edge.controller.io.heatingelement.enums.Mode; +import io.openems.edge.controller.io.heatingelement.enums.WorkMode; +import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.io.test.DummyInputOutput; + +public class ControllerHeatingElementImplTest4 { + private static final String CTRL_ID = "ctrl0"; + private static final String IO_ID = "io0"; + + private static final ChannelAddress IO_OUTPUT1 = new ChannelAddress(IO_ID, "InputOutput1"); + private static final ChannelAddress IO_OUTPUT2 = new ChannelAddress(IO_ID, "InputOutput2"); + private static final ChannelAddress IO_OUTPUT3 = new ChannelAddress(IO_ID, "InputOutput3"); + private static final TimeLeapClock clock = new TimeLeapClock( + Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */, ZoneOffset.UTC); + + private static ControllerTest prepareTest(Mode mode, Level level) throws OpenemsNamedException, Exception { + return new ControllerTest(new ControllerIoHeatingElementImpl()) // + .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("sum", new DummySum()) // + .addComponent(new DummyInputOutput("io0")) // + .activate(MyConfig.create() // + .setId(CTRL_ID) // + .setOutputChannelPhaseL1(IO_OUTPUT1.toString()) // + .setOutputChannelPhaseL2(IO_OUTPUT2.toString()) // + .setOutputChannelPhaseL3(IO_OUTPUT3.toString()) // + .setEndTime("15:45:00") // + .setPowerOfPhase(2000) // + .setMode(mode) // + .setDefaultLevel(level) // + .setWorkMode(WorkMode.NONE) // + .setMinTime(1) // + .setMinimumSwitchingTime(180) // + .build()); // + } + + private static final ChannelAddress ESSO_DISCHARGE_POWER = new ChannelAddress("_sum", + Sum.ChannelId.ESS_DISCHARGE_POWER.id()); + private static final ChannelAddress LEVEL = new ChannelAddress(CTRL_ID, + ControllerIoHeatingElement.ChannelId.LEVEL.id()); + private static final ChannelAddress GRID_ACTIVE_POWER = new ChannelAddress("_sum", + Sum.ChannelId.GRID_ACTIVE_POWER.id()); + + @Test + public void testDischargeTakeIntoAccount() throws OpenemsNamedException, Exception { + prepareTest(Mode.AUTOMATIC, Level.LEVEL_3)// + .next(new TestCase()// + .input(GRID_ACTIVE_POWER, -2500)// + .output(LEVEL, Level.LEVEL_1)) // + .next(new TestCase() // + .timeleap(clock, 181, ChronoUnit.SECONDS)// + .input(GRID_ACTIVE_POWER, -2500)// + .output(LEVEL, Level.LEVEL_2))// + // Grid power reducing because of 2kW heating power + .next(new TestCase()// + .timeleap(clock, 181, ChronoUnit.SECONDS)// + .input(GRID_ACTIVE_POWER, -500) // + .output(LEVEL, Level.LEVEL_2)// + ).next(new TestCase() // + .timeleap(clock, 181, ChronoUnit.SECONDS)// + .input(GRID_ACTIVE_POWER, -500) // + .input(ESSO_DISCHARGE_POWER, 2300) // + .output(LEVEL, Level.LEVEL_1)// + ); // ; + } + + @Test + public void realDataTest() throws OpenemsNamedException, Exception { + prepareTest(Mode.AUTOMATIC, Level.LEVEL_3)// + // ensure level 3 + .next(new TestCase()// + .input(GRID_ACTIVE_POWER, -6000)// + .output(LEVEL, Level.LEVEL_3)) // + .next(new TestCase()// + .timeleap(clock, 181, ChronoUnit.SECONDS)// + .input(GRID_ACTIVE_POWER, 0)// + .input(ESSO_DISCHARGE_POWER, 2280)// + .output(LEVEL, Level.LEVEL_1)); // ; + } +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/api/TimedataInfluxDb.java b/io.openems.edge.core/src/io/openems/edge/app/api/TimedataInfluxDb.java new file mode 100644 index 00000000000..88bcaef205e --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/api/TimedataInfluxDb.java @@ -0,0 +1,219 @@ +package io.openems.edge.app.api; + +import java.util.ArrayList; +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.api.TimedataInfluxDb.Property; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.OpenemsAppStatus; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; +import io.openems.edge.core.appmanager.formly.enums.InputType; + +@Component(name = "App.Timedata.InfluxDb") +public class TimedataInfluxDb extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public enum Property implements Type { + // Component-IDs + TIMEDATE_ID(AppDef.componentId("timedate0")), // + // Properties + ALIAS(AppDef.copyOfGeneric(CommonProps.alias())), // + QUERY_LANGUAGE(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".queryLanguage.label") // + .setField(JsonFormlyUtil::buildSelectFromNameable, (app, prop, l, params, field) -> { + final var options = new ArrayList(); + options.add("INFLUX_QL"); + options.add("FLUX"); + field.setOptions(options); + }) // + .setDefaultValue("INFLUX_QL"))), // + URL(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".url.label") // + .setTranslatedDescriptionWithAppPrefix(".url.description") // + .setField(JsonFormlyUtil::buildInput) // + .setDefaultValue("http://localhost:8086"))), // + ORG(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".org.label") // + .setTranslatedDescriptionWithAppPrefix(".org.description") // + .setField(JsonFormlyUtil::buildInput) // + .setDefaultValue("-"))), // + API_KEY(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".apiKey.label") // + .setTranslatedLabelWithAppPrefix(".apiKey.description") // + .setField(JsonFormlyUtil::buildInput)// + .setRequired(true))), + BUCKET(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".bucket.label") // + .setTranslatedLabelWithAppPrefix(".bucket.description") // + .setField(JsonFormlyUtil::buildInput)// + .setRequired(true))), + MEASUREMENT(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".measurement.label") // + .setTranslatedLabelWithAppPrefix(".measurement.description") // + .setField(JsonFormlyUtil::buildInput) // + .setDefaultValue("data"))), // + NO_OF_CYCLES(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".noOfCycles.description") // + .setTranslatedLabelWithAppPrefix(".noOfCycles.label") // + .setDefaultValue(1) // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, first) -> { + first.setInputType(InputType.NUMBER); + first.setMin(1); + }))), // + MAX_QUEUE_SIZE(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".maxQueueSize.description")// + .setTranslatedLabelWithAppPrefix(".maxQueueSize.label") // + .setDefaultValue(50) // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, first) -> { + first.setInputType(InputType.NUMBER); + }))), // + IS_READ_ONLY(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".isReadOnly.description") // + .setTranslatedLabelWithAppPrefix(".isReadOnly.label") // + .setDefaultValue(false) // + .setField(JsonFormlyUtil::buildCheckbox))); + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TimedataInfluxDb(// + @Reference ComponentManager componentManager, // + ComponentContext componentContext, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil, // + @Reference AppManagerUtil appManagerUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var id = this.getId(t, p, Property.TIMEDATE_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var queryLanguage = this.getString(p, Property.QUERY_LANGUAGE); + final var url = this.getString(p, Property.URL); + final var apiKey = this.getString(p, Property.API_KEY); + final var bucket = this.getString(p, Property.BUCKET); + final var measuremtn = this.getString(p, Property.MEASUREMENT); + final var noOfCycles = this.getInt(p, Property.NO_OF_CYCLES); + final var maxQueueSize = this.getInt(p, Property.MAX_QUEUE_SIZE); + final var isReadOnly = this.getBoolean(p, Property.IS_READ_ONLY); + + var components = Lists.newArrayList(// + new EdgeConfig.Component(id, alias, "Timedata.InfluxDB", // + JsonUtils.buildJsonObject() // + .addProperty("queryLanguage", queryLanguage) // + .addProperty("url", url) // + .addProperty("apiKey", apiKey) // + .addProperty("bucket", bucket) // + .addProperty("measurement", measuremtn) // + .addProperty("noOfCycles", noOfCycles) // + .addProperty("maxQueueSize", maxQueueSize) // + .addProperty("isReadOnly", isReadOnly)// + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public final OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.TIMEDATA }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.MULTIPLE; + } + + @Override + protected TimedataInfluxDb getApp() { + return this; + } + + @Override + protected OpenemsAppStatus getStatus() { + return OpenemsAppStatus.BETA; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanSee(Role.ADMIN)// + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java index f0c98903754..083bd11673b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java @@ -259,7 +259,6 @@ public FeneconHome20(// } } - @SuppressWarnings("removal") @Override protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { return (t, p, l) -> { diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java index 60c8bacec42..34d2c672789 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java @@ -260,7 +260,6 @@ public FeneconHome30(// } } - @SuppressWarnings("removal") @Override protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { return (t, p, l) -> { diff --git a/io.openems.edge.core/src/io/openems/edge/app/meter/DiscovergyMeter.java b/io.openems.edge.core/src/io/openems/edge/app/meter/DiscovergyMeter.java new file mode 100644 index 00000000000..be525db7656 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/meter/DiscovergyMeter.java @@ -0,0 +1,229 @@ +package io.openems.edge.app.meter; + +import java.util.ArrayList; +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.app.enums.MeterType; +import io.openems.edge.app.meter.DiscovergyMeter.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; +import io.openems.edge.core.appmanager.ComponentManagerSupplier; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.OpenemsAppStatus; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.formly.Exp; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; + +@Component(name = "App.Meter.Discovergy") +public class DiscovergyMeter extends AbstractOpenemsAppWithProps + implements OpenemsApp, AppManagerUtilSupplier { + + public enum Property implements Type { + // Component-IDs + METER_ID(AppDef.componentId("meter0")), // + // Properties + ALIAS(AppDef.copyOfGeneric(CommonProps.alias())), // + TYPE(AppDef.copyOfGeneric(MeterProps.type(MeterType.GRID))), // + EMAIL(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".email.label") // + .setTranslatedDescriptionWithAppPrefix(".email.description") // + .setField(JsonFormlyUtil::buildInputFromNameable).setRequired(true))), // + PASSWORD(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def// + .setTranslatedLabelWithAppPrefix(".password.label") // + .setTranslatedDescriptionWithAppPrefix(".password.description") // + .setRequired(true) // + .setField(JsonFormlyUtil::buildInput, (app, prop, l, params, field) -> { + field.setInputType(io.openems.edge.core.appmanager.formly.enums.InputType.PASSWORD); + }) // + .bidirectional(METER_ID, "password", ComponentManagerSupplier::getComponentManager, t -> { + return JsonUtils.getAsOptionalString(t) // + .map(s -> { + if (s.isEmpty()) { + return null; + } + return new JsonPrimitive("xxx"); + }) // + .orElse(null); + }))), // + SERIAL_NUMBER_TYPE(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".serialType.label") + .setField(JsonFormlyUtil::buildSelect, (app, prop, l, params, field) -> { + final var options = new ArrayList(); + options.add("SERIAL_NUMBER"); + options.add("FULL_SERIAL_NUMBER"); + options.add("METER_ID"); + field.setOptions(options); + }) // + )), // + SERIAL_NUMBER(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".serialNumber.label") // + .setDefaultValue("")// + .setTranslatedDescriptionWithAppPrefix(".serialNumber.description") // + .setField(JsonFormlyUtil::buildInputFromNameable) // + .wrapField((app, property, l, parameter, field) -> { + field.onlyShowIf(Exp.currentModelValue(SERIAL_NUMBER_TYPE).equal(Exp.staticValue("SERIAL_NUMBER"))); // + }))), // + FULL_SERIAL_NUMBER(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".fullSerialNumber.label") // + .setDefaultValue("")// + .setTranslatedDescriptionWithAppPrefix(".fullSerialNumber.description") // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { // + field.onlyShowIf( + Exp.currentModelValue(SERIAL_NUMBER_TYPE).equal(Exp.staticValue("FULL_SERIAL_NUMBER"))); // + }))), // + DISCOVERGY_METER_ID(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def // + .setTranslatedDescriptionWithAppPrefix(".meterId.description") // + .setTranslatedLabelWithAppPrefix(".meterId.label")// + .setDefaultValue("")// + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { // + field.onlyShowIf(Exp.currentModelValue(SERIAL_NUMBER_TYPE).equal(Exp.staticValue("METER_ID"))); // + }))),// + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + private final AppManagerUtil appManagerUtil; + + @Activate + public DiscovergyMeter(// + @Reference ComponentManager componentManager, // + ComponentContext componentContext, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil, // + @Reference AppManagerUtil appManagerUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + this.appManagerUtil = appManagerUtil; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var id = this.getId(t, p, Property.METER_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var meterType = this.getString(p, Property.TYPE); + final var email = this.getString(p, Property.EMAIL); + final var password = this.getString(p, Property.PASSWORD); + final var meterId = this.getString(p, Property.DISCOVERGY_METER_ID); + final var serialNumber = this.getString(p, Property.SERIAL_NUMBER); + final var fullSerialNumber = this.getString(p, Property.FULL_SERIAL_NUMBER); + + var components = Lists.newArrayList(// + new EdgeConfig.Component(id, alias, "Meter.Discovergy", // + JsonUtils.buildJsonObject() // + .addProperty("type", meterType)// + .addProperty("meterId", meterId) // + .addProperty("email", email) // + .addProperty("serialNumber", serialNumber) // + .addProperty("fullSerialNumber", fullSerialNumber)// + .onlyIf(password != null && !password.equals("xxx"), b -> { + b.addProperty("password", password); + }) // + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public final OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.METER }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.MULTIPLE; + } + + @Override + protected DiscovergyMeter getApp() { + return this; + } + + @Override + protected OpenemsAppStatus getStatus() { + return OpenemsAppStatus.BETA; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanSee(Role.ADMIN)// + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java index d6508f37f9b..3e287c25f9b 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java @@ -69,6 +69,12 @@ public enum OpenemsAppCategory { */ API("api"), + /** + * Timedata.. + * + */ + TIMEDATA("timedata"), + /** * Category for test apps. * diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index a7bb8211d12..fb814f5c16c 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -94,6 +94,27 @@ App.Api.RestJson.ReadOnly.Name.short = REST/JSON lesend App.Api.RestJson.ReadWrite.Name = REST/JSON Schreibzugriff App.Api.RestJson.ReadWrite.Name.short = REST/JSON Schreibzugriff +App.Timedata.InfluxDb.Name = Influx Db Timedata +App.Timedata.InfluxDb.Name.short = Timedata +App.Timedata.InfluxDb.queryLanguage.label = Abfragesprache +App.Timedata.InfluxDb.url.label = URL +App.Timedata.InfluxDb.url.description = Die InfluxDB-URL, z. B.: http://localhost:8086 +App.Timedata.InfluxDb.org.label = Organisation +App.Timedata.InfluxDb.org.description = Die Organisation; für InfluxDB v1: '-' +App.Timedata.InfluxDb.apiKey.label = API Key +App.Timedata.InfluxDb.apiKey.description = Der API Key; für InfluxDB v1: 'Benutzername:Passwort', z. B. 'admin:admin' +App.Timedata.InfluxDb.measurement.label = Measurement +App.Timedata.InfluxDb.measurement.description = Die InfluxDB measurement +App.Timedata.InfluxDb.noOfCycles.description = Wie viele Zyklen bis die Daten in InfluxDB geschrieben werden +App.Timedata.InfluxDb.noOfCycles.label = Anzahl der Zyklen +App.Timedata.InfluxDb.maxQueueSize.description = Maximale Größe der Warteschlangenaufgaben. +App.Timedata.InfluxDb.maxQueueSize.label = Anzahl der maximal geplanten Aufgaben +App.Timedata.InfluxDb.isReadOnly.label = Read Only Modus +App.Timedata.InfluxDb.isReadOnly.description = Aktiviert Read Only Modus. Dann werden keine Daten in InfluxDB geschrieben. +App.Timedata.InfluxDb.bucket.label = Bucket +App.Timedata.InfluxDb.bucket.description = Der Bucket-Name; für InfluxDB v1: 'Datenbank/retentionPolicy', z. B. 'db/daten' + + # Evcs App.Evcs.controller.alias = Ladestation Steuerung App.Evcs.ip.description = Die IP-Adresse der Ladestation. @@ -294,6 +315,20 @@ App.Meter.Kdk.Name = KDK Zähler App.Meter.Kdk.Name.short = KDK App.Meter.Microcare.Sdm630.Name = SDM630 Zähler App.Meter.Microcare.Sdm630.Name.short = SDM630 +App.Meter.Discovergy.Name = Discovergy Zähler +App.Meter.Discovergy.Name.short = Discovergy +App.Meter.Discovergy.email.label = Authentifizierungs E-Mail +App.Meter.Discovergy.email.description = E-Mail für Ihren my.discovergy.com Zugang. +App.Meter.Discovergy.password.label = Authentifizierungs Passwort +App.Meter.Discovergy.password.description = Passwort für deinen my.discovergy.com Zugang. +App.Meter.Discovergy.serialNumber.label = Discovergy Seriennummer +App.Meter.Discovergy.serialNumber.description = Seriennummer Ihres Zähler, z.B. 12345678. Siehe https://my.discovergy.com/readings +App.Meter.Discovergy.fullSerialNumber.description = Komplette Seriennummer Ihres Zähler, z.B. 1ESY1234567890. +App.Meter.Discovergy.fullSerialNumber.label = Discovergy Komplette Seriennummer +App.Meter.Discovergy.meterId.label = Discovergy MeterId +App.Meter.Discovergy.meterId.description = Interne Zähler Id. Dieser is ein Hex String mit Länge 32. +App.Meter.Discovergy.serialType.label = Typ der Seriennummer + # PeakShaving App.PeakShaving.power.label = Maximale Netzbezugsleistung diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 00e23e68823..bbec3469d64 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -94,6 +94,27 @@ App.Api.RestJson.ReadOnly.Name.short = REST/JSON reading App.Api.RestJson.ReadWrite.Name = REST/JSON write access App.Api.RestJson.ReadWrite.Name.short = REST/JSON write access +App.Timedata.InfluxDb.Name = Influx Db Timedata +App.Timedata.InfluxDb.Name.short = Timedata +App.Timedata.InfluxDb.queryLanguage.label = Query language +App.Timedata.InfluxDb.url.label = URL +App.Timedata.InfluxDb.url.description = The InfluxDB URL, e.g.: http://localhost:8086 +App.Timedata.InfluxDb.org.label = Org +App.Timedata.InfluxDb.org.description = The Organisation; for InfluxDB v1: '-' +App.Timedata.InfluxDb.apiKey.label = ApiKey +App.Timedata.InfluxDb.apiKey.description = The ApiKey; for InfluxDB v1: 'username:password', e.g. 'admin:admin' +App.Timedata.InfluxDb.measurement.label = Measurement +App.Timedata.InfluxDb.measurement.description = The InfluxDB measurement +App.Timedata.InfluxDb.noOfCycles.description = How many Cycles till data is written to InfluxDB +App.Timedata.InfluxDb.noOfCycles.label = No of Cycles +App.Timedata.InfluxDb.maxQueueSize.description = Max-Size of Queued tasks. +App.Timedata.InfluxDb.maxQueueSize.label = Number of max scheduled tasks +App.Timedata.InfluxDb.isReadOnly.label = Read-Only mode +App.Timedata.InfluxDb.isReadOnly.description = Activates the read-only mode. Then no data is written to InfluxDB. +App.Timedata.InfluxDb.bucket.label = Bucket +App.Timedata.InfluxDb.bucket.description = The bucket name; for InfluxDB v1: 'database/retentionPolicy', e.g. 'db/data' + + # Evcs App.Evcs.controller.alias = Charging station control App.Evcs.ip.description = The IP address of the charging station. @@ -294,6 +315,19 @@ App.Meter.Kdk.Name = KDK meter App.Meter.Kdk.Name.short = KDK App.Meter.Microcare.Sdm630.Name = SDM630 meter App.Meter.Microcare.Sdm630.Name.short = SDM630 +App.Meter.Discovergy.Name = Discovergy Meter +App.Meter.Discovergy.Name.short = Discovergy +App.Meter.Discovergy.email.label = Authentication E-Mail +App.Meter.Discovergy.email.description = E-Mail for your my.discovergy.com access. +App.Meter.Discovergy.password.label = Authentication Password +App.Meter.Discovergy.password.description = Password for your my.discovergy.com access. +App.Meter.Discovergy.serialNumber.label = Discovergy Serial-Number +App.Meter.Discovergy.serialNumber.description = Serial-Number of the meter, e.g. 12345678. See https://my.discovergy.com/readings +App.Meter.Discovergy.fullSerialNumber.description = Full Serial-Number of the meter, e.g. 1ESY1234567890. +App.Meter.Discovergy.fullSerialNumber.label = Discovergy Full Serial-Number +App.Meter.Discovergy.meterId.label = Discovergy MeterId +App.Meter.Discovergy.meterId.description = Internal MeterId. This is a hex string with length 32. +App.Meter.Discovergy.serialType.label = Type of the serial number # PeakShaving App.PeakShaving.power.label = Peak-Shaving power diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java index bf41766cd55..2dd6105f73c 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java @@ -12,6 +12,8 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.List; +import java.util.Map.Entry; +import java.util.stream.Stream; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; @@ -65,10 +67,12 @@ import io.openems.edge.common.user.User; import io.openems.edge.core.componentmanager.jsonrpc.ChannelExportXlsxRequest; import io.openems.edge.core.componentmanager.jsonrpc.ChannelExportXlsxResponse; +import io.openems.edge.core.componentmanager.jsonrpc.GetAllComponentFactories; import io.openems.edge.core.componentmanager.jsonrpc.GetChannel; import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent; import io.openems.edge.core.componentmanager.jsonrpc.GetChannelsOfComponent.ChannelRecord; import io.openems.edge.core.componentmanager.jsonrpc.GetDigitalInputChannelsOfComponents; +import io.openems.edge.core.componentmanager.jsonrpc.GetPropertiesOfFactory; import io.openems.edge.core.componentmanager.jsonrpc.GetStateChannelsOfComponent; import io.openems.edge.io.api.DigitalInput; @@ -395,7 +399,6 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { final var request = call.getRequest(); final var channel = this.getChannel(new ChannelAddress(request.componentId(), request.channelId())); - Thread.sleep(5000); return new GetChannel.Response(toChannelRecord(channel)); }); @@ -413,6 +416,38 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { return new GetDigitalInputChannelsOfComponents.Response(result); }); + + builder.handleRequest(new GetAllComponentFactories(), endpoint -> { + endpoint.setDescription(""" + Handles a GetAllComponentFactories. + """) // + .setGuards(EdgeGuards.roleIsAtleast(Role.ADMIN)); + }, call -> { + final var edgeConfig = this.getEdgeConfig(); + + return new GetAllComponentFactories.Response(edgeConfig.getFactories().entrySet().stream() + .collect(JsonUtils.toJsonObject(Entry::getKey, i -> i.getValue().toJson()))); + }); + + builder.handleRequest(new GetPropertiesOfFactory(), endpoint -> { + endpoint.setDescription(""" + Handles a GetPropertiesOfFactory. + """) // + .setGuards(EdgeGuards.roleIsAtleast(Role.ADMIN)); + }, call -> { + final var factoryId = call.getRequest().factoryId(); + + final var edgeConfig = this.getEdgeConfig(); + final var factory = edgeConfig.getFactories().get(factoryId); + + if (factory == null) { + throw new OpenemsException("Factory with id " + factoryId + " could not be found."); + } + + return new GetPropertiesOfFactory.Response(factory.toJson(), Stream.of(factory.getProperties()) // + .map(EdgeConfig.Factory.Property::toJson) // + .collect(JsonUtils.toJsonArray())); + }); } private static ChannelRecord toChannelRecord(Channel channel) { diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetAllComponentFactories.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetAllComponentFactories.java new file mode 100644 index 00000000000..8d9301f7cb2 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetAllComponentFactories.java @@ -0,0 +1,66 @@ +package io.openems.edge.core.componentmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.emptyObjectSerializer; +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.componentmanager.jsonrpc.GetAllComponentFactories.Request; +import io.openems.edge.core.componentmanager.jsonrpc.GetAllComponentFactories.Response; + +public class GetAllComponentFactories implements EndpointRequestType { + + @Override + public String getMethod() { + return "getAllComponentFactories"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public record Request() { + + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return emptyObjectSerializer(Request::new); + } + + } + + // TODO change to proper type + public record Response(JsonObject factories) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetAllComponentFactories.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetAllComponentFactories.Response.class, json -> { + return new Response(json.getJsonElementPath("factories").getAsJsonObjectPath().get()); + }, obj -> { + return JsonUtils.buildJsonObject() // + .add("factories", obj.factories()) // + .build(); + }); + } + + } + +} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetPropertiesOfFactory.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetPropertiesOfFactory.java new file mode 100644 index 00000000000..e942097bd79 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/GetPropertiesOfFactory.java @@ -0,0 +1,76 @@ +package io.openems.edge.core.componentmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.componentmanager.jsonrpc.GetPropertiesOfFactory.Request; +import io.openems.edge.core.componentmanager.jsonrpc.GetPropertiesOfFactory.Response; + +public class GetPropertiesOfFactory implements EndpointRequestType { + + @Override + public String getMethod() { + return "getPropertiesOfFactory"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public record Request(// + String factoryId // + ) { + + /** + * Returns a {@link JsonSerializer} for a {@link AddAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Request.class, // + json -> new Request(// + json.getString("factoryId")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("factoryId", obj.factoryId()) // + .build()); + } + + } + + // TODO change to proper types + public record Response(JsonObject factory, JsonArray properties) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetPropertiesOfFactory.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetPropertiesOfFactory.Response.class, json -> { + return new Response(// + json.getJsonObject("factory"), // + json.getJsonArray("properties")); + }, obj -> { + return JsonUtils.buildJsonObject() // + .add("factory", obj.factory()) // + .add("properties", obj.properties()) // + .build(); + }); + } + + } + +} \ No newline at end of file diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java index 28c448cf56f..ca6f501674b 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java @@ -16,6 +16,7 @@ import io.openems.edge.app.api.ModbusTcpApiReadWrite; import io.openems.edge.app.api.RestJsonApiReadOnly; import io.openems.edge.app.api.RestJsonApiReadWrite; +import io.openems.edge.app.api.TimedataInfluxDb; import io.openems.edge.app.ess.FixActivePower; import io.openems.edge.app.ess.FixStateOfCharge; import io.openems.edge.app.ess.PowerPlantController; @@ -36,6 +37,7 @@ import io.openems.edge.app.loadcontrol.ManualRelayControl; import io.openems.edge.app.loadcontrol.ThresholdControl; import io.openems.edge.app.meter.CarloGavazziMeter; +import io.openems.edge.app.meter.DiscovergyMeter; import io.openems.edge.app.meter.JanitzaMeter; import io.openems.edge.app.meter.MicrocareSdm630Meter; import io.openems.edge.app.meter.SocomecMeter; @@ -299,6 +301,16 @@ public static final IesKeywattEvcs iesKeywattEvcs(AppManagerTestBundle t) { return app(t, IesKeywattEvcs::new, "App.Evcs.IesKeywatt"); } + /** + * Test method for creating a {@link TimedataInfluxDb}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TimedataInfluxDb timedataInfluxDb(AppManagerTestBundle t) { + return app(t, TimedataInfluxDb::new, "App.Timedata.InfluxDb"); + } + /** * Test method for creating a {@link AlpitronicEvcs}. * @@ -427,6 +439,16 @@ public static final SocomecMeter socomecMeter(AppManagerTestBundle t) { return app(t, SocomecMeter::new, "App.Meter.Socomec"); } + /** + * Test method for creating a {@link DiscoveregyMeter}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final DiscovergyMeter discovergyMeter(AppManagerTestBundle t) { + return app(t, DiscovergyMeter::new, "App.Meter.Discovergy"); + } + /** * Test method for creating a {@link CarloGavazziMeter}. * diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java index 05f25ba9c60..1e5ae260b70 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java @@ -60,6 +60,10 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.restJsonApiReadWrite(t), true, JsonUtils.buildJsonObject() // .addProperty("API_TIMEOUT", 60) // .build())); + this.apps.add(new TestTranslation(Apps.timedataInfluxDb(t), true, JsonUtils.buildJsonObject() // + .addProperty("API_KEY", "123456789") // + .addProperty("BUCKET", "bucket")// + .build())); this.apps.add(new TestTranslation(Apps.hardyBarthEvcs(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.kebaEvcs(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.iesKeywattEvcs(t), true, new JsonObject())); @@ -92,6 +96,10 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.thresholdControl(t), false, JsonUtils.buildJsonObject() // .add("OUTPUT_CHANNELS", JsonUtils.buildJsonArray().add("io0/Relay1").build()) // .build())); + this.apps.add(new TestTranslation(Apps.discovergyMeter(t), false, JsonUtils.buildJsonObject() // + .addProperty("EMAIL", "test@test.test") // + .addProperty("PASSWORD", "xxxx") // + .build())); this.apps.add(new TestTranslation(Apps.socomecMeter(t), false, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .build())); diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java index 392eb4324cb..4c8c476ec44 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java @@ -211,6 +211,10 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access .channel(1, ChannelId.GRID_MODE, ModbusType.UINT16) // .channel(2, ChannelId.ACTIVE_POWER, ModbusType.FLOAT32) // .channel(4, ChannelId.REACTIVE_POWER, ModbusType.FLOAT32) // + .channel(6, ChannelId.MIN_CELL_VOLTAGE, ModbusType.FLOAT32) // + .channel(8, ChannelId.MAX_CELL_VOLTAGE, ModbusType.FLOAT32) // + .channel(10, ChannelId.MIN_CELL_TEMPERATURE, ModbusType.FLOAT32) // + .channel(12, ChannelId.MAX_CELL_TEMPERATURE, ModbusType.FLOAT32) // .build(); } diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java index af85ef0b031..c77a5496cc1 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractChannelManager.java @@ -108,6 +108,18 @@ private void addBatteryListener(ClockProvider clockProvider, Battery battery, Sy this.addCopyListener(battery, // Battery.ChannelId.SOC, // SymmetricEss.ChannelId.SOC); + this.addCopyListener(battery, // + Battery.ChannelId.MIN_CELL_VOLTAGE, // + SymmetricEss.ChannelId.MIN_CELL_VOLTAGE); + this.addCopyListener(battery, // + Battery.ChannelId.MAX_CELL_VOLTAGE, // + SymmetricEss.ChannelId.MAX_CELL_VOLTAGE); + this.addCopyListener(battery, // + Battery.ChannelId.MIN_CELL_TEMPERATURE, // + SymmetricEss.ChannelId.MIN_CELL_TEMPERATURE); + this.addCopyListener(battery, // + Battery.ChannelId.MAX_CELL_TEMPERATURE, // + SymmetricEss.ChannelId.MAX_CELL_TEMPERATURE); } private void addEssListener(ClockProvider clockProvider, Battery battery, SymmetricBatteryInverter inverter) { diff --git a/io.openems.shared.influxdb/src/io/openems/shared/influxdb/proxy/InfluxQlProxy.java b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/proxy/InfluxQlProxy.java index 4a78e42f73b..bdd64fb4cb5 100644 --- a/io.openems.shared.influxdb/src/io/openems/shared/influxdb/proxy/InfluxQlProxy.java +++ b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/proxy/InfluxQlProxy.java @@ -19,6 +19,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.primitives.Doubles; +import com.google.common.primitives.Longs; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonPrimitive; @@ -34,7 +36,6 @@ import io.openems.common.types.ChannelAddress; import io.openems.common.utils.CollectorUtils; import io.openems.common.utils.JsonUtils; -import io.openems.common.utils.StringUtils; import io.openems.shared.influxdb.DbDataUtils; import io.openems.shared.influxdb.InfluxConnector.InfluxConnection; @@ -628,17 +629,8 @@ private static JsonElement convertToJsonElement(Object valueObj) { } else { str = valueObj.toString(); } - if (str.isEmpty()) { - return JsonNull.INSTANCE; - } - if (StringUtils.matchesFloatPattern(str)) { - return new JsonPrimitive(Double.parseDouble(str)); - } - if (StringUtils.matchesIntegerPattern(str)) { - return new JsonPrimitive(Long.parseLong(str)); - } - return new JsonPrimitive(valueObj.toString()); + return parseToJsonElement(str); } private static SortedMap convertHistoricEnergyResultSingleValueInDay(// @@ -685,7 +677,7 @@ private static SortedMap convertHistoricEnergyResul continue; } var valueObj = record.getValueByKey(column); - JsonElement value; + final JsonElement value; if (valueObj == null) { value = JsonNull.INSTANCE; } else if (valueObj instanceof Number n) { @@ -697,15 +689,7 @@ private static SortedMap convertHistoricEnergyResul } else { str = valueObj.toString(); } - if (str.isEmpty()) { - value = JsonNull.INSTANCE; - } else if (StringUtils.matchesFloatPattern(str)) { - value = new JsonPrimitive(Double.parseDouble(str)); - } else if (StringUtils.matchesIntegerPattern(str)) { - value = new JsonPrimitive(Long.parseLong(str)); - } else { - value = new JsonPrimitive(valueObj.toString()); - } + value = parseToJsonElement(str); } try { m.accept(new Pair<>(ChannelAddress.fromString(column), value)); @@ -758,15 +742,7 @@ private static SortedMap convertHistoricEnergyResul } else { str = valueObj.toString(); } - if (str.isEmpty()) { - value = JsonNull.INSTANCE; - } else if (StringUtils.matchesFloatPattern(str)) { - value = assertPositive(Double.parseDouble(str), influxEdgeId, channels); - } else if (StringUtils.matchesIntegerPattern(str)) { - value = assertPositive(Long.parseLong(str), influxEdgeId, channels); - } else { - value = new JsonPrimitive(valueObj.toString()); - } + value = parseToJsonElement(str); } map.put(ChannelAddress.fromString(column), value); } @@ -844,4 +820,32 @@ private static JsonElement assertPositive(Number number, Optional influ return new JsonPrimitive(number); } } + + /** + * Parses a String to a JsonElement; handles null/empty, double and long. + * + * @param str the String + * @return the {@link JsonElement} + */ + protected static JsonElement parseToJsonElement(String str) { + // Null/Empty + if (str == null || str.isEmpty()) { + return JsonNull.INSTANCE; + } + + // Try to parse long + var l = Longs.tryParse(str); + if (l != null) { + return new JsonPrimitive(l); + } + + // Try to parse double + var d = Doubles.tryParse(str); + if (d != null) { + return new JsonPrimitive(d); + } + + // Fallback + return new JsonPrimitive(str); + } } diff --git a/io.openems.shared.influxdb/test/io/openems/shared/influxdb/proxy/InfluxQlProxyTest.java b/io.openems.shared.influxdb/test/io/openems/shared/influxdb/proxy/InfluxQlProxyTest.java index 5d76d9c7f69..f4e35cc4ec2 100644 --- a/io.openems.shared.influxdb/test/io/openems/shared/influxdb/proxy/InfluxQlProxyTest.java +++ b/io.openems.shared.influxdb/test/io/openems/shared/influxdb/proxy/InfluxQlProxyTest.java @@ -1,5 +1,6 @@ package io.openems.shared.influxdb.proxy; +import static io.openems.shared.influxdb.proxy.InfluxQlProxy.parseToJsonElement; import static org.junit.Assert.assertEquals; import java.util.List; @@ -33,4 +34,13 @@ public void testAverage() { assertEquals(4d, last.getAsDouble(), 0d); } + @Test + public void testParseToJsonElement() { + assertEquals(123.456, parseToJsonElement("123.456").getAsNumber()); + assertEquals(123L, parseToJsonElement("123").getAsNumber()); + assertEquals(" 123 ", parseToJsonElement(" 123 ").getAsString()); + assertEquals("foo-bar", parseToJsonElement("foo-bar").getAsString()); + assertEquals(JsonNull.INSTANCE, parseToJsonElement(null)); + assertEquals(JsonNull.INSTANCE, parseToJsonElement("")); + } } diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index a4088ac1113..eaa0db0019f 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -25,5 +25,6 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea de.bytefish:pgbulkinsert;version='8.1.3',\ fr.turri:aXMLRPC;version='1.13.0',\ org.dhatim:fastexcel;version='0.18.0',\ + org.dhatim:fastexcel-reader;version='0.18',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ - org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ + org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ \ No newline at end of file diff --git a/io.openems.wrapper/fastexcel.bnd b/io.openems.wrapper/fastexcel.bnd index ab7f758a06e..92ccb7bb914 100644 --- a/io.openems.wrapper/fastexcel.bnd +++ b/io.openems.wrapper/fastexcel.bnd @@ -3,13 +3,16 @@ Bundle-DocURL: https://github.com/dhatim/fastexcel Bundle-License: https://opensource.org/licenses/Apache-2.0 Bundle-Version: 0.18.0 -Include-Resource: @fastexcel-0.18.0.jar +Include-Resource: \ + @fastexcel-0.18.0.jar,\ + @fastexcel-reader-0.18.0.jar,\ -dsannotations: * -metatypeannotations: * Export-Package: \ - org.dhatim.fastexcel + org.dhatim.fastexcel,\ + org.dhatim.fastexcel.reader,\ -sources: false diff --git a/tools/build-debian-package.sh b/tools/build-debian-package.sh index 9582af59322..a57747c6e13 100755 --- a/tools/build-debian-package.sh +++ b/tools/build-debian-package.sh @@ -1,7 +1,9 @@ -#!/bin/bash -e +#!/bin/bash # # Creates a Debian package for OpenEMS Edge + UI +set -e + OUTPUT=$( realpath ${1:-.} ) DEBIAN_UI_LOCATION=tools/debian/usr/share/openems/www @@ -28,7 +30,7 @@ initialize_environment() { source $SCRIPT_DIR/common.sh common_initialize_environment common_build_snapshot_version - + DEB_FILE="${PACKAGE_NAME}.deb" VERSION_FILE="${PACKAGE_NAME}.version" } @@ -53,6 +55,12 @@ prepare_deb_template() { echo "# Build Debian package" sed --in-place "s/^\(Version: \).*$/\1$VERSION/" tools/debian/DEBIAN/control + for script in preinst postinst prerm postrm + do + script="tools/debian/DEBIAN/$script" + [ -f $script ] && chmod 755 $script + done + echo "## Add OpenEMS Edge" if [ -f "$DEBIAN_EDGE_LOCATION/openems.jar" ]; then echo "openems.jar exists. Skipping common_build_edge." diff --git a/tools/debian/DEBIAN/postrm b/tools/debian/DEBIAN/postrm new file mode 100755 index 00000000000..5f387c310fe --- /dev/null +++ b/tools/debian/DEBIAN/postrm @@ -0,0 +1,16 @@ +#!/bin/bash +# postrm script for openems-edge + +set -o errexit + +function purge-openems { + local confdir="/etc/openems.d" + local libdir="/var/lib/openems" + + if [ -d "${confdir}" ]; then rm -r "${confdir}"; fi + if [ -d "${libdir}" ]; then rm -r "${libdir}"; fi +} + +case "$1" in + "purge") purge-openems;; +esac diff --git a/tools/drone/openems-android.sh b/tools/drone/openems-android.sh new file mode 100755 index 00000000000..8e19fd37bea --- /dev/null +++ b/tools/drone/openems-android.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +NODE_MAJOR=20 + +ANDROID_SDK_VERSION=9477386 +ANDROID_HOME="/opt/android-sdk" +ANDROID_BUILD_TOOLS_VERSION=32.0.0 +ANDROID_PLATFORMS_VERSION=32 + +# Build/Update 'openems-android' Container for Drone/Woodpecker CI + +docker pull node:${NODE_MAJOR} + +docker build -t openems-android:${NODE_MAJOR}.${ANDROID_PLATFORMS_VERSION} -f - . < /usr/bin/copy \ + && chmod +x /usr/bin/copy + +RUN ln -sf /bin/bash /bin/sh + +EOF \ No newline at end of file diff --git a/tools/drone/openems-build.sh b/tools/drone/openems-build.sh new file mode 100644 index 00000000000..810fbb5922b --- /dev/null +++ b/tools/drone/openems-build.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +JAVA_VERSION=21 +NODE_MAJOR=20 + +# Build/Update 'openems-build' Container for Drone/Woodpecker CI + +docker pull eclipse-temurin:${JAVA_VERSION}-jdk + +docker build -t openems-build:${JAVA_VERSION}.${NODE_MAJOR} -f - . < [!IMPORTANT] +> Crucial information necessary for users to succeed. Only provide /resources/logo-dark.png and logo.png +* Move the files from res(except values and xml) to ```/android/app/src/$theme/``` (```/main``` acts as default) +* Build apps: `gradlew bundle{$theme}Release` + +Important (if not generated, can be copied and adjusted from existing theme): +- `ui\android\app\src\{$theme}\res\xml\file_paths.xml` +- `ui\android\app\src\{$theme}\res\values` + +### Debugging + +Use `gradlew install{$theme}Release to install it on any device` + +- Available Tasks: `gradlew tasks` +- list available devices + emulators: `$npx native-run android --list --json` + +## i18n - internationalization Translation is based on [ngx-translate](https://github.com/ngx-translate). The language can be changed at runtime in the "About UI" dialog. @@ -84,4 +114,4 @@ ngOnDestroy() { ``` #### Debugging Angular PWA Via USB-Connection -Please follow this: https://medium.com/nerd-for-tech/google-chrome-how-to-inspect-websites-on-mobile-devices-804677f863ce +Please follow this: https://medium.com/nerd-for-tech/google-chrome-how-to-inspect-websites-on-mobile-devices-804677f863ce \ No newline at end of file diff --git a/ui/android/.idea/.gitignore b/ui/android/.idea/.gitignore new file mode 100644 index 00000000000..26d33521af1 --- /dev/null +++ b/ui/android/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/ui/android/.idea/compiler.xml b/ui/android/.idea/compiler.xml new file mode 100644 index 00000000000..b589d56e9f2 --- /dev/null +++ b/ui/android/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ui/android/.idea/jarRepositories.xml b/ui/android/.idea/jarRepositories.xml new file mode 100644 index 00000000000..de647e0dbb5 --- /dev/null +++ b/ui/android/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/android/.idea/misc.xml b/ui/android/.idea/misc.xml new file mode 100644 index 00000000000..8978d23db56 --- /dev/null +++ b/ui/android/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/ui/android/app/.gitignore b/ui/android/app/.gitignore new file mode 100644 index 00000000000..043df802a29 --- /dev/null +++ b/ui/android/app/.gitignore @@ -0,0 +1,2 @@ +/build/* +!/build/.npmkeep diff --git a/ui/android/app/build.gradle b/ui/android/app/build.gradle new file mode 100644 index 00000000000..04b12182cfc --- /dev/null +++ b/ui/android/app/build.gradle @@ -0,0 +1,88 @@ +apply plugin: 'com.android.application' + +def keystorePropertiesFile = rootProject.file("keystore.properties") +def keystoreProperties = new Properties() +keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + defaultConfig { + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 29 + versionName "2024.5.1.1" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + aaptOptions { + // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. + // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61 + ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' + } + multiDexEnabled true //important + } + + flavorDimensions "version" + productFlavors { + // create("example") { + // applicationId "io.example.ui" + // namespace "io.example.ui" + // dimension "version" + // } + } + + sourceSets { + // example { + // res { + // srcDirs 'src/example/res' + // } + // java { + // srcDirs 'src/example/java' + // } + // } + } + + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile file(keystoreProperties['storeFile']) + storePassword keystoreProperties['storePassword'] + } + } + + buildTypes { + release { + signingConfig signingConfigs.release + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +repositories { + flatDir{ + dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion" + implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion" + implementation project(':capacitor-android') + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation project(':capacitor-cordova-android-plugins') +} + +apply from: 'capacitor.build.gradle' + +try { + def servicesJSON = file('google-services.json') + if (servicesJSON.text) { + apply plugin: 'com.google.gms.google-services' + } +} catch(Exception e) { + logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work") +} \ No newline at end of file diff --git a/ui/android/app/capacitor.build.gradle b/ui/android/app/capacitor.build.gradle new file mode 100644 index 00000000000..65d219eae7a --- /dev/null +++ b/ui/android/app/capacitor.build.gradle @@ -0,0 +1,24 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN + +android { + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } +} + +apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" +dependencies { + implementation project(':capacitor-community-file-opener') + implementation project(':capacitor-app') + implementation project(':capacitor-filesystem') + implementation project(':capacitor-splash-screen') + implementation project(':capacitor-blob-writer') + implementation project(':capacitor-secure-storage-plugin') + +} + + +if (hasProperty('postBuildExtras')) { + postBuildExtras() +} diff --git a/ui/android/app/proguard-rules.pro b/ui/android/app/proguard-rules.pro new file mode 100644 index 00000000000..f1b424510da --- /dev/null +++ b/ui/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/ui/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java b/ui/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java new file mode 100644 index 00000000000..f2c2217efa5 --- /dev/null +++ b/ui/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import android.content.Context; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see
    Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.getcapacitor.app", appContext.getPackageName()); + } +} diff --git a/ui/android/app/src/main/AndroidManifest.xml b/ui/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..665cbc6d021 --- /dev/null +++ b/ui/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java b/ui/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java new file mode 100644 index 00000000000..0297327842d --- /dev/null +++ b/ui/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java @@ -0,0 +1,18 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} diff --git a/ui/android/build.gradle b/ui/android/build.gradle new file mode 100644 index 00000000000..3bdeb1b77f0 --- /dev/null +++ b/ui/android/build.gradle @@ -0,0 +1,32 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + ext { + agp_version = '8.1.4' + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath "com.android.tools.build:gradle:$agp_version" + classpath 'com.google.gms:google-services:4.3.15' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +apply from: "variables.gradle" + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/ui/android/capacitor.settings.gradle b/ui/android/capacitor.settings.gradle new file mode 100644 index 00000000000..917fdb649c8 --- /dev/null +++ b/ui/android/capacitor.settings.gradle @@ -0,0 +1,21 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') + +include ':capacitor-community-file-opener' +project(':capacitor-community-file-opener').projectDir = new File('../node_modules/@capacitor-community/file-opener/android') + +include ':capacitor-app' +project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') + +include ':capacitor-filesystem' +project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android') + +include ':capacitor-splash-screen' +project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android') + +include ':capacitor-blob-writer' +project(':capacitor-blob-writer').projectDir = new File('../node_modules/capacitor-blob-writer/android') + +include ':capacitor-secure-storage-plugin' +project(':capacitor-secure-storage-plugin').projectDir = new File('../node_modules/capacitor-secure-storage-plugin/android') diff --git a/ui/android/gradle.properties b/ui/android/gradle.properties new file mode 100644 index 00000000000..2e87c52f83c --- /dev/null +++ b/ui/android/gradle.properties @@ -0,0 +1,22 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true diff --git a/ui/android/gradle/wrapper/gradle-wrapper.jar b/ui/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/ui/android/gradle/wrapper/gradle-wrapper.properties b/ui/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..cab95f43c39 --- /dev/null +++ b/ui/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +#Thu Apr 04 11:31:47 CEST 2024 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/ui/android/gradlew b/ui/android/gradlew new file mode 100644 index 00000000000..79a61d421cc --- /dev/null +++ b/ui/android/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ui/android/gradlew.bat b/ui/android/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/ui/android/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ui/android/keystore.properties b/ui/android/keystore.properties new file mode 100644 index 00000000000..9ac490bd3ea --- /dev/null +++ b/ui/android/keystore.properties @@ -0,0 +1,4 @@ +storePassword=Halelilu4 +keyPassword=Halelilu4 +keyAlias=key1 +storeFile=./../../key.jks \ No newline at end of file diff --git a/ui/android/settings.gradle b/ui/android/settings.gradle new file mode 100644 index 00000000000..3b4431d7724 --- /dev/null +++ b/ui/android/settings.gradle @@ -0,0 +1,5 @@ +include ':app' +include ':capacitor-cordova-android-plugins' +project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') + +apply from: 'capacitor.settings.gradle' \ No newline at end of file diff --git a/ui/android/variables.gradle b/ui/android/variables.gradle new file mode 100644 index 00000000000..5946adabdd2 --- /dev/null +++ b/ui/android/variables.gradle @@ -0,0 +1,16 @@ +ext { + minSdkVersion = 22 + compileSdkVersion = 33 + targetSdkVersion = 33 + androidxActivityVersion = '1.7.0' + androidxAppCompatVersion = '1.6.1' + androidxCoordinatorLayoutVersion = '1.2.0' + androidxCoreVersion = '1.10.0' + androidxFragmentVersion = '1.5.6' + coreSplashScreenVersion = '1.0.0' + androidxWebkitVersion = '1.6.1' + junitVersion = '4.13.2' + androidxJunitVersion = '1.1.5' + androidxEspressoCoreVersion = '3.5.1' + cordovaAndroidVersion = '10.1.1' +} \ No newline at end of file diff --git a/ui/capacitor.config.ts b/ui/capacitor.config.ts new file mode 100644 index 00000000000..7702fbd212e --- /dev/null +++ b/ui/capacitor.config.ts @@ -0,0 +1,47 @@ +import { CapacitorConfig } from '@capacitor/cli'; +import { Theme } from 'src/environments'; + +let config: CapacitorConfig; + +const baseConfig: CapacitorConfig = { + webDir: 'target', + server: { + androidScheme: 'https', + iosScheme: 'https', + }, + plugins: { + SplashScreen: { + launchShowDuration: 1000, + launchAutoHide: false, + launchFadeOutDuration: 1000, + backgroundColor: "#ffffffff", + androidSplashResourceName: "splash", + androidScaleType: "CENTER_INSIDE", + splashFullScreen: false, + splashImmersive: true, + useDialog: true, + }, + CapacitorCookies: { + enabled: true + } + } +} + +switch (process.env.NODE_ENV as Theme) { + // case 'EXAMPLE': + // config = { + // ...baseConfig, + // appId: 'io.openems.ui', + // appName: 'EXAMPL', + // server: { + // ...baseConfig.server, + // hostname: 'portal.openems.io' + // } + // } + // break; + default: + throw new Error(`Capacitor config for theme ${process.env.NODE_ENV} not implemented.`) +} +console.warn(config); + +export default config; diff --git a/ui/ionic.config.json b/ui/ionic.config.json index 5d37ec1d4cc..9ecee1c52ce 100644 --- a/ui/ionic.config.json +++ b/ui/ionic.config.json @@ -1,5 +1,7 @@ { "name": "openems-ui", - "integrations": {}, + "integrations": { + "capacitor": {} + }, "type": "angular" -} \ No newline at end of file +} diff --git a/ui/package-lock.json b/ui/package-lock.json index 68e4c750c74..2fb7e864c4f 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -17,12 +17,25 @@ "@angular/platform-browser-dynamic": "~16.2.12", "@angular/router": "~16.2.12", "@angular/service-worker": "~16.2.12", + "@capacitor-community/file-opener": "^1.0.5", + "@capacitor/android": "5.2.3", + "@capacitor/app": "^5.0.6", + "@capacitor/core": "5.2.3", + "@capacitor/filesystem": "^5.2.0", + "@capacitor/ios": "5.2.3", + "@capacitor/splash-screen": "^5.0.6", + "@ionic-native/core": "^5.36.0", + "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", + "@ionic/cli": "^7.1.6", "@ngx-formly/core": "^6.3.0", "@ngx-formly/ionic": "^6.3.5", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", + "capacitor-blob-writer": "^1.1.14", + "capacitor-ios-autofill-save-password": "^2.0.0", + "capacitor-secure-storage-plugin": "^0.9.0", "chart.js": "^4.4.3", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", @@ -51,6 +64,8 @@ "@angular/compiler": "^16.2.12", "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", + "@capacitor/assets": "^3.0.0", + "@capacitor/cli": "5.2.3", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", @@ -122,9 +137,8 @@ }, "node_modules/@angular-devkit/build-angular": { "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.14.tgz", - "integrity": "sha512-bXQ6i7QPhwmYHuh+DSNkBhjTIHQF0C6fqZEg2ApJA3NmnzE98oQnmJ9AnGnAkdf1Mjn3xi2gxoZWPDDxGEINMw==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "2.2.1", "@angular-devkit/architect": "0.1602.14", @@ -256,9 +270,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { "version": "0.1602.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz", - "integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "16.2.14", "rxjs": "7.8.1" @@ -271,9 +284,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz", - "integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -298,9 +310,8 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/ajv": { "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -314,15 +325,13 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/source-map": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } @@ -632,9 +641,8 @@ }, "node_modules/@angular-devkit/build-webpack": { "version": "0.1602.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.14.tgz", - "integrity": "sha512-f+ZTCjOoA1SCQEaX3L/63ubqr/vlHkwDXAtKjBsQgyz6srnETcjy96Us5k/LoK7/hPc85zFneqLinfqOMVWHJQ==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/architect": "0.1602.14", "rxjs": "7.8.1" @@ -651,9 +659,8 @@ }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { "version": "0.1602.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1602.14.tgz", - "integrity": "sha512-eSdONEV5dbtLNiOMBy9Ue9DdJ1ct6dH9RdZfYiedq6VZn0lejePAjY36MYVXgq2jTE+v/uIiaNy7caea5pt55A==", "dev": true, + "license": "MIT", "dependencies": { "@angular-devkit/core": "16.2.14", "rxjs": "7.8.1" @@ -666,9 +673,8 @@ }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz", - "integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", @@ -693,15 +699,13 @@ }, "node_modules/@angular-devkit/build-webpack/node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -2833,578 +2837,719 @@ "node": ">=6.9.0" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "dev": true, + "node_modules/@capacitor-community/file-opener": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@capacitor-community/file-opener/-/file-opener-1.0.6.tgz", + "integrity": "sha512-iHsPblcgqTF8rEmvpVyAGfxuTUtV8BthoBv/zBLKEEb1vSUVONed0UTRjvvqjHxewS8LNEWVXzuMzXfQU1r1cA==", "license": "MIT", "engines": { - "node": ">=0.1.90" + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "peerDependencies": { + "@capacitor/core": "^5.0.0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "dev": true, + "node_modules/@capacitor/android": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.2.3.tgz", + "integrity": "sha512-TqXOq5RIniMACcAckn/X84XajPP2GU4VH7Er390Ja2Y2BWSeUKgk7T8aURcwLYu2hnv+Op9eTww5MTBb3zBtmg==", "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" + "peerDependencies": { + "@capacitor/core": "^5.2.0" } }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "dev": true, + "node_modules/@capacitor/app": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@capacitor/app/-/app-5.0.8.tgz", + "integrity": "sha512-ClUPJG6Awkf5HncVCZQwLrnuugjU8TnACSJ1dKJb6QNCHv2jQzmXvB3KvTvxTZyWbh5EVvlla0qlobYyU1lb6A==", "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "peerDependencies": { + "@capacitor/core": "^5.0.0" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "dev": true, - "license": "MIT", + "node_modules/@capacitor/assets": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@capacitor/assets/-/assets-3.0.5.tgz", + "integrity": "sha512-ohz/OUq61Y1Fc6aVSt0uDrUdeOA7oTH4pkWDbv/8I3UrPjH7oPkzYhShuDRUjekNp9RBi198VSFdt0CetpEOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@capacitor/cli": "^5.3.0", + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@trapezedev/project": "^7.0.10", + "commander": "8.3.0", + "debug": "4.3.4", + "fs-extra": "10.1.0", + "node-fetch": "2.7.0", + "node-html-parser": "5.4.2", + "sharp": "0.32.6", + "tslib": "2.6.2", + "yargs": "17.7.2" + }, + "bin": { + "capacitor-assets": "bin/capacitor-assets" + }, "engines": { - "node": ">=10.0.0" + "node": ">=10.3.0" } }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.42.0", + "node_modules/@capacitor/assets/node_modules/@capacitor/cli": { + "version": "5.7.6", + "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-5.7.6.tgz", + "integrity": "sha512-CDDcBF7wHm5v/j0dA2bls0vK954XlD1JCjMuTgLtjZMvWrIlTJAkwCQLkiqRhS2P63AXqfqQqkb/qs2RHc1zDQ==", "dev": true, "license": "MIT", "dependencies": { - "comment-parser": "1.4.1", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" + "@ionic/cli-framework-output": "^2.2.5", + "@ionic/utils-fs": "^3.1.6", + "@ionic/utils-subprocess": "^2.1.11", + "@ionic/utils-terminal": "^2.3.3", + "commander": "^9.3.0", + "debug": "^4.3.4", + "env-paths": "^2.2.0", + "kleur": "^4.1.4", + "native-run": "^2.0.0", + "open": "^8.4.0", + "plist": "^3.0.5", + "prompts": "^2.4.2", + "rimraf": "^4.4.1", + "semver": "^7.3.7", + "tar": "^6.1.11", + "tslib": "^2.4.0", + "xml2js": "^0.5.0" + }, + "bin": { + "cap": "bin/capacitor", + "capacitor": "bin/capacitor" }, "engines": { - "node": ">=16" + "node": ">=16.0.0" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.18.17", - "cpu": [ - "x64" - ], + "node_modules/@capacitor/assets/node_modules/@capacitor/cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": "^12.20.0 || >=14" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", + "node_modules/@capacitor/assets/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "balanced-match": "^1.0.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", + "node_modules/@capacitor/assets/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, "license": "MIT", "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">= 12" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", + "node_modules/@capacitor/assets/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", + "node_modules/@capacitor/assets/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", + "node_modules/@capacitor/assets/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, - "license": "Python-2.0" + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", + "node_modules/@capacitor/assets/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "type-fest": "^0.20.2" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", + "node_modules/@capacitor/assets/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/@capacitor/assets/node_modules/native-run": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.1.tgz", + "integrity": "sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "@ionic/utils-fs": "^3.1.7", + "@ionic/utils-terminal": "^2.3.4", + "bplist-parser": "^0.3.2", + "debug": "^4.3.4", + "elementtree": "^0.1.7", + "ini": "^4.1.1", + "plist": "^3.1.0", + "split2": "^4.2.0", + "through2": "^4.0.2", + "tslib": "^2.6.2", + "yauzl": "^2.10.0" }, "bin": { - "js-yaml": "bin/js-yaml.js" + "native-run": "bin/native-run" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", + "node_modules/@capacitor/assets/node_modules/rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "ISC", + "dependencies": { + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@eslint/js": { - "version": "8.57.0", + "node_modules/@capacitor/assets/node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 10.x" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", + "node_modules/@capacitor/assets/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", + "node_modules/@capacitor/assets/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=4.0.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", + "node_modules/@capacitor/cli": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-5.2.3.tgz", + "integrity": "sha512-iqjOnA9fCxm+cFv5iTvxb/vElK2Z1kDpVS+N9XyD2Msyv3l3ezuOZTSvABiDoo6w6CGkj4/AUMpdT4nrZkTHTg==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" + "license": "MIT", + "dependencies": { + "@ionic/cli-framework-output": "^2.2.5", + "@ionic/utils-fs": "^3.1.6", + "@ionic/utils-subprocess": "^2.1.11", + "@ionic/utils-terminal": "^2.3.3", + "commander": "^9.3.0", + "debug": "^4.3.4", + "env-paths": "^2.2.0", + "kleur": "^4.1.4", + "native-run": "^1.7.2", + "open": "^8.4.0", + "plist": "^3.0.5", + "prompts": "^2.4.2", + "rimraf": "^4.4.1", + "semver": "^7.3.7", + "tar": "^6.1.11", + "tslib": "^2.4.0", + "xml2js": "^0.5.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "bin": { + "cap": "bin/capacitor", + "capacitor": "bin/capacitor" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", + "node_modules/@capacitor/cli/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@ionic/angular": { - "version": "6.7.5", "license": "MIT", "dependencies": { - "@ionic/core": "6.7.5", - "ionicons": "^6.1.3", - "jsonc-parser": "^3.0.0", - "tslib": "^2.0.0" - }, - "peerDependencies": { - "@angular/core": ">=12.0.0", - "@angular/forms": ">=12.0.0", - "@angular/router": ">=12.0.0", - "rxjs": ">=6.6.0", - "zone.js": ">=0.11.0" + "balanced-match": "^1.0.0" } }, - "node_modules/@ionic/angular-toolkit": { - "version": "11.0.1", + "node_modules/@capacitor/cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true, "license": "MIT", - "dependencies": { - "@angular-devkit/core": "^17.0.0", - "@angular-devkit/schematics": "^17.0.0", - "@schematics/angular": "^17.0.0" + "engines": { + "node": "^12.20.0 || >=14" } }, - "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": { - "version": "17.3.3", + "node_modules/@capacitor/cli/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.1", - "picomatch": "4.0.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" + "node": ">=16 || 14 >=14.17" }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": { - "version": "17.3.3", + "node_modules/@capacitor/cli/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@angular-devkit/core": "17.3.3", - "jsonc-parser": "3.2.1", - "magic-string": "0.30.8", - "ora": "5.4.1", - "rxjs": "7.8.1" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": { - "version": "17.3.3", + "node_modules/@capacitor/cli/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "17.3.3", - "@angular-devkit/schematics": "17.3.3", - "jsonc-parser": "3.2.1" - }, + "license": "ISC", "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=8" } }, - "node_modules/@ionic/angular-toolkit/node_modules/magic-string": { - "version": "0.30.8", + "node_modules/@capacitor/cli/node_modules/rimraf": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "glob": "^9.2.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" }, "engines": { - "node": ">=12" - } - }, - "node_modules/@ionic/angular-toolkit/node_modules/picomatch": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@ionic/angular-toolkit/node_modules/rxjs": { - "version": "7.8.1", + "node_modules/@capacitor/cli/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "tslib": "^2.1.0" + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "node_modules/@ionic/core": { - "version": "6.7.5", + "node_modules/@capacitor/core": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.3.tgz", + "integrity": "sha512-Q1zbgt3Mvldy7six2/GX54kTL0ozgnR37jeDUAXL/fOJBF4Iorr/8A0OjGEAnwEjpR1la7uFZUunESMFyMLhEQ==", "license": "MIT", "dependencies": { - "@stencil/core": "^2.18.0", - "ionicons": "^6.1.3", "tslib": "^2.1.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" + "node_modules/@capacitor/filesystem": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-5.2.2.tgz", + "integrity": "sha512-h0Ta0NXF/zX9bXoD5qtoEoWSWCewow8Kredb2bBFO+vrd4NVthZH+GyrII2dk0++UIw40HjyLNk4apwGGSu9Sg==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^5.1.1" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "dev": true, + "node_modules/@capacitor/ios": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-5.2.3.tgz", + "integrity": "sha512-ailR/Mer48GEXdqip+ENyN3Qk+ZtUBNDTlHh83WLNbx6uv71z6lCeoLKBXdtSEBFwzFrwtCO5upzbdzK79pONQ==", "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "peerDependencies": { + "@capacitor/core": "^5.2.0" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "dev": true, + "node_modules/@capacitor/splash-screen": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@capacitor/splash-screen/-/splash-screen-5.0.8.tgz", + "integrity": "sha512-mDRJS9QFxL5UMN74gRr6cBhOtkZjWwdttPCjBJNgcMDJIGi9IAKRJuDGTsqSUbp6zWrPF4AW29Mu6qhXtHpHWg==", "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@capacitor/core": "^5.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", + "node_modules/@colors/colors": { + "version": "1.5.0", "dev": true, "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.1.90" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", + "node_modules/@es-joy/jsdoccomment": { + "version": "0.42.0", "dev": true, "license": "MIT", + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, "engines": { - "node": ">=8" + "node": ">=16" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=6.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", "dev": true, "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", "dev": true, "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=6.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", "dev": true, - "license": "MIT" + "license": "Python-2.0" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@kurkle/color": { - "version": "0.3.2", + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, "license": "MIT" }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@ngtools/webpack": { - "version": "16.2.14", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-16.2.14.tgz", - "integrity": "sha512-3+zPP3Wir46qrZ3FEiTz5/emSoVHYUCH+WgBmJ57mZCx1qBOYh2VgllnPr/Yusl1sc/jUZjdwq/es/9ZNw+zDQ==", + "node_modules/@eslint/js": { + "version": "8.57.0", "dev": true, + "license": "MIT", "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@hutson/parse-repository-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", + "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ionic-native/core": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/@ionic-native/core/-/core-5.36.0.tgz", + "integrity": "sha512-lOrkktadlKYbYf1LrDyAtsu1JnQ0oCCdkOU7iHQ8oXnNOkMwobFfD2m62F1CoOr0u9LIkpYnZSPjng8lZbmbNw==", + "license": "MIT", + "dependencies": { + "@types/cordova": "latest" }, "peerDependencies": { - "@angular/compiler-cli": "^16.0.0", - "typescript": ">=4.9.3 <5.2", - "webpack": "^5.54.0" + "rxjs": "^5.5.0 || ^6.5.0" } }, - "node_modules/@ngx-formly/core": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.5.tgz", - "integrity": "sha512-9p4yl7fr2Ojmm/uN7/nM1hYezheUxecEC0WZ0YI6jeSoEJR8NYTglVxTmHrpW5had2oolHeO39sAo9ttJNifSA==", + "node_modules/@ionic-native/file-opener": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/@ionic-native/file-opener/-/file-opener-5.36.0.tgz", + "integrity": "sha512-UKp3pbqvQXsAtLMJ5JE+KcTMxpjSZMFebf6nvy/KJvwy85JGIaCV4ZVM/H9CFUrHJMWBH6wDbY+WPygnsrl4Yg==", + "license": "MIT", "dependencies": { - "tslib": "^2.0.0" + "@types/cordova": "latest" }, "peerDependencies": { - "@angular/forms": ">=13.2.0", - "rxjs": "^6.5.3 || ^7.0.0" + "@ionic-native/core": "^5.1.0", + "rxjs": "^5.5.0 || ^6.5.0" } }, - "node_modules/@ngx-formly/ionic": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.5.tgz", - "integrity": "sha512-WqcsG9YXr9PZdWOV+DVT++2cHrndMabRNlOOHx+VIf8QXQc1cyxq9UWW3CmBKw5lT1P2cy4cxxuKMk4EzNJV+Q==", + "node_modules/@ionic/angular": { + "version": "6.7.5", + "license": "MIT", "dependencies": { + "@ionic/core": "6.7.5", + "ionicons": "^6.1.3", + "jsonc-parser": "^3.0.0", "tslib": "^2.0.0" }, "peerDependencies": { - "@ionic/angular": "^6.0.0 || ^7.0.0", - "@ngx-formly/core": "6.3.5" + "@angular/core": ">=12.0.0", + "@angular/forms": ">=12.0.0", + "@angular/router": ">=12.0.0", + "rxjs": ">=6.6.0", + "zone.js": ">=0.11.0" } }, - "node_modules/@ngx-formly/schematics": { - "version": "6.3.0", + "node_modules/@ionic/angular-toolkit": { + "version": "11.0.1", + "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "^13.0.3", - "@angular-devkit/schematics": "^13.0.3", - "@schematics/angular": "^13.0.3" + "@angular-devkit/core": "^17.0.0", + "@angular-devkit/schematics": "^17.0.0", + "@schematics/angular": "^17.0.0" } }, - "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/core": { - "version": "13.3.11", + "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": { + "version": "17.3.3", + "dev": true, "license": "MIT", "dependencies": { - "ajv": "8.9.0", + "ajv": "8.12.0", "ajv-formats": "2.1.1", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.7", - "source-map": "0.7.3" + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "node": "^18.13.0 || >=20.9.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, @@ -3417,879 +3562,2493 @@ } } }, - "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/schematics": { - "version": "13.3.11", + "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": { + "version": "17.3.3", + "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "13.3.11", - "jsonc-parser": "3.0.0", - "magic-string": "0.25.7", + "@angular-devkit/core": "17.3.3", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.8", "ora": "5.4.1", - "rxjs": "6.6.7" + "rxjs": "7.8.1" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "node": "^18.13.0 || >=20.9.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, - "node_modules/@ngx-formly/schematics/node_modules/@schematics/angular": { - "version": "13.3.11", + "node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": { + "version": "17.3.3", + "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "13.3.11", - "@angular-devkit/schematics": "13.3.11", - "jsonc-parser": "3.0.0" + "@angular-devkit/core": "17.3.3", + "@angular-devkit/schematics": "17.3.3", + "jsonc-parser": "3.2.1" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "node": "^18.13.0 || >=20.9.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, - "node_modules/@ngx-formly/schematics/node_modules/ajv": { - "version": "8.9.0", + "node_modules/@ionic/angular-toolkit/node_modules/magic-string": { + "version": "0.30.8", + "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "@jridgewell/sourcemap-codec": "^1.4.15" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=12" } }, - "node_modules/@ngx-formly/schematics/node_modules/jsonc-parser": { - "version": "3.0.0", - "license": "MIT" - }, - "node_modules/@ngx-formly/schematics/node_modules/magic-string": { - "version": "0.25.7", + "node_modules/@ionic/angular-toolkit/node_modules/picomatch": { + "version": "4.0.1", + "dev": true, "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@ionic/angular-toolkit/node_modules/rxjs": { + "version": "7.8.1", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "sourcemap-codec": "^1.4.4" + "tslib": "^2.1.0" } }, - "node_modules/@ngx-formly/schematics/node_modules/source-map": { - "version": "0.7.3", - "license": "BSD-3-Clause", + "node_modules/@ionic/cli": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@ionic/cli/-/cli-7.2.0.tgz", + "integrity": "sha512-IEms9Df8mJOoWPqgvZEXmqKztttHDFAz+9ewDPZGYv8Xx66Cj7zSen13O2Vf4FuLXhl+U95HXT9sAs4lDwFmcQ==", + "license": "MIT", + "dependencies": { + "@ionic/cli-framework": "6.0.1", + "@ionic/cli-framework-output": "2.2.8", + "@ionic/cli-framework-prompts": "2.1.13", + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-network": "2.1.7", + "@ionic/utils-process": "2.1.12", + "@ionic/utils-stream": "3.1.7", + "@ionic/utils-subprocess": "3.0.1", + "@ionic/utils-terminal": "2.3.5", + "chalk": "^4.0.0", + "debug": "^4.0.0", + "diff": "^4.0.1", + "elementtree": "^0.1.7", + "leek": "0.0.24", + "lodash": "^4.17.5", + "open": "^7.0.4", + "os-name": "^4.0.0", + "proxy-agent": "^6.3.0", + "semver": "^7.1.1", + "split2": "^3.0.0", + "ssh-config": "^1.1.1", + "stream-combiner2": "^1.1.1", + "superagent": "^8.0.9", + "tar": "^6.0.1", + "tslib": "^2.0.1" + }, + "bin": { + "ionic": "bin/ionic" + }, "engines": { - "node": ">= 8" + "node": ">=16.0.0" } }, - "node_modules/@ngx-translate/core": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-15.0.0.tgz", - "integrity": "sha512-Am5uiuR0bOOxyoercDnAA3rJVizo4RRqJHo8N3RqJ+XfzVP/I845yEnMADykOHvM6HkVm4SZSnJBOiz0Anx5BA==", - "engines": { - "node": "^16.13.0 || >=18.10.0" + "node_modules/@ionic/cli-framework": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@ionic/cli-framework/-/cli-framework-6.0.1.tgz", + "integrity": "sha512-Fyix4eQt2HKTV+GoeoiziQGZyqIA8RfoMqjGyAS5XgNXLOYW0P27Ph348hQZh9Mphjf+m0lOYa6dWQTEPzUHiQ==", + "license": "MIT", + "dependencies": { + "@ionic/cli-framework-output": "2.2.8", + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-object": "2.1.6", + "@ionic/utils-process": "2.1.12", + "@ionic/utils-stream": "3.1.7", + "@ionic/utils-subprocess": "3.0.1", + "@ionic/utils-terminal": "2.3.5", + "chalk": "^4.0.0", + "debug": "^4.0.0", + "lodash": "^4.17.5", + "minimist": "^1.2.0", + "rimraf": "^3.0.0", + "tslib": "^2.0.1", + "write-file-atomic": "^3.0.0" }, - "peerDependencies": { - "@angular/common": ">=16.0.0", - "@angular/core": ">=16.0.0", - "rxjs": "^6.5.5 || ^7.4.0" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, + "node_modules/@ionic/cli-framework-output": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ionic/cli-framework-output/-/cli-framework-output-2.2.8.tgz", + "integrity": "sha512-TshtaFQsovB4NWRBydbNFawql6yul7d5bMiW1WYYf17hd99V6xdDdk3vtF51bw6sLkxON3bDQpWsnUc9/hVo3g==", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@ionic/utils-terminal": "2.3.5", + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": ">= 8" + "node": ">=16.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, + "node_modules/@ionic/cli-framework-prompts": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/@ionic/cli-framework-prompts/-/cli-framework-prompts-2.1.13.tgz", + "integrity": "sha512-Yj1fz6p7OehreQ8C70bd9+M6tYP/rvzLw5JVj8pT/N9s0kQSjqEFRbs96LKr3lfd3TADZaS8OlZrQIqenFIUpg==", "license": "MIT", + "dependencies": { + "@ionic/utils-terminal": "2.3.5", + "debug": "^4.0.0", + "inquirer": "^7.0.0", + "tslib": "^2.0.1" + }, "engines": { - "node": ">= 8" + "node": ">=16.0.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, + "node_modules/@ionic/cli-framework-prompts/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@nodro7/angular-mydatepicker": { - "version": "0.14.0", + "node_modules/@ionic/cli-framework-prompts/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "dependencies": { - "tslib": "^2.0.0" - } - }, - "node_modules/@npmcli/fs": { - "version": "3.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@npmcli/git": { - "version": "4.1.0", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework-prompts/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { - "@npmcli/promise-spawn": "^6.0.0", - "lru-cache": "^7.4.4", - "npm-pick-manifest": "^8.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^3.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=7.0.0" } }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "7.18.3", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework-prompts/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "3.0.1", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework-prompts/node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8.0.0" } }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework-prompts/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "lib/index.js" + "has-flag": "^4.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "dev": true, + "node_modules/@ionic/cli-framework/node_modules/@ionic/utils-subprocess": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-3.0.1.tgz", + "integrity": "sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A==", "license": "MIT", "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-process": "2.1.12", + "@ionic/utils-stream": "3.1.7", + "@ionic/utils-terminal": "2.3.5", + "cross-spawn": "^7.0.3", + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@npmcli/promise-spawn": { - "version": "6.0.2", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { - "which": "^3.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "3.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" + "node": ">=8" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@npmcli/run-script": { - "version": "6.0.2", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/promise-spawn": "^6.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^3.0.0", - "which": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "3.0.1", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli-framework/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" + "color-name": "~1.1.4" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=7.0.0" } }, - "node_modules/@nrwl/devkit": { - "version": "16.5.1", - "dev": true, + "node_modules/@ionic/cli-framework/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "dependencies": { - "@nx/devkit": "16.5.1" + "engines": { + "node": ">=8" } }, - "node_modules/@nrwl/tao": { - "version": "16.5.1", - "dev": true, + "node_modules/@ionic/cli-framework/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", "dependencies": { - "nx": "16.5.1" + "has-flag": "^4.0.0" }, - "bin": { - "tao": "index.js" + "engines": { + "node": ">=8" } }, - "node_modules/@nx/devkit": { - "version": "16.5.1", - "dev": true, + "node_modules/@ionic/cli/node_modules/@ionic/utils-subprocess": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-3.0.1.tgz", + "integrity": "sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A==", "license": "MIT", "dependencies": { - "@nrwl/devkit": "16.5.1", - "ejs": "^3.1.7", - "ignore": "^5.0.4", - "semver": "7.5.3", - "tmp": "~0.2.1", - "tslib": "^2.3.0" + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-process": "2.1.12", + "@ionic/utils-stream": "3.1.7", + "@ionic/utils-terminal": "2.3.5", + "cross-spawn": "^7.0.3", + "debug": "^4.0.0", + "tslib": "^2.0.1" }, - "peerDependencies": { - "nx": ">= 15 <= 17" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@nx/devkit/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@nx/devkit/node_modules/semver": { - "version": "7.5.3", - "dev": true, - "license": "ISC", + "node_modules/@ionic/cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@nx/devkit/node_modules/tmp": { - "version": "0.2.3", - "dev": true, + "node_modules/@ionic/cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=14.14" + "node": ">=7.0.0" } }, - "node_modules/@nx/devkit/node_modules/yallist": { + "node_modules/@ionic/cli/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/@nx/nx-linux-x64-gnu": { - "version": "16.5.1", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-x64-musl": { - "version": "16.5.1", - "cpu": [ - "x64" - ], - "dev": true, + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/@parcel/watcher": { - "version": "2.0.4", - "dev": true, - "hasInstallScript": true, + "node_modules/@ionic/cli/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "license": "MIT", "dependencies": { - "node-addon-api": "^3.2.1", - "node-gyp-build": "^4.3.0" + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" }, "engines": { - "node": ">= 10.0.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "dev": true, + "node_modules/@ionic/cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "optional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=14" + "node": ">=8" } }, - "node_modules/@schematics/angular": { - "version": "16.2.13", - "dev": true, + "node_modules/@ionic/core": { + "version": "6.7.5", "license": "MIT", "dependencies": { - "@angular-devkit/core": "16.2.13", - "@angular-devkit/schematics": "16.2.13", - "jsonc-parser": "3.2.0" + "@stencil/core": "^2.18.0", + "ionicons": "^6.1.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@ionic/utils-array": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.6.tgz", + "integrity": "sha512-0JZ1Zkp3wURnv8oq6Qt7fMPo5MpjbLoUoa9Bu2Q4PJuSDWM8H8gwF3dQO7VTeUj3/0o1IB1wGkFWZZYgUXZMUg==", + "license": "MIT", + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": "^16.14.0 || >=18.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=16.0.0" } }, - "node_modules/@schematics/angular/node_modules/jsonc-parser": { - "version": "3.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@sigstore/bundle": { - "version": "1.1.0", - "dev": true, - "license": "Apache-2.0", + "node_modules/@ionic/utils-fs": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.7.tgz", + "integrity": "sha512-2EknRvMVfhnyhL1VhFkSLa5gOcycK91VnjfrTB0kbqkTFCOXyXgVLI5whzq7SLrgD9t1aqos3lMMQyVzaQ5gVA==", + "license": "MIT", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0" + "@types/fs-extra": "^8.0.0", + "debug": "^4.0.0", + "fs-extra": "^9.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", - "dev": true, - "license": "Apache-2.0", + "node_modules/@ionic/utils-fs/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" } }, - "node_modules/@sigstore/sign": { - "version": "1.0.0", - "dev": true, - "license": "Apache-2.0", + "node_modules/@ionic/utils-fs/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", "dependencies": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "make-fetch-happen": "^11.0.1" + "universalify": "^2.0.0" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/@sigstore/sign/node_modules/@tootallnate/once": { - "version": "2.0.0", - "dev": true, + "node_modules/@ionic/utils-fs/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "license": "MIT", "engines": { - "node": ">= 10" + "node": ">= 10.0.0" } }, - "node_modules/@sigstore/sign/node_modules/http-proxy-agent": { - "version": "5.0.0", - "dev": true, + "node_modules/@ionic/utils-network": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@ionic/utils-network/-/utils-network-2.1.7.tgz", + "integrity": "sha512-5Q3NdZtSLiLs7ufuX9X293BvAwo8CxaD93Hkp3ODPgctLYErv3nFibhq3j+eguEqUh2um9WNXEUOuQ8x+Sd1fw==", "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": ">= 6" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/sign/node_modules/lru-cache": { - "version": "7.18.3", - "dev": true, - "license": "ISC", + "node_modules/@ionic/utils-object": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.6.tgz", + "integrity": "sha512-vCl7sl6JjBHFw99CuAqHljYJpcE88YaH2ZW4ELiC/Zwxl5tiwn4kbdP/gxi2OT3MQb1vOtgAmSNRtusvgxI8ww==", + "license": "MIT", + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, "engines": { - "node": ">=12" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { - "version": "11.1.1", - "dev": true, - "license": "ISC", + "node_modules/@ionic/utils-process": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.12.tgz", + "integrity": "sha512-Jqkgyq7zBs/v/J3YvKtQQiIcxfJyplPgECMWgdO0E1fKrrH8EF0QGHNJ9mJCn6PYe2UtHNS8JJf5G21e09DfYg==", + "license": "MIT", "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" + "@ionic/utils-object": "2.1.6", + "@ionic/utils-terminal": "2.3.5", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "tree-kill": "^1.2.2", + "tslib": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/sign/node_modules/minipass-fetch": { - "version": "3.0.4", - "dev": true, + "node_modules/@ionic/utils-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.7.tgz", + "integrity": "sha512-eSELBE7NWNFIHTbTC2jiMvh1ABKGIpGdUIvARsNPMNQhxJB3wpwdiVnoBoTYp+5a6UUIww4Kpg7v6S7iTctH1w==", "license": "MIT", "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", + "node_modules/@ionic/utils-subprocess": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.14.tgz", + "integrity": "sha512-nGYvyGVjU0kjPUcSRFr4ROTraT3w/7r502f5QJEsMRKTqa4eEzCshtwRk+/mpASm0kgBN5rrjYA5A/OZg8ahqg==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "@ionic/utils-array": "2.1.6", + "@ionic/utils-fs": "3.1.7", + "@ionic/utils-process": "2.1.11", + "@ionic/utils-stream": "3.1.6", + "@ionic/utils-terminal": "2.3.4", + "cross-spawn": "^7.0.3", + "debug": "^4.0.0", + "tslib": "^2.0.1" + }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16.0.0" } }, - "node_modules/@sigstore/tuf": { - "version": "1.0.3", + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-process": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.11.tgz", + "integrity": "sha512-Uavxn+x8j3rDlZEk1X7YnaN6wCgbCwYQOeIjv/m94i1dzslqWhqIHEqxEyeE8HsT5Negboagg7GtQiABy+BLbA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0", - "tuf-js": "^1.1.7" + "@ionic/utils-object": "2.1.6", + "@ionic/utils-terminal": "2.3.4", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "tree-kill": "^1.2.2", + "tslib": "^2.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=16.0.0" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.0", + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.6.tgz", + "integrity": "sha512-4+Kitey1lTA1yGtnigeYNhV/0tggI3lWBMjC7tBs1K9GXa/q7q4CtOISppdh8QgtOhrhAXS2Igp8rbko/Cj+lA==", "dev": true, - "license": "MIT" - }, - "node_modules/@stencil/core": { - "version": "2.22.3", "license": "MIT", - "bin": { - "stencil": "bin/stencil" + "dependencies": { + "debug": "^4.0.0", + "tslib": "^2.0.1" }, "engines": { - "node": ">=12.10.0", - "npm": ">=6.0.0" + "node": ">=16.0.0" } }, - "node_modules/@stylistic/eslint-plugin": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.2.2.tgz", - "integrity": "sha512-GNRtyhhPsc9I9FNTaU2L0V/4LdSPAciQNEdYo6NBRdAz7sdiaxgEJKLNSXeXSQAuO9JBWWjZBs/57+WvrU0Iug==", + "node_modules/@ionic/utils-subprocess/node_modules/@ionic/utils-terminal": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.4.tgz", + "integrity": "sha512-cEiMFl3jklE0sW60r8JHH3ijFTwh/jkdEKWbylSyExQwZ8pPuwoXz7gpkWoJRLuoRHHSvg+wzNYyPJazIHfoJA==", "dev": true, + "license": "MIT", "dependencies": { - "@stylistic/eslint-plugin-js": "2.2.2", - "@stylistic/eslint-plugin-jsx": "2.2.2", - "@stylistic/eslint-plugin-plus": "2.2.2", - "@stylistic/eslint-plugin-ts": "2.2.2", - "@types/eslint": "^8.56.10" + "@types/slice-ansi": "^4.0.0", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "slice-ansi": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "tslib": "^2.0.1", + "untildify": "^4.0.0", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=16.0.0" + } + }, + "node_modules/@ionic/utils-terminal": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.5.tgz", + "integrity": "sha512-3cKScz9Jx2/Pr9ijj1OzGlBDfcmx7OMVBt4+P1uRR0SSW4cm1/y3Mo4OY3lfkuaYifMNBW8Wz6lQHbs1bihr7A==", + "license": "MIT", + "dependencies": { + "@types/slice-ansi": "^4.0.0", + "debug": "^4.0.0", + "signal-exit": "^3.0.3", + "slice-ansi": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "tslib": "^2.0.1", + "untildify": "^4.0.0", + "wrap-ansi": "^7.0.0" }, - "peerDependencies": { - "eslint": ">=8.40.0" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.2.2.tgz", - "integrity": "sha512-Vj2Q1YHVvJw+ThtOvmk5Yx7wZanVrIBRUTT89horLDb4xdP9GA1um9XOYQC6j67VeUC2gjZQnz5/RVJMzaOhtw==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", "dev": true, + "license": "ISC", "dependencies": { - "@types/eslint": "^8.56.10", - "acorn": "^8.11.3", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.0.1" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" + "node": ">=12" } }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", "dev": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@stylistic/eslint-plugin-jsx": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.2.2.tgz", - "integrity": "sha512-xfIMdLivoMV1wV+5Tl0PtkLN/oUwjIt7LuIu48vhrZfJ2jCXwjlTGPGSoM7dnLZYD65XjtrHHIFAvPuvvvjlaw==", + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", "dev": true, + "license": "MIT", "dependencies": { - "@stylistic/eslint-plugin-js": "^2.2.2", - "@types/eslint": "^8.56.10", - "estraverse": "^5.3.0", - "picomatch": "^4.0.2" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-jsx/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@stylistic/eslint-plugin-plus": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.2.2.tgz", - "integrity": "sha512-oeqPs01yAH4ad4bSchGtx8Jf5XTbxRx++A0joNYiOoq3EBTAUHE/ZB7dVv3BhNuCKiwojOQduLkUCXI5UMHoSw==", + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, - "peerDependencies": { - "eslint": "*" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", - "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", "dev": true, + "license": "ISC", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "license": "MIT" + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@ngtools/webpack": { + "version": "16.2.14", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^16.0.0", + "typescript": ">=4.9.3 <5.2", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-formly/core": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.5.tgz", + "integrity": "sha512-9p4yl7fr2Ojmm/uN7/nM1hYezheUxecEC0WZ0YI6jeSoEJR8NYTglVxTmHrpW5had2oolHeO39sAo9ttJNifSA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/forms": ">=13.2.0", + "rxjs": "^6.5.3 || ^7.0.0" + } + }, + "node_modules/@ngx-formly/ionic": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.5.tgz", + "integrity": "sha512-WqcsG9YXr9PZdWOV+DVT++2cHrndMabRNlOOHx+VIf8QXQc1cyxq9UWW3CmBKw5lT1P2cy4cxxuKMk4EzNJV+Q==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@ionic/angular": "^6.0.0 || ^7.0.0", + "@ngx-formly/core": "6.3.5" + } + }, + "node_modules/@ngx-formly/schematics": { + "version": "6.3.0", + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "^13.0.3", + "@angular-devkit/schematics": "^13.0.3", + "@schematics/angular": "^13.0.3" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/core": { + "version": "13.3.11", + "license": "MIT", + "dependencies": { + "ajv": "8.9.0", + "ajv-formats": "2.1.1", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.6.7", + "source-map": "0.7.3" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@ngx-formly/schematics/node_modules/@angular-devkit/schematics": { + "version": "13.3.11", + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "13.3.11", + "jsonc-parser": "3.0.0", + "magic-string": "0.25.7", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/@schematics/angular": { + "version": "13.3.11", + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "13.3.11", + "@angular-devkit/schematics": "13.3.11", + "jsonc-parser": "3.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/ajv": { + "version": "8.9.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", - "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "node_modules/@ngx-formly/schematics/node_modules/jsonc-parser": { + "version": "3.0.0", + "license": "MIT" + }, + "node_modules/@ngx-formly/schematics/node_modules/magic-string": { + "version": "0.25.7", + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/@ngx-formly/schematics/node_modules/source-map": { + "version": "0.7.3", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@ngx-translate/core": { + "version": "15.0.0", + "license": "SEE LICENSE IN LICENSE", + "engines": { + "node": "^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0", + "rxjs": "^6.5.5 || ^7.4.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodro7/angular-mydatepicker": { + "version": "0.14.0", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@nrwl/devkit": { + "version": "16.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@nx/devkit": "16.5.1" + } + }, + "node_modules/@nrwl/tao": { + "version": "16.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "nx": "16.5.1" + }, + "bin": { + "tao": "index.js" + } + }, + "node_modules/@nx/devkit": { + "version": "16.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@nrwl/devkit": "16.5.1", + "ejs": "^3.1.7", + "ignore": "^5.0.4", + "semver": "7.5.3", + "tmp": "~0.2.1", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "nx": ">= 15 <= 17" + } + }, + "node_modules/@nx/devkit/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/semver": { + "version": "7.5.3", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/tmp": { + "version": "0.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@nx/devkit/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@parcel/watcher": { + "version": "2.0.4", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^3.2.1", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@prettier/plugin-xml": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.2.0.tgz", + "integrity": "sha512-UWRmygBsyj4bVXvDiqSccwT1kmsorcwQwaIy30yVh8T+Gspx4OlC0shX1y+ZuwXZvgnafmpRYKks0bAu9urJew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xml-tools/parser": "^1.0.11", + "prettier": ">=2.4.0" + } + }, + "node_modules/@schematics/angular": { + "version": "16.2.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "16.2.13", + "@angular-devkit/schematics": "16.2.13", + "jsonc-parser": "3.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@schematics/angular/node_modules/jsonc-parser": { + "version": "3.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@sigstore/bundle": { + "version": "1.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "1.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign/node_modules/@tootallnate/once": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@sigstore/sign/node_modules/http-proxy-agent": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@sigstore/sign/node_modules/lru-cache": { + "version": "7.18.3", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { + "version": "11.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign/node_modules/minipass-fetch": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@sigstore/sign/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@sigstore/tuf": { + "version": "1.0.3", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@stencil/core": { + "version": "2.22.3", + "license": "MIT", + "bin": { + "stencil": "bin/stencil" + }, + "engines": { + "node": ">=12.10.0", + "npm": ">=6.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.3.0.tgz", + "integrity": "sha512-rtiz6u5gRyyEZp36FcF1/gHJbsbT3qAgXZ1qkad6Nr/xJ9wrSJkiSFFQhpYVTIZ7FJNRJurEcumZDCwN9dEI4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stylistic/eslint-plugin-js": "2.3.0", + "@stylistic/eslint-plugin-jsx": "2.3.0", + "@stylistic/eslint-plugin-plus": "2.3.0", + "@stylistic/eslint-plugin-ts": "2.3.0", + "@types/eslint": "^8.56.10" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.3.0.tgz", + "integrity": "sha512-lQwoiYb0Fs6Yc5QS3uT8+T9CPKK2Eoxc3H8EnYJgM26v/DgtW+1lvy2WNgyBflU+ThShZaHm3a6CdD9QeKx23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "^8.56.10", + "acorn": "^8.11.3", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.3.0.tgz", + "integrity": "sha512-tsQ0IEKB195H6X9A4iUSgLLLKBc8gUBWkBIU8tp1/3g2l8stu+PtMQVV/VmK1+3bem5FJCyvfcZIQ/WF1fsizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stylistic/eslint-plugin-js": "^2.3.0", + "@types/eslint": "^8.56.10", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@stylistic/eslint-plugin-plus": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.3.0.tgz", + "integrity": "sha512-xboPWGUU5yaPlR+WR57GwXEuY4PSlPqA0C3IdNA/+1o2MuBi95XgDJcZiJ9N+aXsqBXAPIpFFb+WQ7QEHo4f7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "^8.56.10", + "@typescript-eslint/utils": "^7.12.0" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/scope-manager": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/types": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@stylistic/eslint-plugin-plus/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@stylistic/eslint-plugin-ts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.3.0.tgz", + "integrity": "sha512-wqOR38/uz/0XPnHX68ftp8sNMSAqnYGjovOTN7w00xnjS6Lxr3Sk7q6AaxWWqbMvOj7V2fQiMC5HWAbTruJsCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stylistic/eslint-plugin-js": "2.3.0", + "@types/eslint": "^8.56.10", + "@typescript-eslint/utils": "^7.12.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.14.1", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@stylistic/eslint-plugin-ts/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, + "node_modules/@trapezedev/gradle-parse": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@trapezedev/gradle-parse/-/gradle-parse-7.0.10.tgz", + "integrity": "sha512-k822Is3jGroqOTKF0gAFm80LmhFJWBAyZvNtyuXq6uQUzDDe2fj/gHwixP6VFzlpaWKLP7IuR609Xv8gwJCXyg==", + "dev": true, + "license": "SEE LICENSE" + }, + "node_modules/@trapezedev/project": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@trapezedev/project/-/project-7.0.10.tgz", + "integrity": "sha512-UjwsStjhHq/+D1bWREmFDoyKql+qFIgJX93zQLg7R6CyWZUdtlGP2hU3l7tsVRtjJBVXpVu5mj8tdwJJoABO3A==", + "dev": true, + "license": "SEE LICENSE", + "dependencies": { + "@ionic/utils-fs": "^3.1.5", + "@ionic/utils-subprocess": "^2.1.8", + "@prettier/plugin-xml": "^2.2.0", + "@trapezedev/gradle-parse": "7.0.10", + "@xmldom/xmldom": "^0.7.5", + "conventional-changelog": "^3.1.4", + "cross-fetch": "^3.1.5", + "cross-spawn": "^7.0.3", + "diff": "^5.1.0", + "env-paths": "^3.0.0", + "gradle-to-js": "^2.0.0", + "ini": "^2.0.0", + "kleur": "^4.1.5", + "lodash": "^4.17.21", + "mergexml": "^1.2.3", + "npm-watch": "^0.9.0", + "plist": "^3.0.4", + "prettier": "^2.7.1", + "prompts": "^2.4.2", + "replace": "^1.1.0", + "tempy": "^1.0.1", + "tmp": "^0.2.1", + "ts-node": "^10.2.1", + "xcode": "^3.0.1", + "xml-js": "^1.6.11", + "xpath": "^0.0.32", + "yargs": "^17.2.1" + } + }, + "node_modules/@trapezedev/project/node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/@trapezedev/project/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@trapezedev/project/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/@trapezedev/project/node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cordova": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-11.0.3.tgz", + "integrity": "sha512-kyuRQ40/NWQVhqGIHq78Ehu2Bf9Mlg0LhmSmis6ZFJK7z933FRfYi8tHe/k/0fB+PGfCf95rJC6TO7dopaFvAg==", + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.21", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", + "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "4.3.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jasminewd2": { + "version": "2.0.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jasmine": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.12.7", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/q": { + "version": "0.0.32", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/selenium-webdriver": { + "version": "3.0.26", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==", + "license": "MIT" + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", - "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "6.21.0", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1" + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", - "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@stylistic/eslint-plugin-plus/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.2.2.tgz", - "integrity": "sha512-n6cYMSWTDDcrQLLxEKIrL/ihQ1lyyq6+gGp0g5VdstBElmImSRsQkCq+g3jRoDJIUo7tGO9lwQtGnuJ7oGB4kg==", - "dev": true, - "dependencies": { - "@stylistic/eslint-plugin-js": "2.2.2", - "@types/eslint": "^8.56.10", - "@typescript-eslint/utils": "^7.12.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/scope-manager": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", - "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1" + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", - "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", - "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -4301,59 +6060,100 @@ } } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, - "peerDependencies": { - "eslint": "^8.56.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", - "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "node_modules/@typescript-eslint/type-utils/node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.14.1", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/brace-expansion": { + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/globby": { + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -4369,11 +6169,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4384,1566 +6183,1608 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@stylistic/eslint-plugin-ts/node_modules/slash": { + "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", "dev": true, "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=8" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@tufjs/canonical-json": { - "version": "1.0.0", + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", "dev": true, "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@tufjs/models": { - "version": "1.0.4", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", "dev": true, "license": "MIT", "dependencies": { - "@tufjs/canonical-json": "1.0.0", - "minimatch": "^9.0.0" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "2.0.1", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.4", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", "dev": true, - "license": "ISC", + "license": "BSD-2-Clause", "dependencies": { - "brace-expansion": "^2.0.1" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", - "dev": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/cors": { - "version": "2.8.17", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", + "node_modules/@typescript-eslint/utils/node_modules/globby": { + "version": "11.1.0", "dev": true, "license": "MIT", "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@types/estree": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "node_modules/@typescript-eslint/utils/node_modules/slash": { + "version": "3.0.0", "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", - "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", - "dev": true, - "dependencies": { - "@types/node": "*" - } + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "dev": true, + "license": "ISC" }, - "node_modules/@types/jasmine": { - "version": "4.3.6", + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.0.1", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0" + } }, - "node_modules/@types/jasminewd2": { - "version": "2.0.13", + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", "dev": true, "license": "MIT", "dependencies": { - "@types/jasmine": "*" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", "dev": true, "license": "MIT" }, - "node_modules/@types/json5": { - "version": "0.0.29", + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", "dev": true, "license": "MIT" }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.12.7", + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } + "license": "MIT" }, - "node_modules/@types/node-forge": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" } }, - "node_modules/@types/q": { - "version": "0.0.32", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true - }, - "node_modules/@types/selenium-webdriver": { - "version": "3.0.26", + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", "dev": true, "license": "MIT" }, - "node_modules/@types/semver": { - "version": "7.5.8", + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", "dev": true, + "license": "MIT", "dependencies": { - "@types/mime": "^1", - "@types/node": "*" + "@xtuc/ieee754": "^1.2.0" } }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@types/express": "*" + "@xtuc/long": "4.2.2" } }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, - "node_modules/@types/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", - "dev": true - }, - "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "6.21.0", + "node_modules/@wessberg/ts-evaluator": { + "version": "0.0.27", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "chalk": "^4.1.0", + "jsdom": "^16.4.0", + "object-path": "^0.11.5", + "tslib": "^2.0.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=10.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/wessberg/ts-evaluator?sponsor=1" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "typescript": ">=3.2.x || >= 4.x" } }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", + "node_modules/@wessberg/ts-evaluator/node_modules/ansi-styles": { + "version": "4.3.0", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" + "color-convert": "^2.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", + "node_modules/@wessberg/ts-evaluator/node_modules/chalk": { + "version": "4.1.2", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", + "node_modules/@wessberg/ts-evaluator/node_modules/color-convert": { + "version": "2.0.1", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" + "color-name": "~1.1.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=7.0.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.62.0", + "node_modules/@wessberg/ts-evaluator/node_modules/has-flag": { + "version": "4.0.0", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8" + } + }, + "node_modules/@wessberg/ts-evaluator/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">=8" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", + "node_modules/@xml-tools/parser": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz", + "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "chevrotain": "7.1.1" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz", + "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@yarnpkg/parsers": { + "version": "3.0.0-rc.46", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "js-yaml": "^3.10.0", + "tslib": "^2.4.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=14.15.0" + } + }, + "node_modules/@zkochan/js-yaml": { + "version": "0.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", + "node_modules/@zkochan/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/abab": { + "version": "2.0.6", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/accepts": { + "version": "1.3.8", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/globby": { - "version": "11.1.0", + "node_modules/acorn-globals": { + "version": "6.0.0", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/slash": { - "version": "3.0.0", + "node_modules/acorn-globals/node_modules/acorn-walk": { + "version": "7.2.0", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", + "node_modules/acorn-import-assertions": { + "version": "1.9.0", "dev": true, "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "acorn": "^8" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", + "node_modules/acorn-jsx": { + "version": "5.3.2", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", + "node_modules/acorn-walk": { + "version": "8.3.1", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { - "version": "11.1.0", + "node_modules/add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8.9" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8.9.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { - "version": "3.0.0", + "node_modules/adm-zip": { + "version": "0.5.12", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6.0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", + "node_modules/agent-base": { + "version": "6.0.2", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "debug": "4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node": ">= 6.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", + "node_modules/agentkeepalive": { + "version": "4.5.0", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "humanize-ms": "^1.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">= 8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.62.0", + "node_modules/aggregate-error": { + "version": "3.1.0", "dev": true, "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/ajv-formats": { + "version": "2.1.1", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "ajv": "^8.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "ajv": "^8.0.0" }, "peerDependenciesMeta": { - "typescript": { + "ajv": { "optional": true } } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", + "node_modules/ajv-keywords": { + "version": "5.1.0", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "fast-deep-equal": "^3.1.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/@typescript-eslint/utils/node_modules/globby": { - "version": "11.1.0", + "node_modules/ansi-colors": { + "version": "4.1.3", "dev": true, "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "type-fest": "^0.21.3" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/utils/node_modules/slash": { - "version": "3.0.0", + "node_modules/ansi-html-community": { + "version": "0.0.8", "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", + "node_modules/ansi-styles": { + "version": "3.2.1", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "color-convert": "^1.9.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "devOptional": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">= 8" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", + "node_modules/aproba": { + "version": "2.0.0", "dev": true, "license": "ISC" }, - "node_modules/@vitejs/plugin-basic-ssl": { - "version": "1.0.1", + "node_modules/are-docs-informative": { + "version": "0.0.2", "dev": true, "license": "MIT", "engines": { - "node": ">=14.6.0" - }, - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0" + "node": ">=14" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", + "node_modules/are-we-there-yet": { + "version": "3.0.1", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", + "node_modules/arg": { + "version": "4.1.3", "dev": true, "license": "MIT" }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", + "node_modules/argparse": { + "version": "1.0.10", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" + "sprintf-js": "~1.0.2" } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", + "node_modules/aria-query": { + "version": "5.3.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "dequal": "^2.0.3" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", "dev": true, "license": "MIT", "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@xtuc/long": "4.2.2" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", + "node_modules/array-flatten": { + "version": "1.1.1", "dev": true, "license": "MIT" }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" - } + "license": "MIT" }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", + "node_modules/array-includes": { + "version": "3.1.7", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", + "node_modules/array-union": { + "version": "2.1.0", "dev": true, "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "engines": { + "node": ">=8" } }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", + "node_modules/array-uniq": { + "version": "1.0.3", "dev": true, "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@xtuc/long": "4.2.2" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@wessberg/ts-evaluator": { - "version": "0.0.27", + "node_modules/array.prototype.flat": { + "version": "1.3.2", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.1.0", - "jsdom": "^16.4.0", - "object-path": "^0.11.5", - "tslib": "^2.0.3" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=10.1.0" + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/wessberg/ts-evaluator?sponsor=1" - }, - "peerDependencies": { - "typescript": ">=3.2.x || >= 4.x" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/ansi-styles": { - "version": "4.3.0", + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/chalk": { - "version": "4.1.2", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/color-convert": { - "version": "2.0.1", + "node_modules/arrify": { + "version": "1.0.1", "dev": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/has-flag": { - "version": "4.0.0", + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/asn1": { + "version": "0.2.6", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "safer-buffer": "~2.1.0" } }, - "node_modules/@wessberg/ts-evaluator/node_modules/supports-color": { - "version": "7.2.0", + "node_modules/assert-plus": { + "version": "1.0.0", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "tslib": "^2.0.1" }, + "engines": { + "node": ">=4" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", + "node_modules/async": { + "version": "3.2.5", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT" }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "dev": true, - "license": "Apache-2.0" + "node_modules/asynckit": { + "version": "0.4.0", + "license": "MIT" }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "dev": true, - "license": "BSD-2-Clause" + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", + "node_modules/autoprefixer": { + "version": "10.4.14", "dev": true, - "license": "BSD-2-Clause", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "license": "MIT", "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" }, "engines": { - "node": ">=14.15.0" + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.6", + "node_modules/available-typed-arrays": { + "version": "1.0.7", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "possible-typed-array-names": "^1.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@zkochan/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/abab": { - "version": "2.0.6", + "node_modules/aws-sign2": { + "version": "0.7.0", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": "*" + } }, - "node_modules/abbrev": { - "version": "1.1.1", + "node_modules/aws4": { + "version": "1.12.0", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/accepts": { - "version": "1.3.8", + "node_modules/axios": { + "version": "1.6.8", "dev": true, "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", "dev": true, - "bin": { - "acorn": "bin/acorn" + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=0.4.0" + "node": ">= 6" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", + "node_modules/axobject-query": { + "version": "4.0.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "dequal": "^2.0.3" } }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/babel-loader": { + "version": "9.1.3", "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" }, "engines": { - "node": ">=0.4.0" + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" } }, - "node_modules/acorn-globals/node_modules/acorn-walk": { - "version": "7.2.0", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.10", "dev": true, "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" + }, "peerDependencies": { - "acorn": "^8" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.7", "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.4", + "core-js-compat": "^3.33.1" + }, "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.1", + "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.4", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.4.0" + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", "dev": true, "license": "MIT", "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" + "@babel/helper-define-polyfill-provider": "^0.5.0" }, - "engines": { - "node": ">=8.9" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { - "version": "2.0.4", + "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", "dev": true, "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" }, - "engines": { - "node": ">=8.9.0" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/adm-zip": { - "version": "0.5.12", + "node_modules/balanced-match": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0" + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.1.tgz", + "integrity": "sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-path": "^2.0.0", + "bare-stream": "^2.0.0" } }, - "node_modules/agent-base": { - "version": "6.0.2", + "node_modules/bare-os": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.0.tgz", + "integrity": "sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", + "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" + "bare-os": "^2.1.0" } }, - "node_modules/agentkeepalive": { - "version": "4.5.0", + "node_modules/bare-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.1.3.tgz", + "integrity": "sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" + "streamx": "^2.18.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", "dev": true, "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": "^4.5.0 || >= 5.9" } }, - "node_modules/ajv": { - "version": "8.12.0", + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=10.0.0" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "license": "MIT", + "node_modules/batch": { + "version": "0.6.1", + "dev": true, + "license": "MIT" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "tweetnacl": "^0.14.3" } }, - "node_modules/ajv-keywords": { - "version": "5.1.0", + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" + "license": "Unlicense", + "engines": { + "node": ">=0.6" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", + "node_modules/big.js": { + "version": "5.2.2", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": "*" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "dev": true, + "node_modules/binary-extensions": { + "version": "2.2.0", + "devOptional": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", + "node_modules/bl": { + "version": "4.1.0", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", + "node_modules/blocking-proxy": { + "version": "1.0.1", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "minimist": "^1.2.0" + }, + "bin": { + "blocking-proxy": "built/lib/bin.js" }, "engines": { - "node": ">=4" + "node": ">=6.9.x" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "devOptional": true, - "license": "ISC", + "node_modules/body-parser": { + "version": "1.20.2", + "dev": true, + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/aproba": { - "version": "2.0.0", + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "node_modules/are-docs-informative": { - "version": "0.0.2", + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", "dev": true, "license": "MIT", - "engines": { - "node": ">=14" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.10.0" } }, - "node_modules/arg": { - "version": "4.1.3", + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", "dev": true, "license": "MIT" }, - "node_modules/argparse": { - "version": "1.0.10", + "node_modules/bonjour-service": { + "version": "1.2.1", "dev": true, "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" } }, - "node_modules/aria-query": { - "version": "5.3.0", + "node_modules/boolbase": { + "version": "1.0.0", "dev": true, - "license": "Apache-2.0", + "license": "ISC" + }, + "node_modules/bplist-creator": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", + "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==", + "dev": true, + "license": "MIT", "dependencies": { - "dequal": "^2.0.3" + "stream-buffers": "2.2.x" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", + "node_modules/bplist-parser": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz", + "integrity": "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "big-integer": "1.6.x" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 5.10.0" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true + "node_modules/brace-expansion": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, - "node_modules/array-includes": { - "version": "3.1.7", - "dev": true, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "devOptional": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" + "fill-range": "^7.1.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/array-union": { - "version": "2.1.0", + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/browserslist": { + "version": "4.23.0", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, "engines": { - "node": ">=8" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/array-uniq": { - "version": "1.0.3", + "node_modules/browserstack": { + "version": "1.6.1", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "https-proxy-agent": "^2.2.1" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", + "node_modules/browserstack/node_modules/agent-base": { + "version": "4.3.0", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" + "es6-promisify": "^5.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4.0.0" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", + "node_modules/browserstack/node_modules/debug": { + "version": "3.2.7", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "ms": "^2.1.1" + } + }, + "node_modules/browserstack/node_modules/https-proxy-agent": { + "version": "2.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4.5.0" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "dev": true, + "node_modules/buffer": { + "version": "5.7.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "*" } }, - "node_modules/arrify": { - "version": "1.0.1", + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/asn1": { - "version": "0.2.6", + "node_modules/builtins": { + "version": "5.0.1", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": "~2.1.0" + "semver": "^7.0.0" } }, - "node_modules/assert-plus": { - "version": "1.0.0", + "node_modules/bytes": { + "version": "3.0.0", "dev": true, "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">= 0.8" } }, - "node_modules/async": { - "version": "3.2.5", + "node_modules/cacache": { + "version": "17.1.4", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^7.7.1", + "minipass": "^7.0.3", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/asynckit": { - "version": "0.4.0", + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", "dev": true, - "license": "MIT" + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/autoprefixer": { - "version": "10.4.14", + "node_modules/cacache/node_modules/minipass": { + "version": "7.0.4", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, + "license": "ISC", "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/available-typed-arrays": { + "node_modules/call-bind": { "version": "1.0.7", - "dev": true, "license": "MIT", "dependencies": { - "possible-typed-array-names": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -5952,942 +7793,953 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", + "node_modules/callsites": { + "version": "3.1.0", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": "*" + "node": ">=6" } }, - "node_modules/aws4": { - "version": "1.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.6.8", + "node_modules/camelcase": { + "version": "5.3.1", "dev": true, "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "engines": { + "node": ">=6" } }, - "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" }, "engines": { - "node": ">= 6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/axobject-query": { - "version": "4.0.0", + "node_modules/caniuse-lite": { + "version": "1.0.30001606", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" }, - "node_modules/babel-loader": { - "version": "9.1.3", - "dev": true, + "node_modules/capacitor-blob-writer": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/capacitor-blob-writer/-/capacitor-blob-writer-1.1.16.tgz", + "integrity": "sha512-MKeqLUB7hBmRiJQcMeucD22Ckql1tk1GFnk/xYQDtFNBhKcAJBoV5rMXgkTphvZoRFw9b8025PAdjSj23dbg7A==", "license": "MIT", - "dependencies": { - "find-cache-dir": "^4.0.0", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5" + "@capacitor/core": ">=3.0.0", + "@capacitor/filesystem": ">=1.0.0" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" + "node_modules/capacitor-ios-autofill-save-password": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capacitor-ios-autofill-save-password/-/capacitor-ios-autofill-save-password-2.0.0.tgz", + "integrity": "sha512-7Tnu7qU5elnv1YkcXtXPIBhvyCZX9nskKrI78kJG65qaf6rSL1EE5IBOdTSQcpyPSyVio+UX1EFsS/QZjQrPuA==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^5.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.10", - "dev": true, + "node_modules/capacitor-secure-storage-plugin": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/capacitor-secure-storage-plugin/-/capacitor-secure-storage-plugin-0.9.0.tgz", + "integrity": "sha512-P5fiC94opcLHu41vceo9weXH+20g0SPYKkeAx+qm9eKNcVFqpcuI4dqwivXlGXYNMDygyjSQuAaFwZ4gW0Y91Q==", "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.1", - "semver": "^6.3.1" - }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "@capacitor/core": "^5.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", + "node_modules/caseless": { + "version": "0.12.0", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } + "license": "Apache-2.0" }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.7", + "node_modules/chalk": { + "version": "2.4.2", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.4", - "core-js-compat": "^3.33.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">=4" } }, - "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.4", - "dev": true, + "node_modules/chardet": { + "version": "0.7.0", + "license": "MIT" + }, + "node_modules/chart.js": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "@kurkle/color": "^0.3.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "pnpm": ">=8" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.5", - "dev": true, + "node_modules/chartjs-adapter-date-fns": { + "version": "3.0.0", "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0" - }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "chart.js": ">=2.8.0", + "date-fns": ">=2.0.0" } }, - "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.5.0", - "dev": true, + "node_modules/chartjs-plugin-zoom": { + "version": "2.0.1", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "hammerjs": "^2.0.8" }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "chart.js": ">=3.2.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", + "node_modules/chevrotain": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz", + "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "dependencies": { + "regexp-to-ast": "0.5.0" + } }, - "node_modules/base64-js": { - "version": "1.5.1", + "node_modules/chokidar": { + "version": "3.5.3", + "devOptional": true, "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" + "type": "individual", + "url": "https://paulmillr.com/funding/" } ], - "license": "MIT" - }, - "node_modules/base64id": { - "version": "2.0.0", - "dev": true, "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, "engines": { - "node": "^4.5.0 || >= 5.9" + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" + "node_modules/chownr": { + "version": "2.0.0", + "license": "ISC", + "engines": { + "node": ">=10" } }, - "node_modules/big.js": { - "version": "5.2.2", + "node_modules/chrome-trace-event": { + "version": "1.0.3", "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">=6.0" } }, - "node_modules/binary-extensions": { + "node_modules/classlist.js": { + "version": "1.1.20150312", + "license": "Dedicated to the public domain" + }, + "node_modules/clean-stack": { "version": "2.2.0", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/bl": { - "version": "4.1.0", + "node_modules/cli-cursor": { + "version": "3.1.0", "license": "MIT", "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/blocking-proxy": { - "version": "1.0.1", - "dev": true, + "node_modules/cli-spinners": { + "version": "2.9.2", "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "blocking-proxy": "built/lib/bin.js" + "engines": { + "node": ">=6" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "license": "ISC", "engines": { - "node": ">=6.9.x" + "node": ">= 10" } }, - "node_modules/body-parser": { - "version": "1.20.2", + "node_modules/cliui": { + "version": "8.0.1", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=12" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "dev": true, + "node_modules/clone": { + "version": "1.0.4", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=0.8" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", + "node_modules/clone-deep": { + "version": "4.0.1", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "color-convert": "^2.0.1", + "color-string": "^1.9.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/bonjour-service": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" + "node": ">=12.5.0" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", + "node_modules/color-convert": { + "version": "1.9.3", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "devOptional": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" + "color-name": "1.1.3" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", + "node_modules/color-convert/node_modules/color-name": { + "version": "1.1.3", "dev": true, - "license": "BSD-2-Clause" + "license": "MIT" }, - "node_modules/browserslist": { - "version": "4.23.0", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "dev": true, + "license": "ISC", "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "color-support": "bin.js" } }, - "node_modules/browserstack": { - "version": "1.6.1", + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { - "https-proxy-agent": "^2.2.1" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/browserstack/node_modules/agent-base": { - "version": "4.3.0", + "node_modules/colorette": { + "version": "2.0.20", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "license": "MIT", "dependencies": { - "es6-promisify": "^5.0.0" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">= 4.0.0" + "node": ">= 0.8" } }, - "node_modules/browserstack/node_modules/debug": { - "version": "3.2.7", - "dev": true, + "node_modules/commander": { + "version": "7.2.0", "license": "MIT", - "dependencies": { - "ms": "^2.1.1" + "engines": { + "node": ">= 10" } }, - "node_modules/browserstack/node_modules/https-proxy-agent": { - "version": "2.2.4", + "node_modules/comment-parser": { + "version": "1.4.1", "dev": true, "license": "MIT", - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, "engines": { - "node": ">= 4.5.0" + "node": ">= 12.0.0" } }, - "node_modules/buffer": { - "version": "5.7.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/common-path-prefix": { + "version": "3.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, "license": "MIT", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "dev": true, + "node_modules/compare-versions": { + "version": "6.1.0", "license": "MIT" }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "dev": true, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", "license": "MIT", - "engines": { - "node": ">=6" - }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/builtins": { - "version": "5.0.1", + "node_modules/compressible": { + "version": "2.0.18", "dev": true, "license": "MIT", "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "dev": true, + "mime-db": ">= 1.43.0 < 2" + }, "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, - "node_modules/cacache": { - "version": "17.1.4", + "node_modules/compression": { + "version": "1.7.4", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^7.7.1", - "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 0.8.0" } }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/cacache/node_modules/minipass": { - "version": "7.0.4", + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } + "license": "MIT" }, - "node_modules/call-bind": { - "version": "1.0.7", + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.10.0" } }, - "node_modules/callsites": { - "version": "3.1.0", + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.8" } }, - "node_modules/camelcase": { - "version": "5.3.1", + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001606", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/caseless": { - "version": "0.12.0", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/chalk": { - "version": "2.4.2", + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/chardet": { - "version": "0.7.0", + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", "dev": true, "license": "MIT" }, - "node_modules/chart.js": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", - "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "dev": true, + "license": "MIT", "dependencies": { - "@kurkle/color": "^0.3.0" + "ee-first": "1.1.1" }, "engines": { - "pnpm": ">=8" + "node": ">= 0.8" } }, - "node_modules/chartjs-adapter-date-fns": { - "version": "3.0.0", + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "dev": true, "license": "MIT", - "peerDependencies": { - "chart.js": ">=2.8.0", - "date-fns": ">=2.0.0" + "engines": { + "node": ">= 0.6" } }, - "node_modules/chartjs-plugin-zoom": { - "version": "2.0.1", + "node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "dev": true, "license": "MIT", "dependencies": { - "hammerjs": "^2.0.8" + "safe-buffer": "5.2.1" }, - "peerDependencies": { - "chart.js": ">=3.2.0" + "engines": { + "node": ">= 0.6" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "devOptional": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "node_modules/content-type": { + "version": "1.0.5", + "dev": true, "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">= 0.6" } }, - "node_modules/chownr": { - "version": "2.0.0", + "node_modules/conventional-changelog": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.25.tgz", + "integrity": "sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^5.0.12", + "conventional-changelog-atom": "^2.0.8", + "conventional-changelog-codemirror": "^2.0.8", + "conventional-changelog-conventionalcommits": "^4.5.0", + "conventional-changelog-core": "^4.2.1", + "conventional-changelog-ember": "^2.0.9", + "conventional-changelog-eslint": "^3.0.9", + "conventional-changelog-express": "^2.0.6", + "conventional-changelog-jquery": "^3.0.11", + "conventional-changelog-jshint": "^2.0.9", + "conventional-changelog-preset-loader": "^2.3.4" + }, "engines": { "node": ">=10" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", + "node_modules/conventional-changelog-angular": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", + "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + }, "engines": { - "node": ">=6.0" + "node": ">=10" } }, - "node_modules/classlist.js": { - "version": "1.1.20150312", - "license": "Dedicated to the public domain" - }, - "node_modules/clean-stack": { - "version": "2.2.0", + "node_modules/conventional-changelog-angular/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "license": "MIT", + "node_modules/conventional-changelog-atom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz", + "integrity": "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==", + "dev": true, + "license": "ISC", "dependencies": { - "restore-cursor": "^3.1.0" + "q": "^1.5.1" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/cli-spinners": { - "version": "2.9.2", + "node_modules/conventional-changelog-atom/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, "license": "MIT", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/cli-width": { - "version": "3.0.0", + "node_modules/conventional-changelog-codemirror": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz", + "integrity": "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==", "dev": true, "license": "ISC", + "dependencies": { + "q": "^1.5.1" + }, "engines": { - "node": ">= 10" + "node": ">=10" } }, - "node_modules/cliui": { - "version": "8.0.1", + "node_modules/conventional-changelog-codemirror/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz", + "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==", "dev": true, "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" }, "engines": { - "node": ">=12" + "node": ">=10" } }, - "node_modules/clone": { - "version": "1.0.4", + "node_modules/conventional-changelog-conventionalcommits/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/clone-deep": { - "version": "4.0.1", + "node_modules/conventional-changelog-core": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz", + "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^5.0.0", + "conventional-commits-parser": "^3.2.0", + "dateformat": "^3.0.0", + "get-pkg-repo": "^4.0.0", + "git-raw-commits": "^2.0.8", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^4.1.1", + "lodash": "^4.17.15", + "normalize-package-data": "^3.0.0", + "q": "^1.5.1", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0", + "through2": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/color-convert": { - "version": "1.9.3", + "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "color-name": "1.1.3" + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/color-convert/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/color-name": { - "version": "1.1.4", - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", + "node_modules/conventional-changelog-core/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "dev": true, - "license": "MIT" - }, - "node_modules/colors": { - "version": "1.4.0", - "dev": true, - "license": "MIT", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=0.1.90" + "node": ">=10" } }, - "node_modules/combined-stream": { - "version": "1.0.8", + "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "delayed-stream": "~1.0.0" + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" }, "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "7.2.0", - "license": "MIT", - "engines": { - "node": ">= 10" + "node": ">=10" } }, - "node_modules/comment-parser": { - "version": "1.4.1", + "node_modules/conventional-changelog-core/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/common-path-prefix": { - "version": "3.0.0", + "node_modules/conventional-changelog-core/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" }, - "node_modules/compare-versions": { - "version": "6.1.0", - "license": "MIT" - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/conventional-changelog-ember": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz", + "integrity": "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==", "dev": true, + "license": "ISC", "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "q": "^1.5.1" }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "node_modules/conventional-changelog-ember/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/conventional-changelog-eslint": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz", + "integrity": "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==", "dev": true, + "license": "ISC", "dependencies": { - "ms": "2.0.0" + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", + "node_modules/conventional-changelog-eslint/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } }, - "node_modules/connect": { - "version": "3.7.0", + "node_modules/conventional-changelog-express": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz", + "integrity": "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "q": "^1.5.1" }, "engines": { - "node": ">= 0.10.0" + "node": ">=10" } }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "node_modules/conventional-changelog-express/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", + "node_modules/conventional-changelog-jquery": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz", + "integrity": "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ms": "2.0.0" + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" } }, - "node_modules/connect/node_modules/finalhandler": { - "version": "1.1.2", + "node_modules/conventional-changelog-jquery/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/conventional-changelog-jshint": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz", + "integrity": "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==", + "dev": true, + "license": "ISC", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "compare-func": "^2.0.0", + "q": "^1.5.1" }, "engines": { - "node": ">= 0.8" + "node": ">=10" } }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", + "node_modules/conventional-changelog-jshint/node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } }, - "node_modules/connect/node_modules/on-finished": { - "version": "2.3.0", + "node_modules/conventional-changelog-preset-loader": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", "dev": true, "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, "engines": { - "node": ">= 0.8" + "node": ">=10" } }, - "node_modules/connect/node_modules/statuses": { - "version": "1.5.0", + "node_modules/conventional-changelog-writer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz", + "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==", "dev": true, "license": "MIT", + "dependencies": { + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-changelog-writer": "cli.js" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", + "node_modules/conventional-changelog-writer/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/conventional-commits-filter": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", + "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "5.2.1" + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/content-type": { - "version": "1.0.5", + "node_modules/conventional-commits-parser": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", + "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", "dev": true, "license": "MIT", + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, "node_modules/convert-source-map": { @@ -6897,18 +8749,22 @@ }, "node_modules/cookie": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "license": "MIT" }, "node_modules/copy-anything": { "version": "2.0.6", @@ -6969,7 +8825,6 @@ }, "node_modules/core-util-is": { "version": "1.0.2", - "dev": true, "license": "MIT" }, "node_modules/cors": { @@ -7103,9 +8958,18 @@ "node": ">=8" } }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -7116,6 +8980,16 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/css-loader": { "version": "6.8.1", "dev": true, @@ -7543,6 +9417,16 @@ "node": ">=12" } }, + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/dashdash": { "version": "1.14.1", "dev": true, @@ -7554,6 +9438,15 @@ "node": ">=0.10" } }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/data-urls": { "version": "2.0.0", "dev": true, @@ -7637,9 +9530,18 @@ "node": ">=4.0" } }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/debug": { "version": "4.3.4", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -7661,11 +9563,64 @@ "node": ">=0.10.0" } }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decimal.js": { "version": "10.4.3", "dev": true, "license": "MIT" }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "dev": true, @@ -7673,9 +9628,8 @@ }, "node_modules/default-gateway": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -7695,7 +9649,6 @@ }, "node_modules/define-data-property": { "version": "1.1.4", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -7733,6 +9686,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/del": { "version": "2.2.2", "dev": true, @@ -7824,7 +9791,6 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -7860,11 +9826,30 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } }, "node_modules/di": { "version": "0.0.1", @@ -7873,7 +9858,6 @@ }, "node_modules/diff": { "version": "4.0.2", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -7892,9 +9876,8 @@ }, "node_modules/dns-packet": { "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -7994,6 +9977,19 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dotenv": { "version": "10.0.0", "dev": true, @@ -8007,6 +10003,45 @@ "dev": true, "license": "MIT" }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "dev": true, @@ -8028,27 +10063,43 @@ }, "node_modules/ejs": { "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.728", + "dev": true, + "license": "ISC" + }, + "node_modules/elementtree": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz", + "integrity": "sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==", + "license": "Apache-2.0", "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" + "sax": "1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4.0" } }, - "node_modules/electron-to-chromium": { - "version": "1.4.728", - "dev": true, + "node_modules/elementtree/node_modules/sax": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz", + "integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==", "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, "license": "MIT" }, "node_modules/emojis-list": { @@ -8078,14 +10129,15 @@ }, "node_modules/end-of-stream": { "version": "1.4.4", - "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" } }, "node_modules/engine.io": { - "version": "6.5.4", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", "dev": true, "license": "MIT", "dependencies": { @@ -8098,7 +10150,7 @@ "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.11.0" + "ws": "~8.17.1" }, "engines": { "node": ">=10.2.0" @@ -8121,7 +10173,9 @@ } }, "node_modules/engine.io/node_modules/ws": { - "version": "8.11.0", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "license": "MIT", "engines": { @@ -8129,7 +10183,7 @@ }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -8273,7 +10327,6 @@ }, "node_modules/es-define-property": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" @@ -8284,7 +10337,6 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8418,7 +10470,6 @@ }, "node_modules/escape-string-regexp": { "version": "1.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -8426,7 +10477,6 @@ }, "node_modules/escodegen": { "version": "2.1.0", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", @@ -8446,7 +10496,6 @@ }, "node_modules/escodegen/node_modules/estraverse": { "version": "5.3.0", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -8454,7 +10503,6 @@ }, "node_modules/escodegen/node_modules/source-map": { "version": "0.6.1", - "dev": true, "license": "BSD-3-Clause", "optional": true, "engines": { @@ -8666,9 +10714,8 @@ }, "node_modules/eslint-plugin-unused-imports": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz", - "integrity": "sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==", "dev": true, + "license": "MIT", "dependencies": { "eslint-rule-composer": "^0.3.0" }, @@ -8956,7 +11003,6 @@ }, "node_modules/esprima": { "version": "4.0.1", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -9014,7 +11060,6 @@ }, "node_modules/esutils": { "version": "2.0.3", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -9022,9 +11067,8 @@ }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9049,9 +11093,8 @@ }, "node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -9077,6 +11120,16 @@ "node": ">= 0.8.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/exponential-backoff": { "version": "3.1.1", "dev": true, @@ -9084,9 +11137,8 @@ }, "node_modules/express": { "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -9126,18 +11178,16 @@ }, "node_modules/express/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/express/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/extend": { "version": "3.0.2", @@ -9146,7 +11196,6 @@ }, "node_modules/external-editor": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "chardet": "^0.7.0", @@ -9159,7 +11208,6 @@ }, "node_modules/external-editor/node_modules/iconv-lite": { "version": "0.4.24", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -9180,6 +11228,13 @@ "version": "3.1.3", "license": "MIT" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.2", "dev": true, @@ -9204,6 +11259,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fastq": { "version": "1.16.0", "dev": true, @@ -9214,9 +11275,8 @@ }, "node_modules/faye-websocket": { "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -9224,9 +11284,18 @@ "node": ">=0.8.0" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/figures": { "version": "3.2.0", - "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" @@ -9285,6 +11354,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "devOptional": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -9294,9 +11364,8 @@ }, "node_modules/finalhandler": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -9312,18 +11381,16 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/find-cache-dir": { "version": "4.0.0", @@ -9452,11 +11519,25 @@ "node": ">= 6" } }, + "node_modules/formidable": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.1.tgz", + "integrity": "sha512-WJWKelbRHN41m5dumb0/k8TeAx7Id/y3a+Z7QfhxP/htI9Js5zYaEDtG8uMgG0vM0lOlqnmjE99/kfpOYi/0Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9475,9 +11556,8 @@ }, "node_modules/fresh": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9526,40 +11606,255 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-pkg-repo": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", + "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hutson/parse-repository-url": "^3.0.0", + "hosted-git-info": "^4.0.0", + "through2": "^2.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "get-pkg-repo": "src/cli.js" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-pkg-repo/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/get-pkg-repo/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/get-pkg-repo/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/get-pkg-repo/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/get-pkg-repo/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/get-pkg-repo/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/get-pkg-repo/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-pkg-repo/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], + "license": "ISC", "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=10" } }, - "node_modules/function-bind": { - "version": "1.1.2", + "node_modules/get-stream": { + "version": "6.0.1", "dev": true, "license": "MIT", + "engines": { + "node": ">=10" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name": { - "version": "1.1.6", + "node_modules/get-symbol-description": { + "version": "1.0.2", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" @@ -9568,110 +11863,159 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "dev": true, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/gauge": { - "version": "4.0.4", - "dev": true, - "license": "ISC", + "node_modules/get-uri/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "license": "MIT", "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=14.14" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">= 10.0.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", + "node_modules/getpass": { + "version": "0.1.7", "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" } }, - "node_modules/get-intrinsic": { - "version": "1.2.4", + "node_modules/git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "git-raw-commits": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10" } }, - "node_modules/get-package-type": { - "version": "0.1.0", + "node_modules/git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", "dev": true, "license": "MIT", + "dependencies": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, "engines": { - "node": ">=8.0.0" + "node": ">=4" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/git-remote-origin-url/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/get-symbol-description": { - "version": "1.0.2", + "node_modules/git-semver-tags": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", + "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "meow": "^8.0.0", + "semver": "^6.0.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "git-semver-tags": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10" } }, - "node_modules/getpass": { - "version": "0.1.7", + "node_modules/git-semver-tags/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "MIT", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", + "dev": true, + "license": "BSD", "dependencies": { - "assert-plus": "^1.0.0" + "ini": "^1.3.2" } }, + "node_modules/gitconfiglocal/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT" + }, "node_modules/glob": { "version": "10.3.12", "dev": true, @@ -9781,7 +12125,6 @@ }, "node_modules/gopd": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" @@ -9792,9 +12135,21 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "dev": true, "license": "ISC" }, + "node_modules/gradle-to-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/gradle-to-js/-/gradle-to-js-2.0.1.tgz", + "integrity": "sha512-is3hDn9zb8XXnjbEeAEIqxTpLHUiGBqjegLmXPuyMBfKAggpadWFku4/AP8iYAGBX6qR9/5UIUIp47V0XI3aMw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash.merge": "^4.6.2" + }, + "bin": { + "gradle-to-js": "cli.js" + } + }, "node_modules/graphemer": { "version": "1.4.0", "dev": true, @@ -9820,9 +12175,40 @@ }, "node_modules/handle-thing": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/har-schema": { "version": "2.0.0", @@ -9864,6 +12250,16 @@ "dev": true, "license": "MIT" }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/has-ansi": { "version": "2.0.0", "dev": true, @@ -9901,7 +12297,6 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.2", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -9912,7 +12307,6 @@ }, "node_modules/has-proto": { "version": "1.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9923,7 +12317,6 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9953,7 +12346,6 @@ }, "node_modules/hasown": { "version": "2.0.2", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -9977,6 +12369,25 @@ "dev": true, "license": "MIT" }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/hosted-git-info": { "version": "6.1.1", "dev": true, @@ -9998,9 +12409,8 @@ }, "node_modules/hpack.js": { "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -10010,9 +12420,8 @@ }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -10025,15 +12434,13 @@ }, "node_modules/hpack.js/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -10051,8 +12458,6 @@ }, "node_modules/html-entities": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", "dev": true, "funding": [ { @@ -10063,7 +12468,8 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ] + ], + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", @@ -10095,9 +12501,8 @@ }, "node_modules/http-deceiver": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", @@ -10116,9 +12521,8 @@ }, "node_modules/http-parser-js": { "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", @@ -10148,9 +12552,8 @@ }, "node_modules/http-proxy-middleware": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -10198,9 +12601,8 @@ }, "node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -10260,6 +12662,13 @@ "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, "node_modules/ignore-walk": { "version": "6.0.4", "dev": true, @@ -10340,7 +12749,6 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -10361,7 +12769,6 @@ }, "node_modules/inflight": { "version": "1.0.6", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -10501,7 +12908,6 @@ }, "node_modules/ip-address": { "version": "9.0.5", - "dev": true, "license": "MIT", "dependencies": { "jsbn": "1.1.0", @@ -10513,19 +12919,16 @@ }, "node_modules/ip-address/node_modules/jsbn": { "version": "1.1.0", - "dev": true, "license": "MIT" }, "node_modules/ip-address/node_modules/sprintf-js": { "version": "1.1.3", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/ipaddr.js": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -10653,7 +13056,6 @@ }, "node_modules/is-docker": { "version": "2.2.1", - "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -10675,7 +13077,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10720,6 +13121,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -10738,6 +13140,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-path-cwd": { "version": "1.0.0", "dev": true, @@ -10778,9 +13190,8 @@ }, "node_modules/is-plain-obj": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -10835,7 +13246,6 @@ }, "node_modules/is-stream": { "version": "2.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10872,6 +13282,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-typed-array": { "version": "1.1.13", "dev": true, @@ -10888,7 +13311,6 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/is-unicode-supported": { @@ -10919,7 +13341,6 @@ }, "node_modules/is-wsl": { "version": "2.2.0", - "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -10930,7 +13351,6 @@ }, "node_modules/isarray": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/isbinaryfile": { @@ -10946,7 +13366,6 @@ }, "node_modules/isexe": { "version": "2.0.0", - "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -11357,6 +13776,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "dev": true, @@ -11412,6 +13838,23 @@ ], "license": "MIT" }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/jsprim": { "version": "1.4.2", "dev": true, @@ -11755,6 +14198,16 @@ "node": ">=0.10.0" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/klona": { "version": "2.0.6", "dev": true, @@ -11765,14 +14218,39 @@ }, "node_modules/launch-editor": { "version": "2.6.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", - "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", "dev": true, + "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" } }, + "node_modules/leek": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz", + "integrity": "sha512-6PVFIYXxlYF0o6hrAsHtGpTmi06otkwNrMcmQ0K96SeSRHPREPa9J3nJZ1frliVH7XT0XFswoJFQoXsDukzGNQ==", + "license": "MIT", + "dependencies": { + "debug": "^2.1.0", + "lodash.assign": "^3.2.0", + "rsvp": "^3.0.21" + } + }, + "node_modules/leek/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/leek/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/less": { "version": "4.2.0", "dev": true, @@ -11869,6 +14347,46 @@ "dev": true, "license": "MIT" }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "dev": true, @@ -11898,23 +14416,114 @@ }, "node_modules/lodash": { "version": "4.17.21", - "dev": true, "license": "MIT" }, "node_modules/lodash-es": { "version": "4.17.21", "license": "MIT" }, + "node_modules/lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", + "license": "MIT", + "dependencies": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "node_modules/lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==", + "license": "MIT" + }, + "node_modules/lodash._bindcallback": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==", + "license": "MIT" + }, + "node_modules/lodash._createassigner": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", + "integrity": "sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==", + "license": "MIT", + "dependencies": { + "lodash._bindcallback": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash.restparam": "^3.0.0" + } + }, + "node_modules/lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", + "license": "MIT" + }, + "node_modules/lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==", + "license": "MIT" + }, + "node_modules/lodash.assign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz", + "integrity": "sha512-/VVxzgGBmbphasTg51FrztxQJ/VgAUpol6zmJuSVSGcNg4g7FA4z7rQV8Ovr9V3vFBNWZhvKWHfpAytjTVUfFA==", + "license": "MIT", + "dependencies": { + "lodash._baseassign": "^3.0.0", + "lodash._createassigner": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, "node_modules/lodash.debounce": { "version": "4.0.8", "dev": true, "license": "MIT" }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "license": "MIT" + }, + "node_modules/lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", + "license": "MIT" + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", + "license": "MIT", + "dependencies": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, "node_modules/lodash.merge": { "version": "4.6.2", "dev": true, "license": "MIT" }, + "node_modules/lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==", + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "license": "MIT", @@ -12006,6 +14615,18 @@ "yallist": "^3.0.2" } }, + "node_modules/macos-release": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.5.1.tgz", + "integrity": "sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/magic-string": { "version": "0.30.1", "dev": true, @@ -12234,6 +14855,19 @@ "dev": true, "license": "ISC" }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/media-typer": { "version": "0.3.0", "dev": true, @@ -12253,30 +14887,230 @@ "node": ">= 4.0.0" } }, + "node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/meow/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } }, - "node_modules/merge-stream": { - "version": "2.0.0", + "node_modules/mergexml": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/mergexml/-/mergexml-1.2.4.tgz", + "integrity": "sha512-yiOlDqcVCz7AG1eSboonc18FTlfqDEKYfGoAV3Lul98u6YRV/s0kjtf4bjk47t0hLTFJR0BSYMd6BpmX3xDjNQ==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "@xmldom/xmldom": "^0.7.0", + "formidable": "^3.5.1", + "xpath": "0.0.27" + } }, - "node_modules/merge2": { - "version": "1.4.1", + "node_modules/mergexml/node_modules/xpath": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.27.tgz", + "integrity": "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=0.6.0" } }, "node_modules/methods": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12306,7 +15140,6 @@ }, "node_modules/mime-db": { "version": "1.52.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -12314,7 +15147,6 @@ }, "node_modules/mime-types": { "version": "2.1.35", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -12330,6 +15162,29 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/mini-css-extract-plugin": { "version": "2.7.6", "dev": true, @@ -12350,13 +15205,11 @@ }, "node_modules/minimalistic-assert": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minimatch": { "version": "3.1.2", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -12367,15 +15220,38 @@ }, "node_modules/minimist": { "version": "1.2.8", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/minipass": { "version": "5.0.0", - "dev": true, "license": "ISC", "engines": { "node": ">=8" @@ -12548,7 +15424,6 @@ }, "node_modules/minizlib": { "version": "2.1.2", - "dev": true, "license": "MIT", "dependencies": { "minipass": "^3.0.0", @@ -12560,7 +15435,6 @@ }, "node_modules/minizlib/node_modules/minipass": { "version": "3.3.6", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -12571,12 +15445,10 @@ }, "node_modules/minizlib/node_modules/yallist": { "version": "4.0.0", - "dev": true, "license": "ISC" }, "node_modules/mkdirp": { "version": "1.0.4", - "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -12585,6 +15457,23 @@ "node": ">=10" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/mrmime": { "version": "1.0.1", "dev": true, @@ -12595,14 +15484,12 @@ }, "node_modules/ms": { "version": "2.1.2", - "dev": true, "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, + "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -12613,7 +15500,6 @@ }, "node_modules/mute-stream": { "version": "0.0.8", - "dev": true, "license": "ISC" }, "node_modules/nanoid": { @@ -12633,6 +15519,59 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true, + "license": "MIT" + }, + "node_modules/native-run": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/native-run/-/native-run-1.7.4.tgz", + "integrity": "sha512-yDEwTp66vmXpqFiSQzz4sVQgyq5U58gGRovglY4GHh12ITyWa6mh6Lbpm2gViVOVD1JYFtYnwcgr7GTFBinXNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ionic/utils-fs": "^3.1.6", + "@ionic/utils-terminal": "^2.3.3", + "bplist-parser": "^0.3.2", + "debug": "^4.3.4", + "elementtree": "^0.1.7", + "ini": "^3.0.1", + "plist": "^3.0.6", + "split2": "^4.1.0", + "through2": "^4.0.2", + "tslib": "^2.4.0", + "yauzl": "^2.10.0" + }, + "bin": { + "native-run": "bin/native-run" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/native-run/node_modules/ini": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/native-run/node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "dev": true, @@ -12667,6 +15606,15 @@ "dev": true, "license": "MIT" }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/ng2-charts": { "version": "4.1.1", "license": "ISC", @@ -12705,18 +15653,17 @@ "@angular/core": ">=15.0.0" } }, - "node_modules/nice-napi": { - "version": "1.0.2", + "node_modules/node-abi": { + "version": "3.65.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", + "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "!win32" - ], "dependencies": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" } }, "node_modules/node-addon-api": { @@ -12724,73 +15671,251 @@ "dev": true, "license": "MIT" }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true, - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-gyp": { - "version": "9.4.1", + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "9.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "dev": true, + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-html-parser": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.4.2.tgz", + "integrity": "sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^4.2.1", + "he": "1.2.0" + } + }, + "node_modules/node-html-parser/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/node-html-parser/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/node-html-parser/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/node-html-parser/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/node-html-parser/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, "license": "MIT", "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" }, "bin": { - "node-gyp": "bin/node-gyp.js" + "nodemon": "bin/nodemon.js" }, "engines": { - "node": "^12.13 || ^14.13 || >=16" + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" } }, - "node_modules/node-gyp-build": { - "version": "4.8.0", + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "bin": { + "semver": "bin/semver" } }, - "node_modules/node-releases": { - "version": "2.0.14", - "dev": true, - "license": "MIT" - }, "node_modules/nopt": { "version": "6.0.0", "dev": true, @@ -13001,7 +16126,6 @@ }, "node_modules/npm-run-path": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -13010,6 +16134,20 @@ "node": ">=8" } }, + "node_modules/npm-watch": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/npm-watch/-/npm-watch-0.9.0.tgz", + "integrity": "sha512-C5Rgh5+jvY33K1EH8Qjr1hfpH9Nhasc90QJ0W+JyKg2ogE0LOCZI4xirC8QmywW7XinyBpynwxlrN6aPfjc3Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nodemon": "^2.0.7", + "through2": "^4.0.2" + }, + "bin": { + "npm-watch": "cli.js" + } + }, "node_modules/npmlog": { "version": "6.0.2", "dev": true, @@ -13361,7 +16499,6 @@ }, "node_modules/object-inspect": { "version": "1.13.1", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -13448,9 +16585,8 @@ }, "node_modules/obuf": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/on-finished": { "version": "2.4.1", @@ -13465,16 +16601,14 @@ }, "node_modules/on-headers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/once": { "version": "1.4.0", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -13600,9 +16734,24 @@ "node": ">=8" } }, + "node_modules/os-name": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", + "integrity": "sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==", + "license": "MIT", + "dependencies": { + "macos-release": "^2.5.0", + "windows-release": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/os-tmpdir": { "version": "1.0.2", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13649,9 +16798,8 @@ }, "node_modules/p-retry": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -13662,9 +16810,8 @@ }, "node_modules/p-retry/node_modules/retry": { "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -13677,6 +16824,90 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/pacote": { "version": "15.2.0", "dev": true, @@ -13818,7 +17049,6 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13831,7 +17061,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13867,9 +17096,8 @@ }, "node_modules/path-to-regexp": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", @@ -13879,6 +17107,13 @@ "node": ">=8" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, "node_modules/performance-now": { "version": "2.1.0", "dev": true, @@ -14030,6 +17265,41 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/plist/node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/plist/node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "dev": true, @@ -14158,6 +17428,53 @@ "dev": true, "license": "MIT" }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC" + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "dev": true, @@ -14166,6 +17483,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "dev": true, @@ -14187,7 +17520,6 @@ }, "node_modules/process-nextick-args": { "version": "2.0.1", - "dev": true, "license": "MIT" }, "node_modules/promise-inflight": { @@ -14207,6 +17539,30 @@ "node": ">=10" } }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/protractor": { "version": "7.0.0", "dev": true, @@ -14447,9 +17803,8 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -14460,16 +17815,94 @@ }, "node_modules/proxy-addr/node_modules/ipaddr.js": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-agent/node_modules/socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", - "dev": true, "license": "MIT" }, "node_modules/prr": { @@ -14483,9 +17916,15 @@ "dev": true, "license": "MIT" }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, "node_modules/pump": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -14518,7 +17957,6 @@ }, "node_modules/qs": { "version": "6.11.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" @@ -14554,6 +17992,23 @@ ], "license": "MIT" }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true, + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/randombytes": { "version": "2.1.0", "dev": true, @@ -14603,6 +18058,39 @@ "node": ">=0.10.0" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/read-package-json": { "version": "6.0.4", "dev": true, @@ -14645,6 +18133,161 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/readable-stream": { "version": "3.6.0", "license": "MIT", @@ -14668,6 +18311,20 @@ "node": ">=8.10.0" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/reflect-metadata": { "version": "0.1.14", "dev": true, @@ -14683,78 +18340,217 @@ "dev": true, "license": "MIT", "dependencies": { - "regenerate": "^1.4.2" + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "dev": true, + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/replace": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/replace/-/replace-1.2.2.tgz", + "integrity": "sha512-C4EDifm22XZM2b2JOYe6Mhn+lBsLBAvLbK8drfUQLTfD1KYl/n3VaW/CDju0Ny4w3xTtegBpg8YNSpFJPUDSjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "2.4.2", + "minimatch": "3.0.5", + "yargs": "^15.3.1" + }, + "bin": { + "replace": "bin/replace.js", + "search": "bin/search.js" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/replace/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/replace/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/replace/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" }, "engines": { - "node": ">=4" + "node": ">=7.0.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "license": "MIT" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", + "node_modules/replace/node_modules/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@babel/runtime": "^7.8.4" + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/regex-parser": { - "version": "2.3.0", - "dev": true, - "license": "MIT" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", + "node_modules/replace/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/regexpu-core": { - "version": "5.3.2", + "node_modules/replace/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/replace/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/regjsparser": { - "version": "0.9.1", + "node_modules/replace/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", "dependencies": { - "jsesc": "~0.5.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" + "engines": { + "node": ">=6" } }, "node_modules/request": { @@ -14948,7 +18744,6 @@ }, "node_modules/rimraf": { "version": "3.0.2", - "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -14962,7 +18757,6 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -15002,9 +18796,17 @@ "fsevents": "~2.3.2" } }, + "node_modules/rsvp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", + "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", + "license": "MIT", + "engines": { + "node": "0.12.* || 4.* || 6.* || >= 7.*" + } + }, "node_modules/run-async": { "version": "2.4.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -15239,9 +19041,8 @@ }, "node_modules/select-hose": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/selenium-webdriver": { "version": "3.6.0", @@ -15300,9 +19101,8 @@ }, "node_modules/selfsigned": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -15313,7 +19113,6 @@ }, "node_modules/semver": { "version": "7.6.0", - "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" @@ -15327,7 +19126,6 @@ }, "node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -15338,14 +19136,12 @@ }, "node_modules/semver/node_modules/yallist": { "version": "4.0.0", - "dev": true, "license": "ISC" }, "node_modules/send": { "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -15367,24 +19163,21 @@ }, "node_modules/send/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serialize-javascript": { "version": "6.0.2", @@ -15396,9 +19189,8 @@ }, "node_modules/serve-index": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -15414,27 +19206,24 @@ }, "node_modules/serve-index/node_modules/debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -15447,36 +19236,31 @@ }, "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-static": { "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, + "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -15494,7 +19278,6 @@ }, "node_modules/set-function-length": { "version": "1.2.2", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -15543,9 +19326,39 @@ "node": ">=8" } }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -15556,7 +19369,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -15564,16 +19376,14 @@ }, "node_modules/shell-quote": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel": { "version": "1.0.4", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.0", @@ -15665,39 +19475,201 @@ "dev": true, "license": "MIT", "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-plist": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", + "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bplist-creator": "0.1.0", + "bplist-parser": "0.3.1", + "plist": "^3.0.5" + } + }, + "node_modules/simple-plist/node_modules/bplist-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", + "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "big-integer": "1.6.x" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" }, - "optionalDependencies": { - "encoding": "^0.1.13" + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/sigstore/node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.4", - "dev": true, - "license": "ISC", + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/slash": { - "version": "4.0.0", - "dev": true, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "color-name": "~1.1.4" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=7.0.0" } }, "node_modules/smart-buffer": { "version": "4.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 6.0.0", @@ -15722,15 +19694,20 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.2", + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", "dev": true, "license": "MIT", "dependencies": { - "ws": "~8.11.0" + "debug": "~4.3.4", + "ws": "~8.17.1" } }, "node_modules/socket.io-adapter/node_modules/ws": { - "version": "8.11.0", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "license": "MIT", "engines": { @@ -15738,7 +19715,7 @@ }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -15763,9 +19740,8 @@ }, "node_modules/sockjs": { "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, + "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -15774,16 +19750,16 @@ }, "node_modules/sockjs/node_modules/uuid": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/socks": { - "version": "2.8.1", - "dev": true, + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "license": "MIT", "dependencies": { "ip-address": "^9.0.5", @@ -15894,9 +19870,8 @@ }, "node_modules/spdy": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -15910,9 +19885,8 @@ }, "node_modules/spdy-transport": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -15922,11 +19896,39 @@ "wbuf": "^1.7.3" } }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "dev": true, "license": "BSD-3-Clause" }, + "node_modules/ssh-config": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/ssh-config/-/ssh-config-1.1.6.tgz", + "integrity": "sha512-ZPO9rECxzs5JIQ6G/2EfL1I9ho/BVZkx9HRKn8+0af7QgwAmumQ7XBFP1ggMyPMo+/tUbmv0HFdv4qifdO/9JA==", + "license": "MIT" + }, "node_modules/sshpk": { "version": "1.18.0", "dev": true, @@ -15978,6 +19980,56 @@ "node": ">= 0.8" } }, + "node_modules/stream-buffers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "license": "MIT", + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-combiner2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stream-combiner2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/stream-combiner2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/streamroller": { "version": "3.1.5", "dev": true, @@ -15991,6 +20043,21 @@ "node": ">=8.0" } }, + "node_modules/streamx": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", + "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "license": "MIT", @@ -16000,7 +20067,6 @@ }, "node_modules/string-width": { "version": "4.2.3", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -16103,12 +20169,24 @@ }, "node_modules/strip-final-newline": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -16136,6 +20214,69 @@ "node": ">=4" } }, + "node_modules/superagent": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", + "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/superagent/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/superagent/node_modules/formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "license": "MIT", + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/supports-color": { "version": "5.5.0", "dev": true, @@ -16172,6 +20313,7 @@ "url": "http://opencollective.com/swiper" } ], + "license": "MIT", "engines": { "node": ">= 4.7.0" } @@ -16194,67 +20336,197 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" + } + }, + "node_modules/tar-fs/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "license": "ISC" + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tar": { - "version": "6.2.1", + "node_modules/tempy/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tar-stream": { + "node_modules/tempy/node_modules/is-path-cwd": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true, "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, "engines": { "node": ">=6" } }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", + "node_modules/tempy/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=8" } }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, "node_modules/terser": { "version": "5.29.1", "dev": true, @@ -16387,6 +20659,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/text-decoder": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", + "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -16394,18 +20686,25 @@ }, "node_modules/through": { "version": "2.3.8", - "dev": true, "license": "MIT" }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, "node_modules/thunky": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmp": { "version": "0.0.33", - "dev": true, "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" @@ -16427,6 +20726,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "devOptional": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -16442,6 +20742,16 @@ "node": ">=0.6" } }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, "node_modules/tough-cookie": { "version": "4.1.3", "dev": true, @@ -16477,17 +20787,27 @@ }, "node_modules/tree-kill": { "version": "1.2.2", - "dev": true, "license": "MIT", "bin": { "tree-kill": "cli.js" } }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -16702,7 +21022,6 @@ }, "node_modules/type-fest": { "version": "0.21.3", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -16797,6 +21116,15 @@ "dev": true, "license": "MIT" }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typescript": { "version": "4.9.5", "dev": true, @@ -16814,6 +21142,7 @@ "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.4.tgz", "integrity": "sha512-OXcWHQk+pW9gqEL/Mb1eTgj/Yiqk1oHBERr9v4VInPOYN++p+cXejmQK/h/VlUPGD++FXQ8pgiqVMyEtxU4T6A==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^3.0.0", "execa": "^4.0.0", @@ -17005,6 +21334,20 @@ "node": "*" } }, + "node_modules/uglify-js": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.18.0.tgz", + "integrity": "sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "dev": true, @@ -17019,9 +21362,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { "version": "5.26.5", - "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -17082,6 +21431,19 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/universalify": { "version": "0.1.2", "dev": true, @@ -17098,6 +21460,15 @@ "node": ">= 0.8" } }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "dev": true, @@ -17163,6 +21534,7 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -17220,9 +21592,8 @@ }, "node_modules/vite": { "version": "4.5.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", - "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -17314,9 +21685,8 @@ }, "node_modules/wbuf": { "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -17541,9 +21911,8 @@ }, "node_modules/webpack-dev-server": { "version": "4.15.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", - "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dev": true, + "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -17600,9 +21969,8 @@ }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", @@ -17622,10 +21990,11 @@ } }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -17733,9 +22102,8 @@ }, "node_modules/websocket-driver": { "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -17747,9 +22115,8 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } @@ -17793,7 +22160,6 @@ }, "node_modules/which": { "version": "2.0.2", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -17856,9 +22222,77 @@ "dev": true, "license": "MIT" }, + "node_modules/windows-release": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", + "integrity": "sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==", + "license": "MIT", + "dependencies": { + "execa": "^4.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/windows-release/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/windows-release/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "7.0.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -17916,7 +22350,6 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -17930,7 +22363,6 @@ }, "node_modules/wrap-ansi/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -17941,11 +22373,24 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "dev": true, "license": "ISC" }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/ws": { - "version": "7.5.9", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, "license": "MIT", "engines": { @@ -17964,6 +22409,43 @@ } } }, + "node_modules/xcode": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", + "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "simple-plist": "^1.1.0", + "uuid": "^7.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/xcode/node_modules/uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/xml-name-validator": { "version": "3.0.0", "dev": true, @@ -17994,6 +22476,26 @@ "dev": true, "license": "MIT" }, + "node_modules/xpath": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", + "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "dev": true, @@ -18032,6 +22534,17 @@ "node": ">=12" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yn": { "version": "3.1.1", "dev": true, diff --git a/ui/package.json b/ui/package.json index 9790d1c8f7e..4107030261c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -12,12 +12,25 @@ "@angular/platform-browser-dynamic": "~16.2.12", "@angular/router": "~16.2.12", "@angular/service-worker": "~16.2.12", + "@capacitor-community/file-opener": "^1.0.5", + "@capacitor/android": "5.2.3", + "@capacitor/app": "^5.0.6", + "@capacitor/core": "5.2.3", + "@capacitor/filesystem": "^5.2.0", + "@capacitor/ios": "5.2.3", + "@capacitor/splash-screen": "^5.0.6", + "@ionic-native/core": "^5.36.0", + "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", + "@ionic/cli": "^7.1.6", "@ngx-formly/core": "^6.3.0", "@ngx-formly/ionic": "^6.3.5", "@ngx-formly/schematics": "^6.3.0", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", + "capacitor-blob-writer": "^1.1.14", + "capacitor-ios-autofill-save-password": "^2.0.0", + "capacitor-secure-storage-plugin": "^0.9.0", "chart.js": "^4.4.3", "chartjs-adapter-date-fns": "^3.0.0", "chartjs-plugin-zoom": "^2.0.1", @@ -46,6 +59,8 @@ "@angular/compiler": "^16.2.12", "@angular/compiler-cli": "^16.2.12", "@angular/language-service": "^16.2.12", + "@capacitor/assets": "^3.0.0", + "@capacitor/cli": "5.2.3", "@ionic/angular-toolkit": "^11.0.1", "@stylistic/eslint-plugin": "^2.2.2", "@types/jasmine": "~4.3.6", @@ -74,6 +89,7 @@ }, "scripts": { "lint": "ng lint", - "test": "ng test" + "test": "ng test", + "capacitor-assets": "capacitor-assets" } } diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index a520f995833..4f24cc18d84 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -48,12 +48,14 @@ import { LoginComponent } from './index/login.component'; import { OverViewComponent } from './index/overview/overview.component'; import { DataService } from './shared/genericComponents/shared/dataservice'; import { UserComponent } from './user/user.component'; +import { DetailsOverviewComponent } from './edge/history/common/production/details/details.overview'; +import { LoadingScreenComponent } from './index/shared/loading-screen'; const routes: Routes = [ // TODO should be removed in the future - { path: 'index', redirectTo: 'login', pathMatch: 'full' }, - { path: '', redirectTo: 'login', pathMatch: 'full' }, + { path: '', redirectTo: 'index', pathMatch: 'full' }, + { path: 'index', component: LoadingScreenComponent }, { path: 'login', component: LoginComponent, data: { navbarTitle: environment.uiTitle } }, { path: 'overview', component: OverViewComponent }, @@ -92,6 +94,7 @@ const routes: Routes = [ { path: 'consumptionchart', component: ConsumptionChartOverviewComponent }, { path: 'gridchart', component: GridChartOverviewComponent }, { path: 'productionchart', component: ProductionChartOverviewComponent }, + { path: 'productionchart/:componentId', component: DetailsOverviewComponent }, { path: 'selfconsumptionchart', component: SelfconsumptionChartOverviewComponent }, { path: 'storagechart', component: StorageChartOverviewComponent }, @@ -102,10 +105,10 @@ const routes: Routes = [ { path: 'settings', data: { navbarTitleToBeTranslated: 'Menu.edgeSettings' }, component: EdgeSettingsComponent }, { path: 'settings/channels', component: EdgeSettingsChannelsComponent }, - { path: 'settings/component.install', component: EdgeSettingsComponentInstallIndexComponentComponent }, - { path: 'settings/component.install/:factoryId', component: EdgeSettingsComponentInstallComponentComponent }, - { path: 'settings/component.update', component: EdgeSettingsComponentUpdateIndexComponentComponent }, - { path: 'settings/component.update/:componentId', component: EdgeSettingsComponentUpdateComponentComponent }, + { path: 'settings/component.install', component: EdgeSettingsComponentInstallIndexComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.addComponents' } }, + { path: 'settings/component.install/:factoryId', component: EdgeSettingsComponentInstallComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.addComponents' } }, + { path: 'settings/component.update', component: EdgeSettingsComponentUpdateIndexComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.adjustComponents' } }, + { path: 'settings/component.update/:componentId', component: EdgeSettingsComponentUpdateComponentComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.adjustComponents' } }, { path: 'settings/network', component: EdgeSettingsNetworkComponent, data: { navbarTitleToBeTranslated: 'Edge.Config.Index.networkConfiguration' } }, { path: 'settings/profile', component: EdgeSettingsProfileComponent }, { path: 'settings/profile/:componentId', component: AliasUpdateComponent }, @@ -123,7 +126,7 @@ const routes: Routes = [ { path: 'demo', component: LoginComponent }, // Fallback - { path: '**', pathMatch: 'full', redirectTo: 'login' }, + { path: '**', pathMatch: 'full', redirectTo: 'index' }, ]; export const appRoutingProviders: any[] = []; diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index 72d01cd471d..c0981692639 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -10,6 +10,8 @@ import { environment } from '../environments'; import { GlobalRouteChangeHandler } from './shared/service/globalRouteChangeHandler'; import { Service, UserPermission, Websocket } from './shared/shared'; import { Language } from './shared/type/language'; +import { SplashScreen } from '@capacitor/splash-screen'; +import { AppService } from './app.service'; @Component({ selector: 'app-root', @@ -38,6 +40,7 @@ export class AppComponent implements OnInit, OnDestroy { public websocket: Websocket, private globalRouteChangeHandler: GlobalRouteChangeHandler, private meta: Meta, + private appService: AppService, private title: Title, ) { service.setLang(Language.getByKey(localStorage.LANGUAGE) ?? Language.getByBrowserLang(navigator.language)); @@ -55,6 +58,9 @@ export class AppComponent implements OnInit, OnDestroy { const segments = e.url.split('/'); this.isHistoryDetailView = segments.slice(0, -1).includes('history'); })); + + this.appService.listen(); + SplashScreen.hide(); } ngOnInit() { diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index f76d84f27e3..343f78f6534 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -13,6 +13,7 @@ import { CookieService } from 'ngx-cookie-service'; import { AngularMyDatePickerModule } from '@nodro7/angular-mydatepicker'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; +import { AppService } from './app.service'; import { CheckForUpdateService } from './appupdateservice'; import { ChangelogModule } from './changelog/changelog.module'; import { EdgeModule } from './edge/edge.module'; @@ -63,6 +64,7 @@ import { UserModule } from './user/user.module'; { provide: FORMLY_CONFIG, multi: true, useFactory: registerTranslateExtension, deps: [TranslateService] }, Pagination, CheckForUpdateService, + AppService, ], bootstrap: [AppComponent], }) diff --git a/ui/src/app/app.service.ts b/ui/src/app/app.service.ts new file mode 100644 index 00000000000..397e6c06b35 --- /dev/null +++ b/ui/src/app/app.service.ts @@ -0,0 +1,154 @@ +// @ts-strict-ignore +import { Injectable } from '@angular/core'; +import { App } from '@capacitor/app'; +import { Capacitor } from '@capacitor/core'; +import { Directory, Encoding, Filesystem } from '@capacitor/filesystem'; +import { FileOpener } from '@ionic-native/file-opener'; +import { AlertController } from '@ionic/angular'; +import { TranslateService } from '@ngx-translate/core'; +import { saveAs } from 'file-saver-es'; +import { BehaviorSubject, Subject } from 'rxjs'; +import { JsonrpcRequest } from './shared/jsonrpc/base'; +import { Websocket } from './shared/shared'; + +@Injectable() +export class AppService { + public static isActive: BehaviorSubject = new BehaviorSubject(null); + public static lastActive: Subject = new Subject(); + public static readonly isApp: boolean = Capacitor.getPlatform() !== 'web'; + public static notifications: Map = new Map(); + + constructor( + private websocket: Websocket, + private alertCtrl: AlertController, + private translate: TranslateService, + ) { } + + private async updateState() { + const { isActive } = await App.getState(); + + if (isActive === true && AppService.isActive?.getValue() === false) { + window.location.reload(); + } + + AppService.isActive.next(isActive); + } + + public listen() { + + // // Don't use in web + if (!AppService.isApp) { + return; + } + + this.updateState(); + + App.addListener('appStateChange', () => { + this.updateState(); + }); + } + + public async downloadFile(path: string, blob: Blob, fileName: string) { + + // await this.presentAlert("Di", "asd", () => { }).then((state) => { + // console.log("state", state); + // }); + + fileName = "test.txt"; + + const writeSecretFile = async () => { + await Filesystem.writeFile({ + path: fileName, + data: "this is a test", + directory: Directory.Data, + encoding: Encoding.UTF8, + }); + }; + + // const openFile = async () => { + // const { uri } = await Filesystem.getUri({ path: fileName, directory: Directory.Data }); + + // let fOpts = { + // filePath: uri + fileName, + // openWithDefault: true + // } + + // FileOpener.open(fOpts); + // } + + const readSecretFile = async () => { + const contents = await Filesystem.readFile({ + path: fileName, + directory: Directory.Documents, + encoding: Encoding.UTF8, + }); + + console.log('secrets:', contents); + }; + + await writeSecretFile(); + // await openFile(); + await readSecretFile(); + } + + + /** + * Method that shows a confirmation window for the app selection + * + * @param clickedApp the app that has been clicked + */ + public async presentAlert(header: string, message: string, successCallback: () => void) { + + const alert = this.alertCtrl.create({ + header: header, + message: message, + buttons: [{ + text: this.translate.instant('INSTALLATION.BACK'), + role: 'cancel', + }, + { + text: this.translate.instant('INSTALLATION.FORWARD'), + handler: () => { + successCallback(); + }, + }], + cssClass: 'alertController', + }); + (await alert).present(); + } + + static async writeAndOpenFile(data: Blob, fileName: string) { + + if (!AppService.isApp) { + saveAs(data, fileName); + } + + const reader = new FileReader(); + reader.readAsDataURL(data); + reader.onloadend = async function () { + try { + const result = await Filesystem.writeFile({ + path: fileName, + data: reader.result.toString(), + directory: Directory.Data, + recursive: true, + encoding: Encoding.UTF8, + }); + + FileOpener.open(result.uri, data.type) + .then(() => console.log('File is opened')) + .catch(e => console.log('Error opening file', e)); + + console.log('Wrote file', result.uri); + } catch (e) { + console.error('Unable to write file', e); + } + }; + } + + public static handleRefresh() { + setTimeout(() => + window.location.reload() + , 1000); + } +} diff --git a/ui/src/app/edge/history/common/energy/flat/flat.ts b/ui/src/app/edge/history/common/energy/flat/flat.ts index f69ce558271..b6b06fa87fc 100644 --- a/ui/src/app/edge/history/common/energy/flat/flat.ts +++ b/ui/src/app/edge/history/common/energy/flat/flat.ts @@ -6,6 +6,7 @@ import { Base64PayloadResponse } from 'src/app/shared/jsonrpc/response/base64Pay import { QueryHistoricTimeseriesExportXlxsRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs'; import { isSameDay, format, isSameMonth, isSameYear } from 'date-fns'; import { saveAs } from 'file-saver-es'; +import { AppService } from 'src/app/app.service'; @Component({ selector: 'energy', @@ -17,6 +18,7 @@ export class FlatComponent extends AbstractFlatWidget { private static readonly EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'; private static readonly EXCEL_EXTENSION = '.xlsx'; protected readonly isSmartphoneResolution = this.service.isSmartphoneResolution; + protected readonly isApp: boolean = AppService.isApp; protected override onCurrentData(currentData: CurrentData) { this.autarchyValue = @@ -40,6 +42,12 @@ export class FlatComponent extends AbstractFlatWidget { * Export historic data to Excel file. */ protected exportToXlxs() { + + if (AppService.isApp) { + this.service.toast(this.translate.instant('APP.FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE'), "warning"); + return; + } + this.service.getCurrentEdge().then(edge => { edge.sendRequest(this.websocket, new QueryHistoricTimeseriesExportXlxsRequest(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to)).then(response => { const r = response as Base64PayloadResponse; diff --git a/ui/src/app/edge/history/common/production/details/chart/chart.ts b/ui/src/app/edge/history/common/production/details/chart/chart.ts new file mode 100644 index 00000000000..6797a9c1612 --- /dev/null +++ b/ui/src/app/edge/history/common/production/details/chart/chart.ts @@ -0,0 +1,88 @@ +import { Component } from '@angular/core'; +import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; +import { Phase } from 'src/app/shared/genericComponents/shared/phase'; +import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; +import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; +import { ChannelAddress } from 'src/app/shared/shared'; + +@Component({ + selector: 'meterChart', + templateUrl: '../../../../../../shared/genericComponents/chart/abstracthistorychart.html', +}) +export class ChartComponent extends AbstractHistoryChart { + + + protected override getChartData(): HistoryUtils.ChartData { + + const component = this.config.getComponent(this.route.snapshot.params.componentId); + const isProductionMeter = this.config.hasComponentNature("io.openems.edge.meter.api.ElectricityMeter", component.id) && this.config.isProducer(component); + const isCharger = this.config.hasComponentNature("io.openems.edge.ess.dccharger.api.EssDcCharger", component.id); + + const channels: HistoryUtils.InputChannel[] = []; + + if (isCharger) { + channels.push({ + name: component.id, + powerChannel: ChannelAddress.fromString(component.id + '/ActualPower'), + energyChannel: ChannelAddress.fromString(component.id + '/ActualEnergy'), + }); + } + + if (isProductionMeter) { + channels.push({ + name: component.id, + powerChannel: ChannelAddress.fromString(component.id + '/ActivePower'), + energyChannel: ChannelAddress.fromString(component.id + '/ActiveProductionEnergy'), + }); + + channels.push(...Phase.THREE_PHASE.map(phase => ({ + name: 'ProductionAcActivePower' + phase, + powerChannel: ChannelAddress.fromString(component.id + '/ActivePower' + phase), + }))); + } + + const chartObject: HistoryUtils.ChartData = { + input: channels, + output: (data: HistoryUtils.ChannelData) => { + const datasets: HistoryUtils.DisplayValues[] = []; + datasets.push({ + name: component.alias, + nameSuffix: (energyQueryResponse: QueryHistoricTimeseriesEnergyResponse) => { + return energyQueryResponse.result.data[isCharger ? component.id + '/ActualEnergy' : component.id + '/ActiveProductionEnergy']; + }, + converter: () => { + return data[component.id]; + }, + color: 'rgb(0,152,204)', + hiddenOnInit: false, + stack: 2, + }); + + if (!isProductionMeter) { + return datasets; + } + + datasets.push(...Phase.THREE_PHASE.map((phase, i) => ({ + name: "Phase " + phase, + converter: () => + data['ProductionAcActivePower' + phase], + color: 'rgb(' + AbstractHistoryChart.phaseColors[i] + ')', + stack: 3, + }))); + + return datasets; + }, + tooltip: { + formatNumber: '1.1-2', + afterTitle: this.translate.instant('General.TOTAL'), + }, + yAxes: [{ + unit: YAxisTitle.ENERGY, + position: 'left', + yAxisId: ChartAxis.LEFT, + }], + }; + + return chartObject; + } +} diff --git a/ui/src/app/edge/history/common/production/details/details.overview.html b/ui/src/app/edge/history/common/production/details/details.overview.html new file mode 100644 index 00000000000..5e3c861b1f3 --- /dev/null +++ b/ui/src/app/edge/history/common/production/details/details.overview.html @@ -0,0 +1,6 @@ + + + + diff --git a/ui/src/app/edge/history/common/production/details/details.overview.ts b/ui/src/app/edge/history/common/production/details/details.overview.ts new file mode 100644 index 00000000000..8a2e5bc46ac --- /dev/null +++ b/ui/src/app/edge/history/common/production/details/details.overview.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { AbstractHistoryChartOverview } from 'src/app/shared/genericComponents/chart/abstractHistoryChartOverview'; +import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; + +@Component({ + templateUrl: './details.overview.html', +}) +export class DetailsOverviewComponent extends AbstractHistoryChartOverview { + protected chargerComponents: EdgeConfig.Component[] = []; + protected productionMeterComponents: EdgeConfig.Component[] = []; + + protected override getChannelAddresses(): ChannelAddress[] { + // Get Chargers + this.chargerComponents = + this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") + .filter(component => component.isEnabled); + + // Get productionMeters + this.productionMeterComponents = + this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => component.isEnabled && this.config.isProducer(component)); + return []; + } +} diff --git a/ui/src/app/edge/history/common/production/overview/overview.html b/ui/src/app/edge/history/common/production/overview/overview.html index c4706da4aaf..d02fe0a1f66 100644 --- a/ui/src/app/edge/history/common/production/overview/overview.html +++ b/ui/src/app/edge/history/common/production/overview/overview.html @@ -34,3 +34,4 @@ + diff --git a/ui/src/app/edge/history/common/production/overview/overview.ts b/ui/src/app/edge/history/common/production/overview/overview.ts index 480d20dc501..715e2dfff07 100644 --- a/ui/src/app/edge/history/common/production/overview/overview.ts +++ b/ui/src/app/edge/history/common/production/overview/overview.ts @@ -1,6 +1,9 @@ import { Component } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ModalController } from '@ionic/angular'; +import { NavigationOption } from 'src/app/shared/genericComponents/footer-navigation/footerNavigation'; import { AbstractHistoryChartOverview } from '../../../../../shared/genericComponents/chart/abstractHistoryChartOverview'; -import { ChannelAddress, EdgeConfig } from '../../../../../shared/shared'; +import { ChannelAddress, EdgeConfig, Service } from '../../../../../shared/shared'; @Component({ templateUrl: './overview.html', @@ -8,6 +11,16 @@ import { ChannelAddress, EdgeConfig } from '../../../../../shared/shared'; export class OverviewComponent extends AbstractHistoryChartOverview { protected chargerComponents: EdgeConfig.Component[] = []; protected productionMeterComponents: EdgeConfig.Component[] = []; + protected navigationButtons: NavigationOption[] = []; + + constructor( + public override service: Service, + protected override route: ActivatedRoute, + public override modalCtrl: ModalController, + private router: Router, + ) { + super(service, route, modalCtrl); + } protected override getChannelAddresses(): ChannelAddress[] { // Get Chargers @@ -19,6 +32,10 @@ export class OverviewComponent extends AbstractHistoryChartOverview { this.productionMeterComponents = this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") .filter(component => component.isEnabled && this.config.isProducer(component)); + + this.navigationButtons = [...this.chargerComponents, ...this.productionMeterComponents].map(el => ( + { id: el.id, alias: el.alias, callback: () => { this.router.navigate(['./' + el.id], { relativeTo: this.route }); } } + )); return []; } } diff --git a/ui/src/app/edge/history/common/production/production.ts b/ui/src/app/edge/history/common/production/production.ts index 890070a3e15..bb70ba25068 100644 --- a/ui/src/app/edge/history/common/production/production.ts +++ b/ui/src/app/edge/history/common/production/production.ts @@ -7,6 +7,8 @@ import { ProductionMeterChartComponent } from './chart/productionMeterChart'; import { TotalAcChartComponent } from './chart/totalAcChart'; import { TotalChartComponent } from './chart/totalChart'; import { TotalDcChartComponent } from './chart/totalDcChart'; +import { ChartComponent } from './details/chart/chart'; +import { DetailsOverviewComponent } from './details/details.overview'; import { FlatComponent } from './flat/flat'; import { OverviewComponent } from './overview/overview'; @@ -23,6 +25,8 @@ import { OverviewComponent } from './overview/overview'; TotalAcChartComponent, TotalChartComponent, ChargerChartComponent, + DetailsOverviewComponent, + ChartComponent, ], exports: [ FlatComponent, diff --git a/ui/src/app/edge/history/history.component.html b/ui/src/app/edge/history/history.component.html index 18e1b0c4574..e284994f2ce 100644 --- a/ui/src/app/edge/history/history.component.html +++ b/ui/src/app/edge/history/history.component.html @@ -1,5 +1,8 @@
    + + + @@ -105,4 +108,4 @@ - + \ No newline at end of file diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index 61166b75f5d..03e9c052124 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; +import { AppService } from 'src/app/app.service'; import { HeaderComponent } from 'src/app/shared/header/header.component'; import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base'; import { Edge, EdgeConfig, Service, Widgets } from 'src/app/shared/shared'; @@ -33,6 +34,7 @@ export class HistoryComponent implements OnInit { // public channelthresholdComponents: string[] = []; public config: EdgeConfig = null; + protected handleRefresh: () => void = () => AppService.handleRefresh(); constructor( public service: Service, diff --git a/ui/src/app/edge/history/historydataservice.ts b/ui/src/app/edge/history/historydataservice.ts index 51e5a033ab5..07f2bec9050 100644 --- a/ui/src/app/edge/history/historydataservice.ts +++ b/ui/src/app/edge/history/historydataservice.ts @@ -8,6 +8,7 @@ import { DateUtils } from "src/app/shared/utils/date/dateutils"; import { QueryHistoricTimeseriesEnergyRequest } from "src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest"; import { Websocket } from "src/app/shared/service/websocket"; import { Service } from "src/app/shared/service/service"; +import { RefresherCustomEvent } from "@ionic/angular"; @Injectable() export class HistoryDataService extends DataService { @@ -56,4 +57,9 @@ export class HistoryDataService extends DataService { public override unsubscribeFromChannels(channels: ChannelAddress[]) { return; } + + public override refresh(ev: RefresherCustomEvent) { + this.getValues(Object.values(this.channelAddresses), this.edge, ""); + ev.target.complete(); + } } diff --git a/ui/src/app/edge/live/live.component.html b/ui/src/app/edge/live/live.component.html index 77f76e165e3..e771887a085 100644 --- a/ui/src/app/edge/live/live.component.html +++ b/ui/src/app/edge/live/live.component.html @@ -1,5 +1,9 @@
    + + + + diff --git a/ui/src/app/edge/live/live.component.ts b/ui/src/app/edge/live/live.component.ts index 8f36b79cb9f..8363d1c811d 100644 --- a/ui/src/app/edge/live/live.component.ts +++ b/ui/src/app/edge/live/live.component.ts @@ -1,7 +1,9 @@ // @ts-strict-ignore import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; +import { RefresherCustomEvent } from '@ionic/angular'; import { Subject } from 'rxjs'; +import { DataService } from 'src/app/shared/genericComponents/shared/dataservice'; import { Edge, EdgeConfig, Service, Utils, Websocket, Widgets } from 'src/app/shared/shared'; @Component({ @@ -14,12 +16,14 @@ export class LiveComponent implements OnInit, OnDestroy { public config: EdgeConfig = null; public widgets: Widgets = null; private stopOnDestroy: Subject = new Subject(); + protected handleRefresh: (ev: RefresherCustomEvent) => void = (ev: RefresherCustomEvent) => this.dataService.refresh(ev); constructor( private route: ActivatedRoute, public service: Service, protected utils: Utils, protected websocket: Websocket, + private dataService: DataService, ) { } public ngOnInit() { diff --git a/ui/src/app/edge/live/livedataservice.ts b/ui/src/app/edge/live/livedataservice.ts index 6dd0c30ddbe..4bfbaaf98ac 100644 --- a/ui/src/app/edge/live/livedataservice.ts +++ b/ui/src/app/edge/live/livedataservice.ts @@ -5,6 +5,7 @@ import { v4 as uuidv4 } from 'uuid'; import { DataService } from "../../shared/genericComponents/shared/dataservice"; import { ChannelAddress, Edge, Service, Websocket } from "../../shared/shared"; +import { RefresherCustomEvent } from "@ionic/angular"; @Directive() export class LiveDataService extends DataService implements OnDestroy { @@ -52,4 +53,13 @@ export class LiveDataService extends DataService implements OnDestroy { public unsubscribeFromChannels(channels: ChannelAddress[]) { this.edge.unsubscribeFromChannels(this.websocket, channels); } + + public override refresh(ev: RefresherCustomEvent) { + this.currentValue.next({ allComponents: {} }); + this.edge.unsubscribeFromChannels(this.websocket, this.subscribedChannelAddresses); + setTimeout(() => { + this.edge.subscribeChannels(this.websocket, "", this.subscribedChannelAddresses); + ev.target.complete(); + }, 1000); + } } diff --git a/ui/src/app/edge/settings/channels/channels.component.html b/ui/src/app/edge/settings/channels/channels.component.html index 8c192b88627..90d4834506c 100644 --- a/ui/src/app/edge/settings/channels/channels.component.html +++ b/ui/src/app/edge/settings/channels/channels.component.html @@ -133,14 +133,14 @@ - - diff --git a/ui/src/app/edge/settings/channels/channels.component.ts b/ui/src/app/edge/settings/channels/channels.component.ts index 660aee32288..a848236abae 100644 --- a/ui/src/app/edge/settings/channels/channels.component.ts +++ b/ui/src/app/edge/settings/channels/channels.component.ts @@ -115,19 +115,19 @@ export class ChannelsComponent { this.saveChannelsInUrl(); } - protected setChannelValue(address: ChannelAddress, channelValue: any) { + protected setChannelValue(componentId: string, channelId: string, channelValue: any) { if (this.edge) { this.edge.sendRequest( this.service.websocket, new SetChannelValueRequest({ - componentId: address.componentId, - channelId: address.channelId, + componentId: componentId, + channelId: channelId, value: channelValue, }), ).then(() => { - this.service.toast("Successfully set " + address.toString() + " to [" + channelValue + "]", "success"); + this.service.toast("Successfully set " + componentId + "/" + channelId + " to [" + channelValue + "]", "success"); }).catch(() => { - this.service.toast("Error setting " + address.toString() + " to [" + channelValue + "]", 'danger'); + this.service.toast("Error setting " + componentId + "/" + channelId + " to [" + channelValue + "]", 'danger'); }); } } diff --git a/ui/src/app/edge/settings/component/install/index.component.ts b/ui/src/app/edge/settings/component/install/index.component.ts index 147379b3235..7814b549482 100644 --- a/ui/src/app/edge/settings/component/install/index.component.ts +++ b/ui/src/app/edge/settings/component/install/index.component.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { ActivatedRoute } from '@angular/router'; import { CategorizedFactories } from 'src/app/shared/edge/edgeconfig'; import { Component, OnInit } from '@angular/core'; -import { Service, Utils, EdgeConfig } from '../../../../shared/shared'; -import { TranslateService } from '@ngx-translate/core'; +import { Service, Utils, EdgeConfig, Websocket, Edge, EdgePermission } from '../../../../shared/shared'; +import { JsonrpcRequest, JsonrpcResponseSuccess } from 'src/app/shared/jsonrpc/base'; +import { ComponentJsonApiRequest } from 'src/app/shared/jsonrpc/request/componentJsonApiRequest'; interface MyCategorizedFactories extends CategorizedFactories { isClicked?: boolean, @@ -18,27 +18,42 @@ export class IndexComponent implements OnInit { private static readonly SELECTOR = "indexComponentInstall"; + private edge: Edge; public list: MyCategorizedFactories[]; public showAllFactories = false; constructor( - private route: ActivatedRoute, private service: Service, - private translate: TranslateService, + private websocket: Websocket, ) { } - ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.addComponents' }, this.route); - this.service.getConfig().then(config => { - this.list = config.listAvailableFactories(); - for (const entry of this.list) { - entry.isClicked = false; - entry.filteredFactories = entry.factories; + async ngOnInit() { + this.edge = await this.service.getCurrentEdge(); + this.list = await this.getCategorizedFactories(); + for (const entry of this.list) { + entry.isClicked = false; + entry.filteredFactories = entry.factories; + } + this.updateFilter(""); + } + + private async getCategorizedFactories(): Promise { + if (EdgePermission.hasReducedFactories(this.edge)) { + const response = await this.edge.sendRequest(this.websocket, new ComponentJsonApiRequest({ + componentId: '_componentManager', + payload: new GetAllComponentFactoriesRequest(), + })); + for (const [factoryId, factory] of Object.entries(response.result.factories)) { + factory.id = factoryId; } - this.updateFilter(""); - }); + + return EdgeConfig.listAvailableFactories(response.result.factories); + } + + const config = await this.service.getConfig(); + return config.listAvailableFactories(); } updateFilter(completeFilter: string) { @@ -64,3 +79,27 @@ export class IndexComponent implements OnInit { } } } + +class GetAllComponentFactoriesRequest extends JsonrpcRequest { + + private static METHOD: string = "getAllComponentFactories"; + + public constructor() { + super(GetAllComponentFactoriesRequest.METHOD, {}); + } + +} + +class GetAllComponentFactoriesResponse extends JsonrpcResponseSuccess { + + public constructor( + public override readonly id: string, + public override readonly result: { + factories: { [factoryId: string]: EdgeConfig.Factory }, + }, + ) { + super(id, result); + } + +} + diff --git a/ui/src/app/edge/settings/component/install/install.component.ts b/ui/src/app/edge/settings/component/install/install.component.ts index 89ad5585219..d53a0a642fc 100644 --- a/ui/src/app/edge/settings/component/install/install.component.ts +++ b/ui/src/app/edge/settings/component/install/install.component.ts @@ -4,7 +4,6 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { FormlyFieldConfig } from '@ngx-formly/core'; import { Service, Utils, Websocket, EdgeConfig, Edge } from '../../../../shared/shared'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: ComponentInstallComponent.SELECTOR, @@ -27,67 +26,64 @@ export class ComponentInstallComponent implements OnInit { protected utils: Utils, private websocket: Websocket, private service: Service, - private translate: TranslateService, ) { } - ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.addComponents' }, this.route).then(edge => { - this.edge = edge; - }); - const factoryId = this.route.snapshot.params["factoryId"]; - this.service.getConfig().then(config => { - this.factoryId = factoryId; - this.factory = config.factories[factoryId]; - const fields: FormlyFieldConfig[] = []; - const model = {}; - for (const property of this.factory.properties) { - const property_id = property.id.replace('.', '_'); - let defaultValue = property.defaultValue; - // if the type is an array and there is no defaultValue then set the defaultValue to an empty array - if (property.schema["type"] === 'repeat' && defaultValue === null) { - defaultValue = []; - } - const field: FormlyFieldConfig = { - key: property_id, - type: 'input', - templateOptions: { - label: property.name, - required: defaultValue === null, - description: property.description, - }, - }; - // add Property Schema - Utils.deepCopy(property.schema, field); - fields.push(field); - if (defaultValue != null) { - model[property_id] = defaultValue; + async ngOnInit() { + this.factoryId = this.route.snapshot.params["factoryId"]; + this.edge = await this.service.getCurrentEdge(); + const config = await this.service.getConfig(); + + const [factory, properties] = await this.edge.getFactoryProperties(this.websocket, this.factoryId); + this.factory = factory; + const fields: FormlyFieldConfig[] = []; + const model = {}; + for (const property of properties) { + const property_id = property.id.replace('.', '_'); + let defaultValue = property.defaultValue; + // if the type is an array and there is no defaultValue then set the defaultValue to an empty array + if (property.schema["type"] === 'repeat' && defaultValue === null) { + defaultValue = []; + } + const field: FormlyFieldConfig = { + key: property_id, + type: 'input', + templateOptions: { + label: property.name, + required: defaultValue === null, + description: property.description, + }, + }; + // add Property Schema + Utils.deepCopy(property.schema, field); + fields.push(field); + if (defaultValue != null) { + model[property_id] = defaultValue; - // Set the next free Component-ID as defaultValue - if (property_id == 'id' && property.schema["type"] !== 'repeat') { - const thisMatch = defaultValue.match(/^(.*)(\d+)$/); - if (thisMatch) { - const thisPrefix = thisMatch[1]; - let highestSuffix = Number.parseInt(thisMatch[2]); - for (const componentId of Object.keys(config.components)) { - const componentMatch = componentId.match(/^(.*)(\d+)$/); - if (componentMatch) { - const componentPrefix = componentMatch[1]; - if (componentPrefix === thisPrefix) { - const componentSuffix = Number.parseInt(componentMatch[2]); - highestSuffix = Math.max(highestSuffix, componentSuffix + 1); - } + // Set the next free Component-ID as defaultValue + if (property_id == 'id' && property.schema["type"] !== 'repeat') { + const thisMatch = defaultValue.match(/^(.*)(\d+)$/); + if (thisMatch) { + const thisPrefix = thisMatch[1]; + let highestSuffix = Number.parseInt(thisMatch[2]); + for (const componentId of Object.keys(config.components)) { + const componentMatch = componentId.match(/^(.*)(\d+)$/); + if (componentMatch) { + const componentPrefix = componentMatch[1]; + if (componentPrefix === thisPrefix) { + const componentSuffix = Number.parseInt(componentMatch[2]); + highestSuffix = Math.max(highestSuffix, componentSuffix + 1); } } - model[property_id] = thisPrefix + highestSuffix; } + model[property_id] = thisPrefix + highestSuffix; } } } - this.form = new FormGroup({}); - this.fields = fields; - this.model = model; - }); + } + this.form = new FormGroup({}); + this.fields = fields; + this.model = model; } public submit() { diff --git a/ui/src/app/edge/settings/component/update/index.component.ts b/ui/src/app/edge/settings/component/update/index.component.ts index fcec4e80b41..fb24d9860f9 100644 --- a/ui/src/app/edge/settings/component/update/index.component.ts +++ b/ui/src/app/edge/settings/component/update/index.component.ts @@ -1,6 +1,5 @@ // @ts-strict-ignore import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; import { CategorizedComponents } from 'src/app/shared/edge/edgeconfig'; import { EdgeConfig, Service, Utils } from '../../../../shared/shared'; @@ -23,13 +22,11 @@ export class IndexComponent implements OnInit { public showAllEntries = false; constructor( - private route: ActivatedRoute, private service: Service, ) { } public ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.adjustComponents' }, this.route); this.service.getConfig().then(config => { this.config = config; const categorizedComponentIds: string[] = []; diff --git a/ui/src/app/edge/settings/component/update/update.component.ts b/ui/src/app/edge/settings/component/update/update.component.ts index e4e0f1b7f5b..08a268df402 100644 --- a/ui/src/app/edge/settings/component/update/update.component.ts +++ b/ui/src/app/edge/settings/component/update/update.component.ts @@ -4,7 +4,6 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { FormlyFieldConfig } from '@ngx-formly/core'; import { Service, Utils, Websocket, EdgeConfig, Edge } from '../../../../shared/shared'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: ComponentUpdateComponent.SELECTOR, @@ -28,55 +27,54 @@ export class ComponentUpdateComponent implements OnInit { protected utils: Utils, private websocket: Websocket, private service: Service, - private translate: TranslateService, ) { } - ngOnInit() { - this.service.setCurrentComponent({ languageKey: 'Edge.Config.Index.adjustComponents' }, this.route).then(edge => { - this.edge = edge; - }); + async ngOnInit() { + this.edge = await this.service.getCurrentEdge(); const componentId = this.route.snapshot.params["componentId"]; - this.service.getConfig().then(config => { - this.componentId = componentId; - const component = config.components[componentId]; - this.factory = config.factories[component.factoryId]; - this.componentIcon = config.getFactoryIcon(this.factory); - const fields: FormlyFieldConfig[] = []; - const model = {}; - for (const property of this.factory.properties) { - if (property.id === 'id') { - continue; // ignore Component-ID - } - const property_id = property.id.replace('.', '_'); - const field: FormlyFieldConfig = { - key: property_id, - type: 'input', - templateOptions: { - label: property.name, - description: property.description, - required: property.isRequired, - }, - }; - // add Property Schema - Utils.deepCopy(property.schema, field); - fields.push(field); - if (component.properties[property.id]) { + const config = await this.service.getConfig(); + this.componentId = componentId; + const component = config.components[componentId]; + this.componentIcon = config.getFactoryIcon(this.factory); + const fields: FormlyFieldConfig[] = []; + const model = {}; - // filter arrays with nested objects - if (Array.isArray(component.properties[property.id]) && component.properties[property.id]?.length > 0 && component.properties[property.id]?.every(element => typeof element === 'object')) { + const [factory, properties] = await this.edge.getFactoryProperties(this.websocket, component.factoryId); + this.factory = factory; + + for (const property of properties) { + if (property.id === 'id') { + continue; // ignore Component-ID + } + const property_id = property.id.replace('.', '_'); + const field: FormlyFieldConfig = { + key: property_id, + type: 'input', + templateOptions: { + label: property.name, + description: property.description, + required: property.isRequired, + }, + }; + // add Property Schema + Utils.deepCopy(property.schema, field); + fields.push(field); + if (component.properties[property.id]) { - // Stringify json for objects nested inside an array - model[property_id] = JSON.stringify(component.properties[property.id]); - } else { - model[property_id] = component.properties[property.id]; - } + // filter arrays with nested objects + if (Array.isArray(component.properties[property.id]) && component.properties[property.id]?.length > 0 && component.properties[property.id]?.every(element => typeof element === 'object')) { + + // Stringify json for objects nested inside an array + model[property_id] = JSON.stringify(component.properties[property.id]); + } else { + model[property_id] = component.properties[property.id]; } } - this.form = new FormGroup({}); - this.fields = fields; - this.model = model; - }); + } + this.form = new FormGroup({}); + this.fields = fields; + this.model = model; } public submit() { diff --git a/ui/src/app/edge/settings/system/executeSystemUpdate.ts b/ui/src/app/edge/settings/system/executeSystemUpdate.ts index 00b806ce07c..04da612d21d 100644 --- a/ui/src/app/edge/settings/system/executeSystemUpdate.ts +++ b/ui/src/app/edge/settings/system/executeSystemUpdate.ts @@ -3,7 +3,6 @@ import { Subject, timer } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { ComponentJsonApiRequest } from "src/app/shared/jsonrpc/request/componentJsonApiRequest"; import { Edge, Websocket } from "src/app/shared/shared"; -import { Role } from "src/app/shared/type/role"; import { environment } from "src/environments"; import { ExecuteSystemUpdateRequest } from "./executeSystemUpdateRequest"; import { GetSystemUpdateStateRequest } from "./getSystemUpdateStateRequest"; @@ -51,35 +50,26 @@ export class ExecuteSystemUpdate { private refreshSystemUpdateState(): Promise { return new Promise((resolve, reject) => { - // if the version is a SNAPSHOT always set the udpate state - // to updated with the current SNAPSHOT version - if (this.edge.isSnapshot() && !this.edge.roleIsAtLeast(Role.ADMIN)) { - const updateState = { updated: { version: this.edge.version } }; - this.setSystemUpdateState(updateState); - this.stopRefreshSystemUpdateState(); - resolve(updateState); - } else { - this.edge.sendRequest(this.websocket, - new ComponentJsonApiRequest({ - componentId: "_host", - payload: new GetSystemUpdateStateRequest(), - })).then(response => { - const result = (response as GetSystemUpdateStateResponse).result; + this.edge.sendRequest(this.websocket, + new ComponentJsonApiRequest({ + componentId: "_host", + payload: new GetSystemUpdateStateRequest(), + })).then(response => { + const result = (response as GetSystemUpdateStateResponse).result; - this.setSystemUpdateState(result); - // Stop regular check if there is no Update available - if (result.updated) { - this.stopRefreshSystemUpdateState(); - } - resolve(this.systemUpdateState); - }).catch(error => { - if (this.systemUpdateState.running) { - this.isEdgeRestarting = true; - return; - } - reject(error); - }); - } + this.setSystemUpdateState(result); + // Stop regular check if there is no Update available + if (result.updated) { + this.stopRefreshSystemUpdateState(); + } + resolve(this.systemUpdateState); + }).catch(error => { + if (this.systemUpdateState.running) { + this.isEdgeRestarting = true; + return; + } + reject(error); + }); }); } diff --git a/ui/src/app/index/index.module.ts b/ui/src/app/index/index.module.ts index 9c1805b0a24..fc90698bdaf 100644 --- a/ui/src/app/index/index.module.ts +++ b/ui/src/app/index/index.module.ts @@ -6,6 +6,7 @@ import { FilterComponent } from './filter/filter.component'; import { OverViewComponent } from './overview/overview.component'; import { SumStateComponent } from './shared/sumState'; import { LoginComponent } from './login.component'; +import { LoadingScreenComponent } from './shared/loading-screen'; @NgModule({ imports: [ @@ -17,6 +18,7 @@ import { LoginComponent } from './login.component'; SumStateComponent, LoginComponent, OverViewComponent, + LoadingScreenComponent, ], }) export class IndexModule { } diff --git a/ui/src/app/index/login.component.html b/ui/src/app/index/login.component.html index 8c901dfc4d6..4c4cf15f044 100644 --- a/ui/src/app/index/login.component.html +++ b/ui/src/app/index/login.component.html @@ -93,4 +93,4 @@ - \ No newline at end of file + diff --git a/ui/src/app/index/login.component.ts b/ui/src/app/index/login.component.ts index 4cb1c9ff054..1197e06d501 100644 --- a/ui/src/app/index/login.component.ts +++ b/ui/src/app/index/login.component.ts @@ -5,6 +5,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { Subject } from 'rxjs'; import { environment } from 'src/environments'; +import { AppService } from '../app.service'; import { AuthenticateWithPasswordRequest } from '../shared/jsonrpc/request/authenticateWithPasswordRequest'; import { Edge, Service, Utils, Websocket } from '../shared/shared'; @@ -19,6 +20,9 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { private page = 0; protected formIsDisabled: boolean = false; + protected popoverActive: 'android' | 'iOS' | null = null; + protected readonly isApp: boolean = AppService.isApp; + constructor( public service: Service, public websocket: Websocket, diff --git a/ui/src/app/index/shared/loading-screen.html b/ui/src/app/index/shared/loading-screen.html new file mode 100644 index 00000000000..c20266ac0b3 --- /dev/null +++ b/ui/src/app/index/shared/loading-screen.html @@ -0,0 +1,5 @@ + + +

    Loading...

    +
    +
    \ No newline at end of file diff --git a/ui/src/app/index/shared/loading-screen.ts b/ui/src/app/index/shared/loading-screen.ts new file mode 100644 index 00000000000..8538a706089 --- /dev/null +++ b/ui/src/app/index/shared/loading-screen.ts @@ -0,0 +1,38 @@ +// @ts-strict-ignore +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Service, Websocket } from '../../shared/shared'; + +@Component({ + selector: 'index', + templateUrl: './loading-screen.html', +}) +export class LoadingScreenComponent implements OnInit { + + protected readonly spinnerId: string = "IndexComponent"; + + constructor( + public service: Service, + public websocket: Websocket, + private router: Router, + ) { } + + ngOnInit() { + + // TODO add websocket status observable + const interval = setInterval(() => { + this.service.startSpinner(this.spinnerId); + if (this.websocket.status === 'online') { + this.service.stopSpinner(this.spinnerId); + this.router.navigate(['/overview']); + clearInterval(interval); + } + if (this.websocket.status === 'waiting for credentials') { + this.service.stopSpinner(this.spinnerId); + this.router.navigate(['/login']); + clearInterval(interval); + } + }, 1000); + } +} diff --git a/ui/src/app/shared/directive/autofill.ts b/ui/src/app/shared/directive/autofill.ts new file mode 100644 index 00000000000..8665630df5b --- /dev/null +++ b/ui/src/app/shared/directive/autofill.ts @@ -0,0 +1,25 @@ +// @ts-strict-ignore +import { Directive, ElementRef, OnInit } from '@angular/core'; +import { Capacitor } from '@capacitor/core'; +import { Logger } from '../shared'; + +@Directive({ + selector: '[appAutofill]', +}) +export class AutofillDirective implements OnInit { + + constructor(private el: ElementRef, private logger: Logger) { } + + ngOnInit(): void { + if (Capacitor.getPlatform() !== 'ios') { return; } + setTimeout(() => { + try { + this.el.nativeElement.children[0].addEventListener('change', (e) => { + this.el.nativeElement.value = (e.target as any).value; + }); + } catch { + console.error("Android Autofill Directive inactive"); + } + }, 100); // Need some time for the ion-input to create the input element + } +} diff --git a/ui/src/app/shared/edge/edge.spec.ts b/ui/src/app/shared/edge/edge.spec.ts new file mode 100644 index 00000000000..9d943acd1ed --- /dev/null +++ b/ui/src/app/shared/edge/edge.spec.ts @@ -0,0 +1,53 @@ + +import { TestBed } from "@angular/core/testing"; +import { DummyConfig } from "./edgeconfig.spec"; +import { EdgeConfig, Websocket } from "../shared"; +import { GetPropertiesOfFactoryResponse } from "../jsonrpc/response/getPropertiesOfFactoryResponse"; +import { JsonrpcResponseSuccess } from "../jsonrpc/base"; +import { GetEdgeConfigResponse } from "../jsonrpc/response/getEdgeConfigResponse"; + +describe('Edge', () => { + const websocketSpyObject = jasmine.createSpyObj('Websocket', ['sendRequest']); + + let websocket: Websocket; + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + { provide: Websocket, useValue: websocketSpyObject }, + ], + }); + websocket = TestBed.inject(Websocket); + }); + + it('#getFactoryPropertiesOldVersion', async () => { + const edge = DummyConfig.dummyEdge({ version: '2024.1.1' }); + + const dummyConfig = DummyConfig.from(DummyConfig.Component.EVCS_KEBA_KECONTACT('evcs0')); + dummyConfig.factories[DummyConfig.Factory.EVCS_KEBA_KECONTACT.id].properties.push(new EdgeConfig.FactoryProperty()); + websocketSpyObject.sendRequest.and.resolveTo(new JsonrpcResponseSuccess('', { + payload: new GetEdgeConfigResponse('', dummyConfig), + })); + + const [factory, properties] = await edge.getFactoryProperties(websocket, DummyConfig.Factory.EVCS_KEBA_KECONTACT.id); + expect(factory.id).toBe(DummyConfig.Factory.EVCS_KEBA_KECONTACT.id); + expect(properties).toBe(dummyConfig.factories[DummyConfig.Factory.EVCS_KEBA_KECONTACT.id].properties); + }); + + it('#getFactoryPropertiesNewVersion', async () => { + const edge = DummyConfig.dummyEdge({ version: '2024.6.1' }); + + const dummmyFactory = new EdgeConfig.Factory('dummy.factory.id', 'description'); + const dummyProperties: EdgeConfig.FactoryProperty[] = [new EdgeConfig.FactoryProperty()]; + + websocketSpyObject.sendRequest.and.resolveTo(new JsonrpcResponseSuccess('', { + payload: new GetPropertiesOfFactoryResponse('', { + factory: dummmyFactory, + properties: dummyProperties, + }), + })); + + const [factory, properties] = await edge.getFactoryProperties(websocket, 'dummy.factory.id'); + expect(factory).toBe(dummmyFactory); + expect(properties).toBe(dummyProperties); + }); +}); diff --git a/ui/src/app/shared/edge/edge.ts b/ui/src/app/shared/edge/edge.ts index 93e0077735d..2a8c11a4dcc 100644 --- a/ui/src/app/shared/edge/edge.ts +++ b/ui/src/app/shared/edge/edge.ts @@ -28,6 +28,9 @@ import { GetChannelResponse } from '../jsonrpc/response/getChannelResponse'; import { Channel, GetChannelsOfComponentResponse } from '../jsonrpc/response/getChannelsOfComponentResponse'; import { GetChannelsOfComponentRequest } from '../jsonrpc/request/getChannelsOfComponentRequest'; import { EdgePermission } from '../shared'; +import { filter, first } from 'rxjs/operators'; +import { GetPropertiesOfFactoryRequest } from '../jsonrpc/request/getPropertiesOfFactoryRequest'; +import { GetPropertiesOfFactoryResponse } from '../jsonrpc/response/getPropertiesOfFactoryResponse'; export class Edge { @@ -71,6 +74,18 @@ export class Edge { return this.config; } + /** + * Gets the first valid Config. If not available yet, it requests it via Websocket. + * + * @param websocket the Websocket connection + */ + public getFirstValidConfig(websocket: Websocket): Promise { + return this.getConfig(websocket) + .pipe(filter(config => config != null && config.isValid()), + first()) + .toPromise(); + } + /** * Gets a channel either from {@link EdgeConfig edgeconfig} or requests it from the edge. * @@ -81,8 +96,8 @@ export class Edge { */ public async getChannel(websocket: Websocket, channel: ChannelAddress): Promise { if (EdgePermission.hasChannelsInEdgeConfig(this)) { - const config = await this.getConfig(websocket); - const foundChannel = config.value.getChannel(channel); + const config = await this.getFirstValidConfig(websocket); + const foundChannel = config.getChannel(channel); if (!foundChannel) { throw new Error("Channel not found: " + channel); } @@ -110,8 +125,8 @@ export class Edge { */ public async getChannels(websocket: Websocket, componentId: string): Promise { if (EdgePermission.hasChannelsInEdgeConfig(this)) { - const config = await this.getConfig(websocket); - const component = config.value.components[componentId]; + const config = await this.getFirstValidConfig(websocket); + const component = config.components[componentId]; if (!component) { throw new Error('Component not found'); } @@ -128,6 +143,19 @@ export class Edge { return response.result.channels; } + public async getFactoryProperties(websocket: Websocket, factoryId: string): Promise<[EdgeConfig.Factory, EdgeConfig.FactoryProperty[]]> { + if (EdgePermission.hasReducedFactories(this)) { + const response = await this.sendRequest(websocket, new ComponentJsonApiRequest({ + componentId: '_componentManager', + payload: new GetPropertiesOfFactoryRequest({ factoryId }), + })); + return [response.result.factory, response.result.properties]; + } + + const factory = (await this.getFirstValidConfig(websocket)).factories[factoryId]; + return [factory, factory.properties]; + } + /** * Called by Service, when this Edge is set as currentEdge. */ diff --git a/ui/src/app/shared/edge/edgeconfig.spec.ts b/ui/src/app/shared/edge/edgeconfig.spec.ts index 9b6a9bb0b99..f2fbe800b66 100644 --- a/ui/src/app/shared/edge/edgeconfig.spec.ts +++ b/ui/src/app/shared/edge/edgeconfig.spec.ts @@ -10,12 +10,42 @@ import { EdgeConfig, PersistencePriority } from "./edgeconfig"; export namespace DummyConfig { + export function dummyEdge(values: { + edgeId?: string, + comment?: string, + producttype?: string, + version?: string, + role?: Role, + isOnline?: boolean, + lastmessage?: Date, + sumState?: SumState, + firstSetupProtocol?: Date, + }): Edge { + return new Edge( + values.edgeId ?? "edge0", + values.comment ?? "edge0", + values.producttype ?? "", + values.version ?? "2023.3.5", + values.role ?? Role.ADMIN, + values.isOnline ?? true, + values.lastmessage ?? new Date(), + values.sumState ?? SumState.OK, + values.firstSetupProtocol ?? new Date(0), + ); + } + const DUMMY_EDGE: Edge = new Edge("edge0", "", "", "2023.3.5", Role.ADMIN, true, new Date(), SumState.OK, new Date(0)); export function from(...components: Component[]): EdgeConfig { - return new EdgeConfig(DUMMY_EDGE, { - components: components?.reduce((acc, c) => ({ ...acc, [c.id]: c }), {}), - factories: components?.map(c => c.factory), + return new EdgeConfig(DUMMY_EDGE, { + components: components?.reduce((acc, c) => { + c.factoryId = c.factory.id; + return ({ ...acc, [c.id]: c }); + }, {}), + factories: components?.reduce((p, c) => { + p[c.factory.id] = new EdgeConfig.Factory(c.factory.id, '', c.factory.natureIds); + return p; + }, {}), }); } @@ -24,16 +54,15 @@ export namespace DummyConfig { const factories = {}; components.forEach(obj => { - const component = obj as unknown; - if (factories[component['factoryId']]) { - factories[component['factoryId']].componentIds = [...factories[component['factoryId']].componentIds, ...component['factory'].componentIds]; + if (factories[obj.factoryId]) { + factories[obj.factoryId].componentIds = [...factories[obj.factoryId].componentIds, obj.id]; } else { - factories[component['factoryId']] = { - componentIds: component['factory'].componentIds, + factories[obj.factoryId] = { + componentIds: [obj.id], description: "", - id: component['factoryId'], - name: component['factoryId'], - natureIds: component['factory'].natureIds, + id: obj.factoryId, + name: obj.factoryId, + natureIds: edgeConfig.factories[obj.factoryId].natureIds, properties: [], }; } @@ -45,7 +74,7 @@ export namespace DummyConfig { }); } - namespace Factory { + export namespace Factory { export const METER_SOCOMEC_THREEPHASE = { id: "Meter.Socomec.Threephase", @@ -210,7 +239,8 @@ export namespace DummyConfig { // identifier `Factory` is also used in namespace // eslint-disable-next-line @typescript-eslint/no-unused-vars type Factory = { - id: string + id: string, + natureIds: string[], }; /** diff --git a/ui/src/app/shared/edge/edgeconfig.ts b/ui/src/app/shared/edge/edgeconfig.ts index 47b529147d6..e5e04a8b8f8 100644 --- a/ui/src/app/shared/edge/edgeconfig.ts +++ b/ui/src/app/shared/edge/edgeconfig.ts @@ -120,34 +120,62 @@ export class EdgeConfig { } } + public getFactoriesByNature(natureId: string): EdgeConfig.Factory[] { + return EdgeConfig.getFactoriesByNature(this.factories, natureId); + } + /** * Get Factories of Nature. * * @param natureId the given Nature. */ - public getFactoriesByNature(natureId: string): EdgeConfig.Factory[] { + public static getFactoriesByNature(factories: { [id: string]: EdgeConfig.Factory }, natureId: string): EdgeConfig.Factory[] { const result = []; - const nature = this.natures[natureId]; + const nature = EdgeConfig.getNaturesOfFactories(factories)[natureId]; if (nature) { for (const factoryId of nature.factoryIds) { - if (factoryId in this.factories) { - result.push(this.factories[factoryId]); + if (factoryId in factories) { + result.push(factories[factoryId]); } } } return result; } + public static getNaturesOfFactories(factories: { [id: string]: EdgeConfig.Factory }): { [natureId: string]: EdgeConfig.Nature } { + const natures: { [natureId: string]: EdgeConfig.Nature } = {}; + // initialize Factorys + for (const [factoryId, factory] of Object.entries(factories)) { + // Fill 'natures' map + for (const natureId of factory.natureIds) { + if (!(natureId in natures)) { + const parts = natureId.split("."); + const name = parts[parts.length - 1]; + natures[natureId] = { + id: natureId, + name: name, + factoryIds: [], + }; + } + natures[natureId].factoryIds.push(factoryId); + } + } + return natures; + } + /** * Get Factories by Factory-IDs. * * @param ids the given Factory-IDs. */ public getFactoriesByIds(factoryIds: string[]): EdgeConfig.Factory[] { + return EdgeConfig.getFactoriesByIds(this.factories, factoryIds); + } + public static getFactoriesByIds(factories: { [id: string]: EdgeConfig.Factory }, factoryIds: string[]): EdgeConfig.Factory[] { const result = []; for (const factoryId of factoryIds) { - if (factoryId in this.factories) { - result.push(this.factories[factoryId]); + if (factoryId in factories) { + result.push(factories[factoryId]); } } return result; @@ -159,11 +187,15 @@ export class EdgeConfig { * @param ids the given Factory-IDs pattern. */ public getFactoriesByIdsPattern(patterns: RegExp[]): EdgeConfig.Factory[] { + return EdgeConfig.getFactoriesByIdsPattern(this.factories, patterns); + } + + public static getFactoriesByIdsPattern(factories: { [id: string]: EdgeConfig.Factory }, patterns: RegExp[]): EdgeConfig.Factory[] { const result = []; for (const pattern of patterns) { - for (const factoryId in this.factories) { + for (const factoryId in factories) { if (pattern.test(factoryId)) { - result.push(this.factories[factoryId]); + result.push(factories[factoryId]); } } } @@ -248,6 +280,17 @@ export class EdgeConfig { } } + /** + * Determines if component has nature + * + * @param nature the given Nature. + * @param componentId the Component-ID + */ + public hasComponentNature(nature: string, componentId: string) { + const natureIds = this.getNatureIdsByComponentId(componentId); + return natureIds.includes(nature); + } + /** * Determines if Edge has a Storage device */ @@ -362,35 +405,41 @@ export class EdgeConfig { return false; } + public listAvailableFactories(): CategorizedFactories[] { + return EdgeConfig.listAvailableFactories(this.factories); + } + /** * Lists all available Factories, grouped by category. */ - public listAvailableFactories(): CategorizedFactories[] { + public static listAvailableFactories(factories: { [id: string]: EdgeConfig.Factory }): CategorizedFactories[] { const allFactories = [ { category: { title: 'Simulatoren', icon: 'flask-outline' }, - factories: Object.values(this.factories).filter(factory => factory.id.startsWith('Simulator.')), + factories: Object.entries(factories) + .filter(([factory]) => factory.startsWith('Simulator.')) + .map(e => e[1]), }, { category: { title: 'Zähler', icon: 'speedometer-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.meter.api.SymmetricMeter"), // TODO replaced by ElectricityMeter - this.getFactoriesByNature("io.openems.edge.meter.api.ElectricityMeter"), - this.getFactoriesByNature("io.openems.edge.ess.dccharger.api.EssDcCharger"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.meter.api.SymmetricMeter"), // TODO replaced by ElectricityMeter + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.meter.api.ElectricityMeter"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.ess.dccharger.api.EssDcCharger"), ], }, { category: { title: 'Speichersysteme', icon: 'battery-charging-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.ess.api.SymmetricEss"), - this.getFactoriesByNature("io.openems.edge.battery.api.Battery"), - this.getFactoriesByNature("io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.ess.api.SymmetricEss"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.battery.api.Battery"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter"), ], }, { category: { title: 'Speichersystem-Steuerung', icon: 'options-outline' }, factories: [ - this.getFactoriesByIdsPattern([ + EdgeConfig.getFactoriesByIdsPattern(factories, [ /Controller\.Asymmetric.*/, /Controller\.Ess.*/, /Controller\.Symmetric.*/, @@ -400,13 +449,13 @@ export class EdgeConfig { { category: { title: 'E-Auto-Ladestation', icon: 'car-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.evcs.api.Evcs"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.evcs.api.Evcs"), ], }, { category: { title: 'E-Auto-Ladestation-Steuerung', icon: 'options-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.Evcs', ]), ], @@ -414,14 +463,14 @@ export class EdgeConfig { { category: { title: 'I/Os', icon: 'log-in-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.io.api.DigitalOutput"), - this.getFactoriesByNature("io.openems.edge.io.api.DigitalInput"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.io.api.DigitalOutput"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.io.api.DigitalInput"), ], }, { category: { title: 'I/O-Steuerung', icon: 'options-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.IO.ChannelSingleThreshold', 'Controller.Io.FixDigitalOutput', 'Controller.IO.HeatingElement', @@ -432,13 +481,13 @@ export class EdgeConfig { { category: { title: 'Temperatursensoren', icon: 'thermometer-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.thermometer.api.Thermometer"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.thermometer.api.Thermometer"), ], }, { category: { title: 'Externe Schnittstellen', icon: 'megaphone-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.Api.Websocket', 'Controller.Api.ModbusTcp', 'Controller.Api.ModbusTcp.ReadOnly', @@ -452,10 +501,10 @@ export class EdgeConfig { { category: { title: 'Cloud-Schnittstellen', icon: 'cloud-outline' }, factories: [ - this.getFactoriesByIdsPattern([ + EdgeConfig.getFactoriesByIdsPattern(factories, [ /TimeOfUseTariff\.*/, ]), - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.Api.Backend', ]), ], @@ -463,7 +512,7 @@ export class EdgeConfig { { category: { title: 'Geräte-Schnittstellen', icon: 'swap-horizontal-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Bridge.Mbus', 'Bridge.Onewire', 'Bridge.Modbus.Serial', @@ -475,24 +524,24 @@ export class EdgeConfig { { category: { title: 'Standard-Komponenten', icon: 'resize-outline' }, factories: [ - this.getFactoriesByIds([ + EdgeConfig.getFactoriesByIds(factories, [ 'Controller.Debug.Log', 'Controller.Debug.DetailedLog', ]), - this.getFactoriesByNature("io.openems.edge.timedata.api.Timedata"), - this.getFactoriesByNature("io.openems.edge.predictor.api.oneday.Predictor24Hours"), - this.getFactoriesByNature("io.openems.edge.scheduler.api.Scheduler"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.timedata.api.Timedata"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.predictor.api.oneday.Predictor24Hours"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.scheduler.api.Scheduler"), ], }, { category: { title: 'Spezial-Controller', icon: 'repeat-outline' }, factories: [ - this.getFactoriesByNature("io.openems.edge.controller.api.Controller"), + EdgeConfig.getFactoriesByNature(factories, "io.openems.edge.controller.api.Controller"), ], }, { category: { title: 'Weitere', icon: 'radio-button-off-outline' }, - factories: Object.values(this.factories), + factories: Object.values(factories), }, ]; diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.html b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.html index e0ac9bd56e9..0c1225b56f0 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.html +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.html @@ -1,5 +1,5 @@ - +
    @@ -7,6 +7,7 @@
    - + -
    \ No newline at end of file + diff --git a/ui/src/app/shared/genericComponents/chart/chart.html b/ui/src/app/shared/genericComponents/chart/chart.html index f6f67a457d5..075411661cb 100644 --- a/ui/src/app/shared/genericComponents/chart/chart.html +++ b/ui/src/app/shared/genericComponents/chart/chart.html @@ -19,7 +19,7 @@ - + - \ No newline at end of file + diff --git a/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.html b/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.html new file mode 100644 index 00000000000..bfa8f32655c --- /dev/null +++ b/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + {{button.alias ?? button.id}} + + + ... + + + + + + + + + {{popoverbtn.alias ?? popoverbtn.id}} + + + + + + + + + + + + + + + diff --git a/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.ts b/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.ts new file mode 100644 index 00000000000..b0774b0538b --- /dev/null +++ b/ui/src/app/shared/genericComponents/footer-navigation/footerNavigation.ts @@ -0,0 +1,114 @@ +import { Location } from "@angular/common"; +import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, HostListener, Input, QueryList, ViewChild, ViewChildren } from "@angular/core"; +import { PopoverController } from "@ionic/angular"; + +export type NavigationOption = { + id: string, + callback: () => void, + alias?: string, +}; + +@Component({ + selector: 'oe-footer-subnavigation', + templateUrl: 'footerNavigation.html', +}) +export class FooterNavigationComponent implements AfterViewInit { + + @ViewChildren('subnavigationbuttons', { read: ElementRef }) + public subnavigationbuttons!: QueryList; + @ViewChild('container', { read: ElementRef }) public container!: ElementRef; + + @Input() public backButton: boolean = false; + @Input() public set navigationOptions(nodes: NavigationOption[]) { + this._buttons = nodes; + this.buttons = nodes; + } + + protected areButtonsReadyToShow: boolean = false; + protected buttons: NavigationOption[] = []; + protected popoverButtons: NavigationOption[] | null = []; + protected showPopover: boolean = false; + + private _buttons: NavigationOption[] = []; + + private static readonly INTERVAL: number = 1000; + + constructor( + protected location: Location, + protected popoverCtrl: PopoverController, + private cdr: ChangeDetectorRef, + ) { + } + + ngAfterViewInit() { + this.cdr.detectChanges(); + this.initializeFooterSubnavigation(); + } + + protected togglePopover(popoverbtn: NavigationOption) { + popoverbtn.callback(); + this.showPopover = false; + } + + @HostListener('window:resize', ['$event.target.innerWidth']) + private onResize(width: number) { + this.initializeFooterSubnavigation(); + } + + + /** + * Initializes sub-navigation + */ + private initializeFooterSubnavigation(): void { + this.buttons = this._buttons; + this.getSplitIndex() + .then((indexToSplit) => { + + if (indexToSplit == null) { + return; + } + + this.buttons = this._buttons.slice(0, indexToSplit); + this.popoverButtons = this._buttons.slice(indexToSplit); + this.areButtonsReadyToShow = true; + }); + } + + /** + * Gets the split index for navigation buttons + * + * @returns a promise + */ + private async getSplitIndex(): Promise { + return new Promise((resolve) => { + let indexToSplit: number = 0; + + const interval = setInterval(() => { + if (this.subnavigationbuttons && this.container) { + + const colLeftPadding = 16; + const paddingLeftRight = 24; + const ionItemWidth = this.container?.nativeElement.offsetWidth - colLeftPadding; + if (ionItemWidth) { + + let sum: number = colLeftPadding; + this.subnavigationbuttons.forEach((b, index, el) => { + sum += b.nativeElement.offsetWidth + paddingLeftRight; + if ((ionItemWidth) > sum) { + indexToSplit = index; + } + }); + + // Workaround + if (ionItemWidth > sum) { + ++indexToSplit; + } + + clearInterval(interval); + resolve(indexToSplit); + } + } + }, FooterNavigationComponent.INTERVAL); + }); + } +} diff --git a/ui/src/app/shared/genericComponents/genericComponents.ts b/ui/src/app/shared/genericComponents/genericComponents.ts index 417ac36b721..7136735eded 100644 --- a/ui/src/app/shared/genericComponents/genericComponents.ts +++ b/ui/src/app/shared/genericComponents/genericComponents.ts @@ -13,6 +13,7 @@ import { FlatWidgetHorizontalLineComponent } from './flat/flat-widget-horizontal import { FlatWidgetLineComponent } from './flat/flat-widget-line/flat-widget-line'; import { FlatWidgetLineItemComponent } from './flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item'; import { FlatWidgetPercentagebarComponent } from './flat/flat-widget-percentagebar/flat-widget-percentagebar'; +import { FooterNavigationComponent } from './footer-navigation/footerNavigation'; import { HelpButtonComponent } from './modal/help-button/help-button'; import { ModalComponent } from './modal/modal'; import { ModalButtonsComponent } from './modal/modal-button/modal-button'; @@ -59,6 +60,7 @@ import { NotificationComponent } from './shared/notification/notification'; PickDateComponent, HelpButtonComponent, NotificationComponent, + FooterNavigationComponent, ], exports: [ // Flat @@ -85,6 +87,7 @@ import { NotificationComponent } from './shared/notification/notification'; PickDateComponent, HelpButtonComponent, NotificationComponent, + FooterNavigationComponent, ], schemas: [CUSTOM_ELEMENTS_SCHEMA], diff --git a/ui/src/app/shared/genericComponents/shared/converter.ts b/ui/src/app/shared/genericComponents/shared/converter.ts index 12458d38a0e..4054c9f9ec0 100644 --- a/ui/src/app/shared/genericComponents/shared/converter.ts +++ b/ui/src/app/shared/genericComponents/shared/converter.ts @@ -1,6 +1,7 @@ // @ts-strict-ignore import { TranslateService } from "@ngx-translate/core"; + import { CurrentData, EdgeConfig, Utils } from "../../shared"; import { TimeUtils } from "../../utils/time/timeutils"; import { Formatter } from "./formatter"; diff --git a/ui/src/app/shared/genericComponents/shared/dataservice.ts b/ui/src/app/shared/genericComponents/shared/dataservice.ts index 7af1ff7bb55..c43aad16467 100644 --- a/ui/src/app/shared/genericComponents/shared/dataservice.ts +++ b/ui/src/app/shared/genericComponents/shared/dataservice.ts @@ -3,6 +3,7 @@ import { Injectable } from "@angular/core"; import { BehaviorSubject, Subject } from "rxjs"; import { ChannelAddress, Edge } from "../../shared"; +import { RefresherCustomEvent } from "@ionic/angular"; @Injectable() export abstract class DataService { @@ -29,4 +30,6 @@ export abstract class DataService { * @param channels the channels */ public abstract unsubscribeFromChannels(channels: ChannelAddress[]); + + public abstract refresh(ev: RefresherCustomEvent); } diff --git a/ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts b/ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts new file mode 100644 index 00000000000..b5ed8cf783e --- /dev/null +++ b/ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts @@ -0,0 +1,33 @@ + +import { JsonrpcRequest } from "../base"; + +/** + * Represents a JSON-RPC Request to get properties and the factory of a factoryId. + * + *

    + * This is used by UI to get the properties for component update and installation. + * + *

    + * {
    + *   "jsonrpc": "2.0",
    + *   "id": "UUID",
    + *   "method": "getPropertiesOfFactory",
    + *   "params": {
    + *      "factoryId": string
    + *   }
    + * }
    + * 
    + */ +export class GetPropertiesOfFactoryRequest extends JsonrpcRequest { + + private static METHOD: string = "getPropertiesOfFactory"; + + public constructor( + params: { + factoryId: string, + }, + ) { + super(GetPropertiesOfFactoryRequest.METHOD, params); + } + +} diff --git a/ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts b/ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts new file mode 100644 index 00000000000..7ca2647c505 --- /dev/null +++ b/ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts @@ -0,0 +1,31 @@ +import { EdgeConfig } from "../../edge/edgeconfig"; +import { JsonrpcResponseSuccess } from "../base"; + +/** + * Represents a JSON-RPC Response for a {@link GetPropertiesOfFactoryResponse}. + * + *
    + * {
    + *   "jsonrpc": "2.0",
    + *   "id": UUID,
    + *   "result": {
    + *     "factory": EdgeConfig.Factory,
    + *     "properties": EdgeConfig.FactoryProperty[]
    + *   }
    + * }
    + * 
    + */ +export class GetPropertiesOfFactoryResponse extends JsonrpcResponseSuccess { + + public constructor( + public override readonly id: string, + public override readonly result: { + factory: EdgeConfig.Factory, + properties: EdgeConfig.FactoryProperty[], + }, + ) { + super(id, result); + } + +} + diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index 64997f0428c..fb192b6ae74 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -169,14 +169,10 @@ export class Service extends AbstractService { public getConfig(): Promise { return new Promise((resolve, reject) => { this.getCurrentEdge().then(edge => { - edge.getConfig(this.websocket).pipe( - filter(config => config != null && config.isValid()), - first(), - ).toPromise() - .then(config => resolve(config)) - .catch(reason => reject(reason)); - }) - .catch(reason => reject(reason)); + edge.getFirstValidConfig(this.websocket) + .then(resolve) + .catch(reject); + }).catch(reason => reject(reason)); }); } diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index c751bfd0527..8f3b5d125fd 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -659,7 +659,7 @@ export namespace HistoryUtils { export type DisplayValues = { name: string, /** suffix to the name */ - nameSuffix?: (energyValues: QueryHistoricTimeseriesEnergyResponse) => number | string, + nameSuffix?: (energyValues: QueryHistoricTimeseriesEnergyResponse) => number | string | null, /** Convert the values to be displayed in Chart */ converter: () => any, /** If dataset should be hidden on Init */ diff --git a/ui/src/app/shared/service/websocket.ts b/ui/src/app/shared/service/websocket.ts index a6295c1dbb9..2cfa39ac454 100644 --- a/ui/src/app/shared/service/websocket.ts +++ b/ui/src/app/shared/service/websocket.ts @@ -82,6 +82,7 @@ export class Websocket implements WebsocketInterface { } const token = this.cookieService.get('token'); if (token) { + // Login with Session Token this.login(new AuthenticateWithTokenRequest({ token: token })); this.status = 'authenticating'; @@ -89,7 +90,6 @@ export class Websocket implements WebsocketInterface { } else { // No Token -> directly ask for Login credentials this.status = 'waiting for credentials'; - this.router.navigate(['/login']); } }, }, diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 12eb25994cb..86e15a76d18 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -70,6 +70,19 @@ export class EdgePermission { return !edge.isVersionAtLeast('2024.6.1'); } + /** + * Determines if the edge has only the factories which are used by the + * active components in the edgeconfig or if all factories are inlcuded. + * + * The reason this was introduced is to reduce the size of the EdgeConfig + * and therefore improve performance in network, backend, ui, edge. + * + * @returns true if only the factories of the used components are in the edgeconfig + */ + public static hasReducedFactories(edge: Edge): boolean { + return edge.isVersionAtLeast('2024.6.1'); + } + } export class UserPermission { diff --git a/ui/src/app/shared/status/single/status.component.spec.ts b/ui/src/app/shared/status/single/status.component.spec.ts index 7499acb1944..4f92151f8fb 100644 --- a/ui/src/app/shared/status/single/status.component.spec.ts +++ b/ui/src/app/shared/status/single/status.component.spec.ts @@ -12,7 +12,7 @@ describe('StatusComponent', () => { const testComponent = new EdgeConfig.Component("test", {}, { "testChannel": { accessMode: "RO", - category: "ENUM", + category: "STATE", type: "BOOLEAN", unit: "W", level: "OK", diff --git a/ui/src/app/shared/status/single/status.component.ts b/ui/src/app/shared/status/single/status.component.ts index c1d8c019409..c203e873a27 100644 --- a/ui/src/app/shared/status/single/status.component.ts +++ b/ui/src/app/shared/status/single/status.component.ts @@ -82,6 +82,12 @@ export class StatusSingleComponent implements OnInit, OnDestroy { if (EdgePermission.hasChannelsInEdgeConfig(this.edge)) { const channels: typeof this.channels['componentId'] = {}; for (const [key, value] of Object.entries(this.config.components[componentId].channels)) { + + // show only state channels + if (value.category !== "STATE") { + continue; + } + channels[key] = { text: value.text, level: value.level }; } resolve(channels); diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index fbd56096e39..b582b58c8b2 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -954,5 +954,8 @@ "SET_VALUE": "Eingestellter Wert", "MORE_CHANNELS": "Weitere Kanäle hinzufügen", "CHANNEL": "Kanal" + }, + "APP": { + "FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE": "Diese Funktion ist vorübergehend in der App nicht verfügbar, verwenden Sie bitte dafür die Web-App." } -} +} \ No newline at end of file diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index 3b4def7a994..70acb7994e9 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -957,5 +957,8 @@ "SET_VALUE": "Set value", "MORE_CHANNELS": "Add More Channels", "CHANNEL": "Channel" + }, + "APP": { + "FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE": "This function is temporarily not available in the app, please use the web app instead." } -} +} \ No newline at end of file From d6eaac18841ce38b42b305d417a4b315cb996838 Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:14:23 +0200 Subject: [PATCH 28/37] CI: add Codecov for UI (#2693) --- .github/workflows/build.yml | 8 +++++++- codecov.yml | 3 ++- ui/karma.conf.js | 6 +++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8211dc2cec2..a67813b0d63 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -70,4 +70,10 @@ jobs: node_modules/.bin/ng build -c "openems,openems-edge-prod,prod" node_modules/.bin/ng lint export CHROME_BIN=/usr/bin/google-chrome-stable - npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI \ No newline at end of file + npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4 + with: + directory: ./ui/ + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/codecov.yml b/codecov.yml index 1f9dcb53ef3..00b2350eb74 100644 --- a/codecov.yml +++ b/codecov.yml @@ -4,7 +4,8 @@ coverage: status: project: default: - target: auto #default + target: auto + threshold: 10% comment: layout: "condensed_header, diff" diff --git a/ui/karma.conf.js b/ui/karma.conf.js index 65647d92cac..0980006d7ec 100644 --- a/ui/karma.conf.js +++ b/ui/karma.conf.js @@ -5,6 +5,9 @@ module.exports = function (config) { config.set({ basePath: '', frameworks: ['jasmine', '@angular-devkit/build-angular'], + preprocessor: { + 'src/**/*.ts': ['coverage'] + }, plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), @@ -28,11 +31,12 @@ module.exports = function (config) { dir: require('path').join(__dirname, './coverage/ngv'), subdir: '.', reporters: [ + {type: 'lcov'}, { type: 'html' }, { type: 'text-summary' } ], }, - reporters: ['progress', 'kjhtml'], + reporters: ['progress', 'kjhtml', 'coverage'], port: 9876, colors: true, logLevel: config.LOG_INFO, From 8011483ef5d6e3ff3084663b372468f058a937fa Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 1 Jul 2024 11:34:18 +0200 Subject: [PATCH 29/37] Push version to 2024.7.0 --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 2 +- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index 28910dcf23c..848265f9c22 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -36,7 +36,7 @@ public class OpenemsConstants { /** * The additional version string. */ - public static final String VERSION_STRING = "SNAPSHOT"; + public static final String VERSION_STRING = ""; /** * The complete version as a SemanticVersion. diff --git a/ui/package-lock.json b/ui/package-lock.json index 2fb7e864c4f..b38f652d904 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index 4107030261c..cf51861bf7d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index fec1a68180b..1341682b050 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.7.0-SNAPSHOT"; + public static readonly UI_VERSION = "2024.7.0"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From 30b35800ac5d976017d252097fa27c3a71be6fe6 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 1 Jul 2024 11:43:33 +0200 Subject: [PATCH 30/37] Push version to 2024.7.0 --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 2 +- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index 28910dcf23c..848265f9c22 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -36,7 +36,7 @@ public class OpenemsConstants { /** * The additional version string. */ - public static final String VERSION_STRING = "SNAPSHOT"; + public static final String VERSION_STRING = ""; /** * The complete version as a SemanticVersion. diff --git a/ui/package-lock.json b/ui/package-lock.json index 2fb7e864c4f..b38f652d904 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index 4107030261c..cf51861bf7d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.7.0-SNAPSHOT", + "version": "2024.7.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index fec1a68180b..1341682b050 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.7.0-SNAPSHOT"; + public static readonly UI_VERSION = "2024.7.0"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From a3ca778d6903b10bc79bbd36d30859be58026a91 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 1 Jul 2024 11:45:55 +0200 Subject: [PATCH 31/37] Start development of version 2024.8.0-SNAPSHOT --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 4 ++-- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index 848265f9c22..803d88b7e4a 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -22,7 +22,7 @@ public class OpenemsConstants { *

    * This is the month of the release. */ - public static final short VERSION_MINOR = 7; + public static final short VERSION_MINOR = 8; /** * The patch version of OpenEMS. @@ -36,7 +36,7 @@ public class OpenemsConstants { /** * The additional version string. */ - public static final String VERSION_STRING = ""; + public static final String VERSION_STRING = "SNAPSHOT"; /** * The complete version as a SemanticVersion. diff --git a/ui/package-lock.json b/ui/package-lock.json index b38f652d904..2a040ed94b9 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.7.0", + "version": "2024.8.0-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.7.0", + "version": "2024.8.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~16.2.12", diff --git a/ui/package.json b/ui/package.json index cf51861bf7d..4971ace7628 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.7.0", + "version": "2024.8.0-SNAPSHOT", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 1341682b050..473e291c675 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.7.0"; + public static readonly UI_VERSION = "2024.8.0-SNAPSHOT"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + '. '; From 504954f19d73c244c7feabd69d182ad39ce53abe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:06:50 +0200 Subject: [PATCH 32/37] Bump peaceiris/actions-gh-pages from 3 to 4 in /.github/workflows (#2690) Bumps [peaceiris/actions-gh-pages](https://github.com/peaceiris/actions-gh-pages) from 3 to 4. - [Release notes](https://github.com/peaceiris/actions-gh-pages/releases) - [Changelog](https://github.com/peaceiris/actions-gh-pages/blob/main/CHANGELOG.md) - [Commits](https://github.com/peaceiris/actions-gh-pages/compare/v3...v4) --- updated-dependencies: - dependency-name: peaceiris/actions-gh-pages dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 07b07ba9953..5050d32b4bf 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -24,7 +24,7 @@ jobs: run: ./gradlew buildAntoraDocs --continue - name: Deploy to GitHub pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: personal_token: ${{ secrets.DOCS }} external_repository: OpenEMS/openems.io From aa3f01793194622fdffd87f0923d2f3c77f34197 Mon Sep 17 00:00:00 2001 From: Hiromasa Ihara Date: Mon, 1 Jul 2024 23:18:18 +0900 Subject: [PATCH 33/37] UI: resolve ts-strict and angular compatibility (#2687) * fix: resolve ts-strict -- angular compatibility This change add non-null assertion to angular mandatory component inputs and marked as `required` in input decolation argument. problem background - typescript strictPropertyInitialization option check non-initialized property. - In angular mandatory component inputs has no initialization in ts code. - strictPropertyInitialization dont consider it, so the checking point mandatory component inputs as error. detail procedure for addressing problem 1. finding non-initialized property in angular components. 2. regarding these inputs will be initialized in angular lifecycle (=> mandatory component inputs). 3. marking these inputs peroperty type as non-null assertion type(!). 3. marking these inputs as required directive({ required: true }). --- .../Controller/Ess/TimeOfUseTariff/chart/chart.ts | 2 +- .../Controller/Ess/TimeOfUseTariff/flat/flat.ts | 3 +-- ui/src/app/edge/history/chpsoc/chart.component.ts | 4 ++-- ui/src/app/edge/history/chpsoc/widget.component.ts | 4 ++-- .../edge/history/delayedselltogrid/chart.component.ts | 4 ++-- .../edge/history/delayedselltogrid/widget.component.ts | 4 ++-- .../history/fixdigitaloutput/singlechart.component.ts | 4 ++-- .../history/fixdigitaloutput/totalchart.component.ts | 2 +- .../edge/history/fixdigitaloutput/widget.component.ts | 4 ++-- ui/src/app/edge/history/grid/chart.component.ts | 4 ++-- .../history/gridoptimizedcharge/chart.component.ts | 4 ++-- .../sellToGridLimitChart.component.ts | 4 ++-- .../history/gridoptimizedcharge/widget.component.ts | 4 ++-- .../app/edge/history/heatingelement/chart.component.ts | 4 ++-- .../edge/history/heatingelement/widget.component.ts | 4 ++-- ui/src/app/edge/history/heatpump/chart.component.ts | 4 ++-- ui/src/app/edge/history/heatpump/widget.component.ts | 4 ++-- .../history/peakshaving/asymmetric/chart.component.ts | 4 ++-- .../history/peakshaving/asymmetric/widget.component.ts | 4 ++-- .../history/peakshaving/symmetric/chart.component.ts | 4 ++-- .../history/peakshaving/symmetric/widget.component.ts | 4 ++-- .../history/peakshaving/timeslot/chart.component.ts | 4 ++-- .../history/peakshaving/timeslot/widget.component.ts | 4 ++-- .../edge/history/singlethreshold/chart.component.ts | 6 +++--- .../edge/history/singlethreshold/widget.component.ts | 4 ++-- .../app/edge/history/storage/chargerchart.component.ts | 4 ++-- ui/src/app/edge/history/storage/esschart.component.ts | 6 +++--- .../app/edge/history/storage/singlechart.component.ts | 4 ++-- ui/src/app/edge/history/storage/socchart.component.ts | 2 +- .../app/edge/history/storage/totalchart.component.ts | 4 ++-- ui/src/app/edge/history/storage/widget.component.ts | 2 +- .../live/Controller/ChpSoc/modal/modal.component.ts | 8 ++++---- .../Ess/GridOptimizedCharge/modal/predictionChart.ts | 10 +++++----- .../Ess/TimeOfUseTariff/modal/powerSocChart.ts | 6 +++--- .../Ess/TimeOfUseTariff/modal/statePriceChart.ts | 6 +++--- .../Evcs/administration/administration.component.ts | 4 ++-- .../Io/ChannelSingleThreshold/modal/modal.component.ts | 8 ++++---- .../Io/FixDigitalOutput/modal/modal.component.ts | 5 ++--- .../PeakShaving/Asymmetric/modal/modal.component.ts | 6 +++--- .../PeakShaving/Symmetric/modal/modal.component.ts | 4 ++-- .../live/Io/Api_DigitalInput/modal/modal.component.ts | 4 ++-- .../Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts | 8 ++++---- .../Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts | 4 ++-- .../edge/live/common/storage/modal/modal.component.ts | 6 +++--- .../delayedselltogrid/delayedselltogrid.component.ts | 2 +- .../live/delayedselltogrid/modal/modal.component.ts | 4 ++-- .../safe-input/formly-safe-input-modal.component.ts | 8 ++++---- .../app/edge/settings/app/keypopup/modal.component.ts | 4 ++-- .../edge/settings/system/oe-system-update.component.ts | 2 +- .../app/shared/chartoptions/chartoptions.component.ts | 4 ++-- .../shared/edge/meter/esscharger/modal.component.ts | 3 +-- .../formly/formly-select-field-modal.component.ts | 5 ++--- ui/src/app/shared/formly/formly-skeleton-wrapper.ts | 7 +++---- .../shared/genericComponents/abstracthistorywidget.ts | 8 ++++---- .../genericComponents/chart/abstracthistorychart.ts | 6 +++--- ui/src/app/shared/genericComponents/chart/chart.ts | 2 +- .../flat/flat-widget-line/flat-widget-line.ts | 7 +++---- ui/src/app/shared/genericComponents/flat/flat.ts | 8 ++++---- .../genericComponents/modal/abstract-modal-line.ts | 6 +++--- .../modal/modal-button/modal-button.ts | 3 +-- .../modal/modal-info-line/modal-info-line.ts | 9 ++++----- .../genericComponents/modal/modal-line/modal-line.ts | 9 ++++----- .../modal/modal-value-line/modal-value-line.ts | 6 +++--- ui/src/app/shared/genericComponents/modal/modal.ts | 2 +- .../model-horizontal-line/modal-horizontal-line.ts | 5 ++--- .../shared/percentagebar/percentagebar.component.ts | 3 +-- 66 files changed, 150 insertions(+), 161 deletions(-) diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts index 84ad2eb878e..aeceaec2560 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/chart/chart.ts @@ -13,7 +13,7 @@ import { ColorUtils } from 'src/app/shared/utils/color/color.utils'; }) export class ChartComponent extends AbstractHistoryChart { - @Input() public override component: EdgeConfig.Component; + @Input({ required: true }) public override component!: EdgeConfig.Component; private currencyLabel: Currency.Label; // Default diff --git a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts index eeb4fb4fab2..de855a23302 100644 --- a/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts +++ b/ui/src/app/edge/history/Controller/Ess/TimeOfUseTariff/flat/flat.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; @@ -11,7 +10,7 @@ import { ChannelAddress, CurrentData } from 'src/app/shared/shared'; }) export class FlatComponent extends AbstractFlatWidget { - @Input() public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; protected delayedActiveTimeOverPeriod: number | null = null; protected chargedConsumptionActiveTimeOverPeriod: number | null = null; diff --git a/ui/src/app/edge/history/chpsoc/chart.component.ts b/ui/src/app/edge/history/chpsoc/chart.component.ts index aa37afaee2f..5a5a82d43ec 100644 --- a/ui/src/app/edge/history/chpsoc/chart.component.ts +++ b/ui/src/app/edge/history/chpsoc/chart.component.ts @@ -14,8 +14,8 @@ import { YAxisTitle } from 'src/app/shared/service/utils'; }) export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/chpsoc/widget.component.ts b/ui/src/app/edge/history/chpsoc/widget.component.ts index 090b3ed1da8..78c42a533c8 100644 --- a/ui/src/app/edge/history/chpsoc/widget.component.ts +++ b/ui/src/app/edge/history/chpsoc/widget.component.ts @@ -14,8 +14,8 @@ import { calculateActiveTimeOverPeriod } from '../shared'; }) export class ChpSocWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "chpsocWidget"; diff --git a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts index e51dd2b147c..a1dd843c2b2 100644 --- a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts @@ -14,8 +14,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class DelayedSellToGridChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts index 3b4e3442ca5..85480c54c97 100644 --- a/ui/src/app/edge/history/delayedselltogrid/widget.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/widget.component.ts @@ -10,8 +10,8 @@ import { Edge, Service, EdgeConfig } from 'src/app/shared/shared'; }) export class DelayedSellToGridWidgetComponent implements OnInit { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "delayedSellToGridWidget"; diff --git a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts index 7dba882fa89..e86032d5ff7 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts @@ -16,8 +16,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class FixDigitalOutputSingleChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts index ede98a6e38b..c43325a0c39 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts @@ -15,7 +15,7 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class FixDigitalOutputTotalChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts index f4990c751fb..b640b941b56 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts @@ -14,8 +14,8 @@ import { calculateActiveTimeOverPeriod } from '../shared'; }) export class FixDigitalOutputWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private config: EdgeConfig = null; public component: EdgeConfig.Component = null; diff --git a/ui/src/app/edge/history/grid/chart.component.ts b/ui/src/app/edge/history/grid/chart.component.ts index 285c8d4961e..76758432d1c 100644 --- a/ui/src/app/edge/history/grid/chart.component.ts +++ b/ui/src/app/edge/history/grid/chart.component.ts @@ -15,8 +15,8 @@ import * as Chart from 'chart.js'; }) export class GridChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public showPhases: boolean; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public showPhases!: boolean; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts index 828617a2266..11523c2d1a1 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts @@ -16,8 +16,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class GridOptimizedChargeChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts index 0c556547ae4..6f65d69c923 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts @@ -14,8 +14,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class SellToGridLimitChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; private gridMeter: string; diff --git a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts index fd5361b5b33..5b0d61878a5 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts @@ -12,8 +12,8 @@ import { AbstractHistoryWidget } from '../abstracthistorywidget'; }) export class GridOptimizedChargeWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "gridOptimizedChargeWidget"; diff --git a/ui/src/app/edge/history/heatingelement/chart.component.ts b/ui/src/app/edge/history/heatingelement/chart.component.ts index d2647126584..1835620d460 100644 --- a/ui/src/app/edge/history/heatingelement/chart.component.ts +++ b/ui/src/app/edge/history/heatingelement/chart.component.ts @@ -17,8 +17,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class HeatingelementChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/heatingelement/widget.component.ts b/ui/src/app/edge/history/heatingelement/widget.component.ts index 54c59de124b..1bdd6ae51cb 100644 --- a/ui/src/app/edge/history/heatingelement/widget.component.ts +++ b/ui/src/app/edge/history/heatingelement/widget.component.ts @@ -13,8 +13,8 @@ import { AbstractHistoryWidget } from '../abstracthistorywidget'; }) export class HeatingelementWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "heatingelementWidget"; diff --git a/ui/src/app/edge/history/heatpump/chart.component.ts b/ui/src/app/edge/history/heatpump/chart.component.ts index a026c2e3d71..42e87f0c482 100644 --- a/ui/src/app/edge/history/heatpump/chart.component.ts +++ b/ui/src/app/edge/history/heatpump/chart.component.ts @@ -15,8 +15,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class HeatPumpChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/heatpump/widget.component.ts b/ui/src/app/edge/history/heatpump/widget.component.ts index 14ef01243f7..8bc60b9106c 100644 --- a/ui/src/app/edge/history/heatpump/widget.component.ts +++ b/ui/src/app/edge/history/heatpump/widget.component.ts @@ -13,8 +13,8 @@ import { AbstractHistoryWidget } from '../abstracthistorywidget'; }) export class HeatpumpWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "heatpumpWidget"; diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts index 158d68ca676..8cbe32085b3 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts @@ -14,8 +14,8 @@ import { AbstractHistoryChart } from '../../abstracthistorychart'; }) export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public component!: EdgeConfig.Component; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts index daf215d6681..5a5f8cfaa6f 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/widget.component.ts @@ -10,8 +10,8 @@ import { Edge, Service, EdgeConfig } from 'src/app/shared/shared'; }) export class AsymmetricPeakshavingWidgetComponent implements OnInit { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "asymmetricPeakshavingWidget"; diff --git a/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts index 8cd625e16b9..a7a103273ab 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts @@ -13,8 +13,8 @@ import { AbstractHistoryChart } from '../../abstracthistorychart'; }) export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts index 179d46e5e31..0f8a8392aa8 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/widget.component.ts @@ -10,8 +10,8 @@ import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; }) export class SymmetricPeakshavingWidgetComponent implements OnInit { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "symmetricPeakshavingWidget"; diff --git a/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts index 1e65baae7f0..05ac5a3a27f 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts @@ -14,8 +14,8 @@ import { AbstractHistoryChart } from '../../abstracthistorychart'; }) export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts index ab34310c2a0..39b3fe686cb 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/widget.component.ts @@ -10,8 +10,8 @@ import { Edge, EdgeConfig, Service } from 'src/app/shared/shared'; }) export class TimeslotPeakshavingWidgetComponent implements OnInit { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "timeslotPeakshavingWidget"; diff --git a/ui/src/app/edge/history/singlethreshold/chart.component.ts b/ui/src/app/edge/history/singlethreshold/chart.component.ts index 41371fa0bc4..240c429afd4 100644 --- a/ui/src/app/edge/history/singlethreshold/chart.component.ts +++ b/ui/src/app/edge/history/singlethreshold/chart.component.ts @@ -17,9 +17,9 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class SinglethresholdChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; - @Input() public inputChannelUnit: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; + @Input({ required: true }) public inputChannelUnit!: string; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/singlethreshold/widget.component.ts b/ui/src/app/edge/history/singlethreshold/widget.component.ts index 5af56a066b8..d8c1dce7e06 100644 --- a/ui/src/app/edge/history/singlethreshold/widget.component.ts +++ b/ui/src/app/edge/history/singlethreshold/widget.component.ts @@ -14,8 +14,8 @@ import { calculateActiveTimeOverPeriod } from '../shared'; }) export class SinglethresholdWidgetComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private static readonly SELECTOR = "singlethresholdWidget"; diff --git a/ui/src/app/edge/history/storage/chargerchart.component.ts b/ui/src/app/edge/history/storage/chargerchart.component.ts index 354e37e2aec..093f68da279 100644 --- a/ui/src/app/edge/history/storage/chargerchart.component.ts +++ b/ui/src/app/edge/history/storage/chargerchart.component.ts @@ -13,8 +13,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class StorageChargerChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; private moreThanOneProducer: boolean = null; diff --git a/ui/src/app/edge/history/storage/esschart.component.ts b/ui/src/app/edge/history/storage/esschart.component.ts index 507377c51dd..10f63f0715a 100644 --- a/ui/src/app/edge/history/storage/esschart.component.ts +++ b/ui/src/app/edge/history/storage/esschart.component.ts @@ -14,9 +14,9 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; export class StorageESSChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public componentId: string; - @Input() public showPhases: boolean; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public componentId!: string; + @Input({ required: true }) public showPhases!: boolean; private moreThanOneProducer: boolean = null; diff --git a/ui/src/app/edge/history/storage/singlechart.component.ts b/ui/src/app/edge/history/storage/singlechart.component.ts index 44bebe80fff..54c71ec221f 100644 --- a/ui/src/app/edge/history/storage/singlechart.component.ts +++ b/ui/src/app/edge/history/storage/singlechart.component.ts @@ -16,8 +16,8 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class StorageSingleChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public showPhases: boolean; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public showPhases!: boolean; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/storage/socchart.component.ts b/ui/src/app/edge/history/storage/socchart.component.ts index b6e67531da2..b185c72cc30 100644 --- a/ui/src/app/edge/history/storage/socchart.component.ts +++ b/ui/src/app/edge/history/storage/socchart.component.ts @@ -14,7 +14,7 @@ import { AbstractHistoryChart } from '../abstracthistorychart'; }) export class SocStorageChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; private emergencyCapacityReserveComponents: EdgeConfig.Component[] = []; public ngOnChanges() { diff --git a/ui/src/app/edge/history/storage/totalchart.component.ts b/ui/src/app/edge/history/storage/totalchart.component.ts index 36cfb326953..e371ec9121e 100644 --- a/ui/src/app/edge/history/storage/totalchart.component.ts +++ b/ui/src/app/edge/history/storage/totalchart.component.ts @@ -15,8 +15,8 @@ import { formatNumber } from '@angular/common'; templateUrl: '../abstracthistorychart.html', }) export class StorageTotalChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; - @Input() public showPhases: boolean; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public showPhases!: boolean; ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/history/storage/widget.component.ts b/ui/src/app/edge/history/storage/widget.component.ts index 1673230f739..185c962da11 100644 --- a/ui/src/app/edge/history/storage/widget.component.ts +++ b/ui/src/app/edge/history/storage/widget.component.ts @@ -12,7 +12,7 @@ import { AbstractHistoryWidget } from '../abstracthistorywidget'; }) export class StorageComponent extends AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) public period!: DefaultTypes.HistoryPeriod; private static readonly SELECTOR = "storageWidget"; diff --git a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts index 3a4ab019f79..636e1265b75 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/ChpSoc/modal/modal.component.ts @@ -17,10 +17,10 @@ export class Controller_ChpSocModalComponent implements OnInit { private static readonly SELECTOR = "chpsoc-modal"; - @Input() public edge: Edge; - @Input() public component: EdgeConfig.Component; - @Input() public outputChannel: ChannelAddress; - @Input() public inputChannel: ChannelAddress; + @Input({ required: true }) public edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; + @Input({ required: true }) public outputChannel!: ChannelAddress; + @Input({ required: true }) public inputChannel!: ChannelAddress; public thresholds: RangeValue = { lower: null, diff --git a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/predictionChart.ts b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/predictionChart.ts index 746098619b3..66d67ee2cf5 100644 --- a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/predictionChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/predictionChart.ts @@ -15,11 +15,11 @@ import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from 'src/app/shared }) export class PredictionChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() protected refresh: boolean; - @Input() protected override edge: Edge; - @Input() public component: EdgeConfig.Component; - @Input() public targetEpochSeconds: number; - @Input() public chargeStartEpochSeconds: number; + @Input({ required: true }) protected refresh!: boolean; + @Input({ required: true }) protected override edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; + @Input({ required: true }) public targetEpochSeconds!: number; + @Input({ required: true }) public chargeStartEpochSeconds!: number; private static DEFAULT_PERIOD: DefaultTypes.HistoryPeriod = new DefaultTypes.HistoryPeriod(new Date(), new Date()); diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts index 562a139ceae..37e03611dc0 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/powerSocChart.ts @@ -18,9 +18,9 @@ import { GetScheduleResponse } from '../../../../../../shared/jsonrpc/response/g }) export class SchedulePowerAndSocChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public refresh: boolean; - @Input() public override edge: Edge; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public refresh!: boolean; + @Input({ required: true }) public override edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; public ngOnChanges() { this.updateChart(); diff --git a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts index cb6fc333a81..797f22701c0 100644 --- a/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/TimeOfUseTariff/modal/statePriceChart.ts @@ -21,9 +21,9 @@ import { Controller_Ess_TimeOfUseTariff } from '../Ess_TimeOfUseTariff'; }) export class ScheduleStateAndPriceChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - @Input() public refresh: boolean; - @Input() public override edge: Edge; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public refresh!: boolean; + @Input({ required: true }) public override edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; private currencyLabel: Currency.Label; // Default diff --git a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts index bc9fb3b4fef..9fafeee392b 100644 --- a/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts +++ b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts @@ -11,8 +11,8 @@ import { Edge, EdgeConfig, Service, Websocket } from '../../../../../shared/shar }) export class AdministrationComponent implements OnInit { - @Input() public evcsComponent: EdgeConfig.Component; - @Input() public edge: Edge; + @Input({ required: true }) public evcsComponent!: EdgeConfig.Component; + @Input({ required: true }) public edge!: Edge; private static readonly SELECTOR = "administration"; diff --git a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts index 5e58e17716d..93ea4683053 100644 --- a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/modal/modal.component.ts @@ -14,11 +14,11 @@ type inputMode = 'SOC' | 'GRIDSELL' | 'GRIDBUY' | 'PRODUCTION' | 'OTHER'; }) export class Controller_Io_ChannelSingleThresholdModalComponent implements OnInit { - @Input() public edge: Edge; - @Input() public config: EdgeConfig; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public edge!: Edge; + @Input({ required: true }) public config!: EdgeConfig; + @Input({ required: true }) public component!: EdgeConfig.Component; @Input() public outputChannel: ChannelAddress | null = null; - @Input() public inputChannel: ChannelAddress; + @Input({ required: true }) public inputChannel!: ChannelAddress; @Input() public inputChannelUnit: string | null = null; public formGroup: FormGroup; diff --git a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts index 3a6111ccab2..b1564acb6da 100644 --- a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/modal/modal.component.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { Router } from '@angular/router'; import { ModalController } from '@ionic/angular'; @@ -11,8 +10,8 @@ import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; }) export class Controller_Io_FixDigitalOutputModalComponent { - @Input() public edge: Edge; - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public edge!: Edge; + @Input({ required: true }) public component!: EdgeConfig.Component; constructor( public service: Service, diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts index 751df3e54b1..327a63386d6 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/modal/modal.component.ts @@ -12,9 +12,9 @@ import { Edge, EdgeConfig, Service, Websocket } from '../../../../../../shared/s }) export class Controller_Asymmetric_PeakShavingModalComponent implements OnInit { - @Input() protected component: EdgeConfig.Component; - @Input() protected edge: Edge; - @Input() protected mostStressedPhase: Subject<{ name: 'L1' | 'L2' | 'L3' | '', value: number }>; + @Input({ required: true }) protected component!: EdgeConfig.Component; + @Input({ required: true }) protected edge!: Edge; + @Input({ required: true }) protected mostStressedPhase!: Subject<{ name: 'L1' | 'L2' | 'L3' | '', value: number }>; public formGroup: FormGroup; public loading: boolean = false; diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts index 2f1c86eed96..b733e98f5b9 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/modal/modal.component.ts @@ -11,8 +11,8 @@ import { Edge, EdgeConfig, Service, Websocket } from '../../../../../../shared/s }) export class Controller_Symmetric_PeakShavingModalComponent implements OnInit { - @Input() protected component: EdgeConfig.Component; - @Input() protected edge: Edge; + @Input({ required: true }) protected component!: EdgeConfig.Component; + @Input({ required: true }) protected edge!: Edge; public formGroup: FormGroup; diff --git a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts index eda63d38897..5169a6f4ae5 100644 --- a/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts +++ b/ui/src/app/edge/live/Io/Api_DigitalInput/modal/modal.component.ts @@ -13,8 +13,8 @@ import { JsonrpcRequest, JsonrpcResponseSuccess } from 'src/app/shared/jsonrpc/b export class Io_Api_DigitalInput_ModalComponent implements OnInit, OnDestroy { private static readonly SELECTOR = "Io_Api_DigitalInput_ModalComponent"; - @Input() public edge: Edge; - @Input() public ioComponents: EdgeConfig.Component[]; + @Input({ required: true }) public edge!: Edge; + @Input({ required: true }) public ioComponents!: EdgeConfig.Component[]; protected digitalInputChannelsPerComponent: { componentId: string, componentAlias: string, channels: Channel[] }[]; diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts index 75ba5857c7a..a80251edbf6 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart.ts @@ -13,11 +13,11 @@ import { TranslateService } from '@ngx-translate/core'; }) export class EvcsChartComponent implements OnInit, OnChanges { - @Input() private evcsMap: { [sourceId: string]: EdgeConfig.Component }; - @Input() private edge: Edge; - @Input() private currentData: CurrentData; + @Input({ required: true }) private evcsMap!: { [sourceId: string]: EdgeConfig.Component }; + @Input({ required: true }) private edge!: Edge; + @Input({ required: true }) private currentData!: CurrentData; @Input() private evcsConfigMap: { [evcsId: string]: EdgeConfig.Component } = {}; - @Input() private componentId: string; + @Input({ required: true }) private componentId!: string; private static readonly SELECTOR = "evcsChart"; public loading: boolean = true; diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts index 065900afded..c6c79c7e69c 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page.ts @@ -14,9 +14,9 @@ type Priority = 'CAR' | 'STORAGE'; }) export class Evcs_Api_ClusterModalComponent implements OnInit { - @Input() public edge: Edge; + @Input({ required: true }) public edge!: Edge; @Input() public config: EdgeConfig.Component = null; - @Input() public componentId: string; + @Input({ required: true }) public componentId!: string; @Input() public evcsMap: { [sourceId: string]: EdgeConfig.Component } = {}; @ViewChild(IonReorderGroup, { static: true }) diff --git a/ui/src/app/edge/live/common/storage/modal/modal.component.ts b/ui/src/app/edge/live/common/storage/modal/modal.component.ts index 8fc10a04131..0c4de15b7d4 100644 --- a/ui/src/app/edge/live/common/storage/modal/modal.component.ts +++ b/ui/src/app/edge/live/common/storage/modal/modal.component.ts @@ -15,10 +15,10 @@ export class StorageModalComponent implements OnInit, OnDestroy { // TODO after refactoring of Model: subscribe to EssActivePowerL1/L2/L3 here instead of Flat Widget - @Input() protected edge: Edge; - @Input() protected config: EdgeConfig; + @Input({ required: true }) protected edge!: Edge; + @Input({ required: true }) protected config!: EdgeConfig; @Input() protected essComponents: EdgeConfig.Component[] | null = null; - @Input() protected chargerComponents: EdgeConfig.Component[]; + @Input({ required: true }) protected chargerComponents!: EdgeConfig.Component[]; @Input() protected singleComponent: EdgeConfig.Component = null; // reference to the Utils method to access via html diff --git a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts index 5f14f0149a4..ea2ca6e7d0a 100644 --- a/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts +++ b/ui/src/app/edge/live/delayedselltogrid/delayedselltogrid.component.ts @@ -14,7 +14,7 @@ export class DelayedSellToGridComponent implements OnInit, OnDestroy { private static readonly SELECTOR = "delayedselltogrid"; - @Input() public componentId: string; + @Input({ required: true }) public componentId!: string; public edge: Edge = null; diff --git a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts index c9a4efbb5b5..e8cd66dad20 100644 --- a/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts +++ b/ui/src/app/edge/live/delayedselltogrid/modal/modal.component.ts @@ -11,8 +11,8 @@ import { Edge, EdgeConfig, Service, Websocket } from '../../../../shared/shared' }) export class DelayedSellToGridModalComponent implements OnInit { - @Input() protected component: EdgeConfig.Component; - @Input() protected edge: Edge; + @Input({ required: true }) protected component!: EdgeConfig.Component; + @Input({ required: true }) protected edge!: Edge; private static readonly SELECTOR = "delayedselltogrid-modal"; diff --git a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts index 745dcf43183..60ef52e3be1 100644 --- a/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts +++ b/ui/src/app/edge/settings/app/formly/safe-input/formly-safe-input-modal.component.ts @@ -10,12 +10,12 @@ import { FormlyFieldConfig } from "@ngx-formly/core"; }) export class FormlySafeInputModalComponent implements OnInit { - @Input() - protected title: string; + @Input({ required: true }) + protected title!: string; @Input() protected fields: FormlyFieldConfig[] = null; - @Input() - protected model: {}; + @Input({ required: true }) + protected model!: {}; protected form: FormGroup = new FormGroup({}); protected myModel: {}; diff --git a/ui/src/app/edge/settings/app/keypopup/modal.component.ts b/ui/src/app/edge/settings/app/keypopup/modal.component.ts index d94779ef5c8..43c1345b999 100644 --- a/ui/src/app/edge/settings/app/keypopup/modal.component.ts +++ b/ui/src/app/edge/settings/app/keypopup/modal.component.ts @@ -22,10 +22,10 @@ import { hasPredefinedKey } from '../permissions'; }) export class KeyModalComponent implements OnInit { - @Input() public edge: Edge; + @Input({ required: true }) public edge!: Edge; @Input() public appId: string | null = null; @Input() public appName: string | null = null; - @Input() public behaviour: KeyValidationBehaviour; + @Input({ required: true }) public behaviour!: KeyValidationBehaviour; @Input() public knownApps: GetApps.App[] | null = null; diff --git a/ui/src/app/edge/settings/system/oe-system-update.component.ts b/ui/src/app/edge/settings/system/oe-system-update.component.ts index 7b0689beab5..b04d15d2f26 100644 --- a/ui/src/app/edge/settings/system/oe-system-update.component.ts +++ b/ui/src/app/edge/settings/system/oe-system-update.component.ts @@ -15,7 +15,7 @@ export class OeSystemUpdateComponent implements OnInit, OnDestroy { @Output() public stateChanged: EventEmitter = new EventEmitter(); @Input() public executeUpdateInstantly: boolean = false; - @Input() public edge: Edge; + @Input({ required: true }) public edge!: Edge; public readonly environment = environment; public readonly spinnerId: string = OeSystemUpdateComponent.SELECTOR; diff --git a/ui/src/app/shared/chartoptions/chartoptions.component.ts b/ui/src/app/shared/chartoptions/chartoptions.component.ts index d7cefe3fd04..842a726c003 100644 --- a/ui/src/app/shared/chartoptions/chartoptions.component.ts +++ b/ui/src/app/shared/chartoptions/chartoptions.component.ts @@ -11,8 +11,8 @@ import { TranslateService } from '@ngx-translate/core'; }) export class ChartOptionsComponent { - @Input() public showPhases: boolean | null; - @Input() public showTotal: boolean | null; + @Input({ required: true }) public showPhases!: boolean | null; + @Input({ required: true }) public showTotal!: boolean | null; @Output() public setShowPhases = new EventEmitter(); @Output() public setShowTotal = new EventEmitter(); diff --git a/ui/src/app/shared/edge/meter/esscharger/modal.component.ts b/ui/src/app/shared/edge/meter/esscharger/modal.component.ts index 594394991e8..e0f8bc8887d 100644 --- a/ui/src/app/shared/edge/meter/esscharger/modal.component.ts +++ b/ui/src/app/shared/edge/meter/esscharger/modal.component.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { Converter } from 'src/app/shared/genericComponents/shared/converter'; import { Utils } from 'src/app/shared/shared'; @@ -10,7 +9,7 @@ import { EdgeConfig } from '../../edgeconfig'; templateUrl: './modal.component.html', }) export class EssChargerComponent { - @Input() public component: EdgeConfig.Component; + @Input({ required: true }) public component!: EdgeConfig.Component; protected readonly Role = Role; protected readonly Utils = Utils; protected readonly Converter = Converter; diff --git a/ui/src/app/shared/formly/formly-select-field-modal.component.ts b/ui/src/app/shared/formly/formly-select-field-modal.component.ts index d2a72af4576..2ef2314fced 100644 --- a/ui/src/app/shared/formly/formly-select-field-modal.component.ts +++ b/ui/src/app/shared/formly/formly-select-field-modal.component.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input, OnInit } from "@angular/core"; import { ModalController } from "@ionic/angular"; @@ -8,8 +7,8 @@ import { ModalController } from "@ionic/angular"; }) export class FormlySelectFieldModalComponent implements OnInit { - @Input() public title: string; - @Input() public options: { label: string, value: string, description?: string }[]; + @Input({ required: true }) public title!: string; + @Input({ required: true }) public options!: { label: string, value: string, description?: string }[]; @Input() public initialSelectedValue: string | null = null; diff --git a/ui/src/app/shared/formly/formly-skeleton-wrapper.ts b/ui/src/app/shared/formly/formly-skeleton-wrapper.ts index fdc339aebae..f0c2bb276dd 100644 --- a/ui/src/app/shared/formly/formly-skeleton-wrapper.ts +++ b/ui/src/app/shared/formly/formly-skeleton-wrapper.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { FormlyFieldConfig } from '@ngx-formly/core'; @@ -25,7 +24,7 @@ import { FormlyFieldConfig } from '@ngx-formly/core'; }) export class FormlyFieldWithLoadingAnimationComponent { @Input() public show: boolean = false; - @Input() public fields: FormlyFieldConfig[]; - @Input() public form: FormGroup; - @Input() public model: any; + @Input({ required: true }) public fields!: FormlyFieldConfig[]; + @Input({ required: true }) public form!: FormGroup; + @Input({ required: true }) public model!: any; } diff --git a/ui/src/app/shared/genericComponents/abstracthistorywidget.ts b/ui/src/app/shared/genericComponents/abstracthistorywidget.ts index 6786e3e0417..550a34c1907 100644 --- a/ui/src/app/shared/genericComponents/abstracthistorywidget.ts +++ b/ui/src/app/shared/genericComponents/abstracthistorywidget.ts @@ -12,11 +12,11 @@ import { v4 as uuidv4 } from 'uuid'; @Directive() export abstract class AbstractHistoryWidget implements OnInit, OnChanges, OnDestroy { - @Input() - public period: DefaultTypes.HistoryPeriod; + @Input({ required: true }) + public period!: DefaultTypes.HistoryPeriod; - @Input() - protected componentId: string; + @Input({ required: true }) + protected componentId!: string; /** * True after this.edge, this.config and this.component are set. diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts index 6cfedde7115..b134b507eed 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts @@ -37,9 +37,9 @@ export abstract class AbstractHistoryChart implements OnInit { @Input() public chartTitle: string = ""; /** TODO: workaround with Observables, to not have to pass the period on Initialisation */ - @Input() public component: EdgeConfig.Component; - @Input() public showPhases: boolean; - @Input() public showTotal: boolean; + @Input() public component?: EdgeConfig.Component; + @Input() public showPhases: boolean = false; + @Input() public showTotal: boolean = false; @Input() public isOnlyChart: boolean = false; public edge: Edge | null = null; diff --git a/ui/src/app/shared/genericComponents/chart/chart.ts b/ui/src/app/shared/genericComponents/chart/chart.ts index 35436b36467..d9e1da57d0b 100644 --- a/ui/src/app/shared/genericComponents/chart/chart.ts +++ b/ui/src/app/shared/genericComponents/chart/chart.ts @@ -23,7 +23,7 @@ export class ChartComponent implements OnInit, OnChanges { @Input() public isPopoverNeeded: boolean = false; // Manually trigger ChangeDetection through Inputchange - @Input() private period: DefaultTypes.PeriodString; + @Input() private period?: DefaultTypes.PeriodString; protected showPopover: boolean = false; constructor( diff --git a/ui/src/app/shared/genericComponents/flat/flat-widget-line/flat-widget-line.ts b/ui/src/app/shared/genericComponents/flat/flat-widget-line/flat-widget-line.ts index 7ce3eab9718..78d3dcabd73 100644 --- a/ui/src/app/shared/genericComponents/flat/flat-widget-line/flat-widget-line.ts +++ b/ui/src/app/shared/genericComponents/flat/flat-widget-line/flat-widget-line.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; @@ -9,10 +8,10 @@ import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; }) export class FlatWidgetLineComponent extends AbstractFlatWidgetLine { /** Name for parameter, displayed on the left side */ - @Input() - public name: string; + @Input({ required: true }) + public name!: string; /** Width of left Column, right Column is (100 - width of left Column) */ @Input() - public leftColumnWidth: number; + public leftColumnWidth?: number; } diff --git a/ui/src/app/shared/genericComponents/flat/flat.ts b/ui/src/app/shared/genericComponents/flat/flat.ts index c15744a15ed..5d651dd208f 100644 --- a/ui/src/app/shared/genericComponents/flat/flat.ts +++ b/ui/src/app/shared/genericComponents/flat/flat.ts @@ -9,14 +9,14 @@ import { Icon } from 'src/app/shared/type/widget'; export class FlatWidgetComponent { /** Image in Header */ - @Input() public img: string; + @Input() public img?: string; /** Icon in Header */ - @Input() public icon: Icon = null; + @Input() public icon: Icon | null = null; /** BackgroundColor of the Header (light or dark) */ - @Input() public color: string; + @Input() public color?: string; /** Title in Header */ - @Input() public title: string; + @Input() public title?: string; } diff --git a/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts b/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts index 5381137990c..77bfd7fc851 100644 --- a/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts @@ -17,13 +17,13 @@ import { Filter } from "../shared/filter"; export abstract class AbstractModalLine implements OnInit, OnDestroy, OnChanges { /** FormGroup */ - @Input() public formGroup: FormGroup; + @Input({ required: true }) public formGroup!: FormGroup; /** component */ @Input() public component: EdgeConfig.Component = null; /** FormGroup ControlName */ - @Input() public controlName: string; + @Input({ required: true }) public controlName!: string; /** * Use `converter` to convert/map a CurrentData value to another value, e.g. an Enum number to a text. @@ -53,7 +53,7 @@ export abstract class AbstractModalLine implements OnInit, OnDestroy, OnChanges } } - @Input() public value: number | string; + @Input({ required: true }) public value!: number | string; @Input() public roleIsAtLeast?: Role = Role.GUEST; protected show: boolean = true; diff --git a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts index 0c118509ce9..ffa19945c66 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-button/modal-button.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { Icon } from "src/app/shared/type/widget"; import { AbstractModalLine } from "../abstract-modal-line"; @@ -9,7 +8,7 @@ import { AbstractModalLine } from "../abstract-modal-line"; }) export class ModalButtonsComponent extends AbstractModalLine { - @Input() protected buttons: ButtonLabel[]; + @Input({ required: true }) protected buttons!: ButtonLabel[]; } export type ButtonLabel = { diff --git a/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts b/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts index ec2b7ff70d1..a1138593a91 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-info-line/modal-info-line.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { Icon } from "src/app/shared/type/widget"; @@ -9,15 +8,15 @@ import { Icon } from "src/app/shared/type/widget"; export class ModalInfoLineComponent { /** Icon, displayed on the left side */ - @Input() protected icon: Icon; + @Input({ required: true }) protected icon!: Icon; /** * Info-Text, displayed on the right side, optional style for all lines * Multiple lines with own style is possible * */ - @Input() public info: { text: string, lineStyle?: string }[] | string; + @Input({ required: true }) public info!: { text: string, lineStyle?: string }[] | string; - @Input() protected lineStyle: string; + @Input({ required: true }) protected lineStyle!: string; - @Input() protected rowStyle: string; + @Input({ required: true }) protected rowStyle!: string; } diff --git a/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts b/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts index 9da02e03038..ce9542a386d 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; import { AbstractModalLine } from "../abstract-modal-line"; import { ButtonLabel } from "../modal-button/modal-button"; @@ -10,14 +9,14 @@ import { ButtonLabel } from "../modal-button/modal-button"; export class ModalLineComponent extends AbstractModalLine { // Width of Left Column, Right Column is (100% - leftColumn) - @Input() - protected leftColumnWidth: number; + @Input({ required: true }) + protected leftColumnWidth!: number; /** ControlName for Form Field */ - @Input() public override controlName: string; + @Input({ required: true }) public override controlName!: string; @Input() protected button: ButtonLabel | null = null; /** ControlName for Toggle Button */ - @Input() protected control: + @Input({ required: true }) protected control!: { type: 'TOGGLE' } | { type: 'INPUT', properties?: {unit:'W'} } | /* the available select options*/ diff --git a/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts b/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts index 6f5ce00db9a..a6946e68d33 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-value-line/modal-value-line.ts @@ -20,11 +20,11 @@ export class ModalValueLineComponent extends AbstractModalLine { return this.channels; } - @Input() private valueCallback: (currentData: CurrentData) => string; + @Input({ required: true }) private valueCallback!: (currentData: CurrentData) => string; // Width of Left Column, Right Column is (100% - leftColumn) - @Input() - protected leftColumnWidth: number; + @Input({ required: true }) + protected leftColumnWidth!: number; /** Fixed indentation of the modal-line */ @Input() protected textIndent: TextIndentation = TextIndentation.NONE; diff --git a/ui/src/app/shared/genericComponents/modal/modal.ts b/ui/src/app/shared/genericComponents/modal/modal.ts index df2dab11224..7911468e26b 100644 --- a/ui/src/app/shared/genericComponents/modal/modal.ts +++ b/ui/src/app/shared/genericComponents/modal/modal.ts @@ -29,7 +29,7 @@ export class ModalComponent { @Input() protected formGroup: FormGroup = new FormGroup({}); /** Title in Header */ - @Input() public title: string; + @Input({ required: true }) public title!: string; @Input() protected toolbarButtons: { url: string, icon: Icon }[] | { url: string, icon: Icon } | { callback: () => diff --git a/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts b/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts index 03214110464..b6971de84de 100644 --- a/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/model-horizontal-line/modal-horizontal-line.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from "@angular/core"; /** @@ -11,7 +10,7 @@ import { Component, Input } from "@angular/core"; export class ModalHorizontalLineComponent { /** Components-Array to iterate over */ - @Input() protected components: any[]; + @Input({ required: true }) protected components!: any[]; /** index is an iterator */ - @Input() protected index: number; + @Input({ required: true }) protected index!: number; } diff --git a/ui/src/app/shared/percentagebar/percentagebar.component.ts b/ui/src/app/shared/percentagebar/percentagebar.component.ts index dfa6da83147..221c1a837ad 100644 --- a/ui/src/app/shared/percentagebar/percentagebar.component.ts +++ b/ui/src/app/shared/percentagebar/percentagebar.component.ts @@ -1,4 +1,3 @@ -// @ts-strict-ignore import { Component, Input } from '@angular/core'; @Component({ @@ -7,7 +6,7 @@ import { Component, Input } from '@angular/core'; }) export class PercentageBarComponent { - @Input() public value: number; + @Input({ required: true }) public value!: number; @Input() public showPercentageValue: boolean = true; constructor( From b82772be20c22804221cce3b5cb79f18e1d4aad9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 23:33:58 +0200 Subject: [PATCH 34/37] Bump docker/build-push-action from 5 to 6 in /.github/workflows (#2689) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5...v6) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 37698ef7701..df0a15180f9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -78,7 +78,7 @@ jobs: type=raw,value=develop,enable=${{ github.ref == 'refs/heads/develop' }} - name: Build and push Docker images - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: file: ${{ matrix.dockerfile }} platforms: linux/amd64, linux/arm64 From 99f1b6dc748fd3b476bf7dde4afc4004cce3e233 Mon Sep 17 00:00:00 2001 From: HarmOtten <10838083+HarmOtten@users.noreply.github.com> Date: Mon, 1 Jul 2024 23:46:31 +0200 Subject: [PATCH 35/37] Docs: fix typo (#1150) Co-authored-by: Stefan Feilmeier --- doc/modules/ROOT/pages/edge/deploy.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/modules/ROOT/pages/edge/deploy.adoc b/doc/modules/ROOT/pages/edge/deploy.adoc index cbeeb1fad82..2088195edbd 100644 --- a/doc/modules/ROOT/pages/edge/deploy.adoc +++ b/doc/modules/ROOT/pages/edge/deploy.adoc @@ -16,7 +16,7 @@ This guide covers a simple, manual approach. For productive systems it is requir Prerequisites: * A target device running Debian Linux like a Raspberry Pi, Beaglebone Black or an IoT gateway. You need the IP address and SSH access. -* Create a JAR-file that should be deployes. See xref:edge/build.adoc[Build OpenEMS Edge] for details. Alternatively you may download the latest release `openems-edge.jar` file from https://github.com/OpenEMS/openems/releases[GitHub] under _Assets_. +* Create a JAR-file that should be deployed. See xref:edge/build.adoc[Build OpenEMS Edge] for details. Alternatively you may download the latest release `openems-edge.jar` file from https://github.com/OpenEMS/openems/releases[GitHub] under _Assets_. * Setup an SSH client to connect to the Linux console, e.g. http://www.9bis.net/kitty/[KiTTY] * Setup an SCP client to copy the JAR file via SSH, e.g. https://winscp.net/eng/docs/lang:de[WinSCP] @@ -132,4 +132,4 @@ Execute `systemctl restart openems --no-block; journalctl -lfu openems` The command restarts the service (_systemctl restart openems_) while not waiting for the OpenEMS startup notification (_--no-block_). Then it directly prints the OpenEMS system log (_journalctl -lfu openems_). + .OpenEMS Edge start-up -image::deploy-openems-start.png[OpenEMS Edge start-up] \ No newline at end of file +image::deploy-openems-start.png[OpenEMS Edge start-up] From 051489e41aba2e4f21ec91adc7152e427e1c4ad2 Mon Sep 17 00:00:00 2001 From: parapluplu Date: Wed, 3 Jul 2024 11:46:10 +0200 Subject: [PATCH 36/37] Unit Tests: Add test case for alphabetical scheduler (#2698) * Unit Tests: Add test case for alphabetical scheduler * Improve test coverage; fix Eclipse autoformat --------- Co-authored-by: Felix Remmel Co-authored-by: Stefan Feilmeier --- .../SchedulerAllAlphabeticallyImplTest.java | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java b/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java index d70d542d30b..204e4e48109 100644 --- a/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java +++ b/io.openems.edge.scheduler.allalphabetically/test/io/openems/edge/scheduler/allalphabetically/SchedulerAllAlphabeticallyImplTest.java @@ -2,7 +2,9 @@ import static org.junit.Assert.assertEquals; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.Test; @@ -25,7 +27,7 @@ public class SchedulerAllAlphabeticallyImplTest { private static final String CTRL4_ID = "ctrl4"; @Test - public void test() throws Exception { + public void testWithFixedPriorities() throws Exception { final SchedulerAllAlphabetically sut = new SchedulerAllAlphabeticallyImpl(); new ComponentTest(sut) // .addReference("componentManager", new DummyComponentManager()) // @@ -36,15 +38,55 @@ public void test() throws Exception { .addComponent(new DummyController(CTRL4_ID)) // .activate(MyConfig.create() // .setId(SCHEDULER_ID) // - .setControllersIds(CTRL2_ID, CTRL1_ID) // + .setControllersIds(CTRL2_ID, CTRL1_ID, "") // .build()) - .next(new TestCase()); + .next(new TestCase()) // + .deactivate(); assertEquals(// Arrays.asList(CTRL2_ID, CTRL1_ID, CTRL0_ID, CTRL3_ID, CTRL4_ID), // getControllerIds(sut)); } + @Test + public void testOnlyAlphabeticalOrdering() throws Exception { + final var controllerIds = new ArrayList<>(List.of(// + "ctrlController1", // + "a", // + "aa", // + "aA", // + "ab", // + "aB", // + "A", // + "0", // + "1", // + "0controller", // + "0Controller", // + "bla", // + "controller0", // + "controller1", // + "dontroller0", // + "dontroller1", // + "d0", // + "D0", // + "Z", // + "z")); + final var sut = new SchedulerAllAlphabeticallyImpl(); + final var test = new ComponentTest(sut); // + controllerIds.forEach(controllerId -> test.addComponent(new DummyController(controllerId))); + test // + .addReference("componentManager", new DummyComponentManager()) // + .activate(MyConfig.create() // + .setId(SCHEDULER_ID) // + .setControllersIds() // + .build()) // + .next(new TestCase()); + + Collections.sort(controllerIds); + + assertEquals(controllerIds, getControllerIds(sut)); + } + private static List getControllerIds(Scheduler scheduler) throws OpenemsNamedException { return scheduler.getControllers().stream() // .toList(); From 7b6e98245d21dc816920e3077b1bb331b637dd63 Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Wed, 3 Jul 2024 16:45:55 +0200 Subject: [PATCH 37/37] CI: Update build actions (#2697) * ui coverage * name artifacts * Update release.yml --- .github/workflows/build.yml | 10 ++++++---- .github/workflows/release.yml | 32 +++++++++++++++++++------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a67813b0d63..6f1d4022ad0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,11 +22,14 @@ jobs: - uses: kiancross/checkstyle-annotations-action@v1 + - name: Checkstyle + run: ./gradlew checkstyleAll --console=plain --warn + - name: Build all Java packages - run: ./gradlew build + run: ./gradlew build --console=plain --warn - name: Resolve OpenEMS bundles - run: ./gradlew resolve + run: ./gradlew resolve --console=plain --warn - name: Validate BackendApp.bndrun run: git diff --exit-code io.openems.backend.application/BackendApp.bndrun @@ -64,13 +67,12 @@ jobs: - name: Build OpenEMS UI run: | cd ui - npm install npm ci --prefer-offline --cache ~/.npm node_modules/.bin/ng config cli.cache.path "~/.ng" node_modules/.bin/ng build -c "openems,openems-edge-prod,prod" node_modules/.bin/ng lint export CHROME_BIN=/usr/bin/google-chrome-stable - npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI + npm run test -- --code-coverage --no-watch --no-progress --browsers=ChromeHeadlessCI - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8acfebfebf7..aaf7c10fc6e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,11 +20,14 @@ jobs: - uses: kiancross/checkstyle-annotations-action@v1 + - name: Checkstyle + run: ./gradlew checkstyleAll --console=plain --warn + - name: Build all Java packages - run: ./gradlew build + run: ./gradlew build --console=plain --warn - name: Resolve OpenEMS bundles - run: ./gradlew resolve + run: ./gradlew resolve --console=plain --warn - name: Validate BackendApp.bndrun run: git diff --exit-code io.openems.backend.application/BackendApp.bndrun @@ -33,12 +36,12 @@ jobs: run: git diff --exit-code io.openems.edge.application/EdgeApp.bndrun - name: Prepare Edge+Backend assets - run: ./gradlew buildEdge buildBackend + run: ./gradlew buildEdge buildBackend --console=plain --warn - name: Save build-artifacts uses: actions/upload-artifact@v4 with: - name: build-artifacts + name: java-build-artifacts path: | build/openems-edge.jar build/openems-backend.jar @@ -65,7 +68,6 @@ jobs: - name: Build OpenEMS UI run: | cd ui - npm install npm ci --prefer-offline --cache ~/.npm node_modules/.bin/ng config cli.cache.path "~/.ng" node_modules/.bin/ng build -c "openems,openems-edge-prod,prod" @@ -75,24 +77,28 @@ jobs: - name: Prepare UI asset run: | - mkdir build - cd ui/target - zip -r ../../build/openems-ui.zip ./* + tar --xz --transform 's|^ui/target|openems-ui|' -cvf openems-ui.tar.xz ui/target/ - name: Save build-artifacts uses: actions/upload-artifact@v4 with: - name: build-artifacts - path: build/openems-ui.zip + name: ui-build-artifacts + path: openems-ui.tar.xz release: runs-on: ubuntu-latest needs: [build-java, build-ui] steps: - - name: Load build-artifacts + - name: Load Java build-artifacts + uses: actions/download-artifact@v4 + with: + name: java-build-artifacts + path: build + + - name: Load UI build-artifacts uses: actions/download-artifact@v4 with: - name: build-artifacts + name: ui-build-artifacts path: build - name: Create draft Release @@ -102,4 +108,4 @@ jobs: files: | build/openems-edge.jar build/openems-backend.jar - build/openems-ui.zip \ No newline at end of file + build/openems-ui.tar.xz \ No newline at end of file

    {{chartTitle}}

    Wh8f913c}syMbca2V09n1=2NL1hPLtB zyPKhi%t!3^zyW&8?q0Qq;a4`mk8idk@q2pEU6LACUE@l89afGR=hP5(7TWmHp&OcB z8b8RCv@={scGoub$_|pc&v9(#%<7fw_F7lg`;)JU7F&Cx*VatKi)R%69=}%va9U|5 zU!;3HW1P1f?&F*j1J=q%BiqCJAR1kyO*PQ)vH0hdJUPl)Ir~A>L!leMVTcdZA*s`8 z6+(uTGE;0~VHCea6l76k7zY_Sohz-|8hiJfeJAVG4+(j2m8F~2jjZcM)$V=;E||+w zyngz^D;4ZI%DuoC)1&!S_Q%cI2GRE9Sxdk~BVe)(+>Y3?6IntW&lh_;d|f8{nn4{7 zS`3o%`EO~>@7g`8cn)5G?8Spc=T#Or0h%qr{ZJ)R*q0G?VD$veQ%#vnQKflP8ICzr z7IMlRVxn09GxfCf+{j)XEjc`$o<(j|O5#=*!L%D;rWPt`B#xh~QCZZ8v~hm9Uy;#2 zqi=!42#&@K*cDzLx;((J0WV|3menSN^VfPke908+FSi1svmhaWZKY2Ucx1X?^1#9` z;=^HAws3TaWEqUcJ8E$m{-nOgxTcGeiB`r?6zy2z608?vv3PoxnG@476a-p=Uz@LU z&{67DK@Pc{PA?-lRn*qPCk!spDbXd4cbl6jmRF%3WA=x9UjI5TW-&UcECIc(S^D!p zNr0-1(m&FH(I5ZjzY@RK(^$02uZ1Xo+m;#MZVr=a`%!4155Y=sWH}VH5j4Tq4|Sck z@REo!*ZYlvo4<70D<^o8*Huv=2o`|D4iMaDser>AlX$c!@QqEn)0zCXLh8>gPIk_6MTlbPc0w1u}fkn&1h&=Z9TJztEIt{=A_Kt3MK8k+!W%;)p zv)>g+WSzmQj+WDoe`hABV;D#5!#15r*B!GYsYqj6VZ{uo_+&>kjCh# zS(wcObl*W|8E@N{$zok?=nGkK*U<*B6uWe{ub@6SK++o!{dM)6R{xhvR*YuXn`J`< zkre6=^Ac>kdcfCHg5@scI)r!rO|Dm1*`0$?AA%-(n5RAo(`i^v04U&AkfR1B6(ML9 zulN^}eUyVHYhW!}oBb7v^EMR5_*()f3>)YM&|fR!(qd$+!{y}K{e~f987>`CbJ$J( z6I<=5*DhL6di=+EB`pp8d_;ouuUF(6i7&K849z-#RgL4B!9sygVhOG(#-I}=O^g+a zjx&YpQKK;FCcNCr(z#_5^gD_$dK_DkwzLG}d4kC1l0AxrV&;yO-lKfU%6Re^we++C zP#G4(2hsA@G?H#!+QgwlHD=IZtBwsyUY`zP!2O0#+BkrdO--n}A&N+^Gc#kFEZs}c z99tLXnSzE~>T$(09M$rW^4RrF4W$ZQ>wu5Nib*GUXIFsN6n=!Gsm zVq^QOXK7x3N65-lrIM`G^KJNXmhZL$ASwtnFazUr(`e*?X$DM^p`1>#(O#-YUb0~v zhZn_oU(4@Xo%37xz0vdAAN%!UmPZAabu=;Ck`yAU-=cDY^$C-n% z)3+HmwsCOQfw-tg`121dfVDH%aIlt~3a|9Br5&;<>m_<-JZe5 z>Ih+P5Gq3k-u|HZB{V>9F7IzEU>#8i(&z-L)(j!qo}}S5OW(^tr;^qeFv=Q=5&S2& ze~>@U?N5P&Mb)+%>W#YWY0n5^VDjG$sX_DQ75KXvjBfWW>`#fWyePZx{i28WVIq=T@mITmb5-jMT&erma4h&`=|eM8|pG zyII-k)gz_qVnqWMQ|xIX_NVItBwrV2J3rhY113-Q3G4>3c)wLarU+(A)A&7C5j}rVvyq)ZJg{d{JTy{_Y|ZwJBO)jfRB@X*g8Uc7r?# z@N#?I&BWYEd$3`GYf+VH^OF1JOq!y#Bu&I>ZYyl=3a<E3@awo{7R!VmlTbCn$TNpV3WkQ zCO+XzQVQCl29G+g8&hs)gQsG5zFbQ84P2q8R1cnhCJ>pw!2f7W!r%)^gbnQuvcIDl zNUi$8<11A9gEPr*?zRAgV8nu;m?3NGPi+cOMWBMmK?bN%0XKlBqWJm}Glf{L$g1M) zVpHsNs{mv~RIOC1vO@*keZ}5s=f8oqs2G{@tZt33m)yuSO&5~7p+)mn?-^MrGUu?1 z^?_z#V;4bv8|$x}m9?9r#MK^88&Olve(t}>#Bw;@D~HJ0=Fq2h=G8q0ZQssM<%)}; zZrs?+G^c$>0k}YyZ6~ZW@PyZhItY(gP*ct^CCQDa(E>!jn034VG(IZ3&-%7L{0miT z$1k^SI5=?JXvOF7z*;ZY-QF5I?^`C>vJ6n85T-CLQT`&naoH#`lb=yFu=68_5Dpz9 zojR`1VLmxt*d0^2w8^s5N=Oe!mFgNlYBCgOcwpmh1w>@T?oB9jlxNsve|i(1?CF-$ zv$pYtx{8hOHoB*-MyH$>j!#h1^E9MZB2@LO%3@YcSGd{k$+8r;xbqPwrY#nU*atHO zwIk%#El1t38XV44(Y~MIY6SM%rJl3W5nt*Yo}!acOXVat^aK&f47mO}?n=pKf93kJ zi15^<0eBfo8x`xmwaB2DAXBPk#5X*y(Q#($yBCHqGuv2h8qTq%8t`*?<2N;Ce)CN2 z-cBuk+B=nA7OxP848w=+6O~E0Oqm+h_&x@D0p=|!|$u1nGRyS|3teQ0_;aQ|J{16+EZ2Roko|O=9eYrxM!8{ z4(TP`1=&s^euyWTRVIQimrqHO8n$mP!vIQ%&5)0PFRyxYlz#r_KX0_kc+A6znS3!Y z8c~YGqv=sD$veATqLW6=j{P$B%*|Fs0f&Eb`;HJu$-ZL=^@MerFg`~;cr4~*I6x6kZ|dcAKt%@%*B)YfK#Ywp6^sW)%2B6uz_~xSG_mi zYLnqEclVN(?zcy!Csgb&d>|^Q3ATwiD9lHa+@?O2dK@fAJ3GCZWy>hiG)CTstgx$B#02KKng$#)qdy>a>JxlC|m@uV^%p92SmpD&fdPg%;u?t4Wlp0Mju8T zlB!6JPdY>6Gd~mAi+3cL!b7P)W9>rt94UtUnucRnnQSghoit+d)_S=Ow=+()0O3{^ zDGWNeK)DKXItY;#ySlPB_0NHH^QPZMe=ru?Vek|OwHvyHmYLKJCIy}jvyz%8^*yOt zqHou3YR3M?D6S*g;F;a>D21|B{CT)9-X=2` zi$!Oy2+!w;XXPSya?iHXL|xKAp`Z?Z*K>QZ#NZ(73IfN|AJtL+)-MZ*oEa zhCAy&FMAdm<|p!DZ(Qoq+u6_TKETYU)qz4k1rjlrc7AHt10gr4m zHQN}PaMBVAt0Ke2FfAG}!~RaYOdM|7$AyP%J8)uD#b`6WG!CPi0N5p(pw2R55_j7b z?4l?(9Yu42EdGMy+$S``;}DzrITw@*28L%L3WP$-PWuWs0j8Ilu2^iYO37;9U-EzJ z=%-m5emR0EP}&5;lXe(o5C)5Mt!8wYZPQW9H?CnlcCcEiB0ZseshfZPS9o)R{VlBO zp3xpeI1?;a@^$zx-+BdPPZxv?@~x>2p9ZF#Vwf+A7;u8^5B}EkjymvL%Jt`oR!GL1 z5O0T8i6veE$Ovdr@N?%KP2zp{{oUopRP^iX52I?B*R44e5|L!d?(pwZpj=DG*dH#A zD5AUI=(4;AXG9CeW!<0LKttVX?oEW(0)VVoq8|Ap!7oJ3*Z{XYY5y_Grs@kF2Dfw@_ zYA2tA96789lVU&P!5XYc5?g(^mt-&&gGg$;vADr)4*WZEA@TVWl$QWv6!Sghqu}-9 zV7ujnckT!V1H(m*m#kr#PhS|9H;b@r6hmYB)QtNeFd&=l7U!?SACH%e!(D@2V#Bgl z30l&*8b<()%-T#$^^EmIl7tw%ftk-jy8hYZc8P`YupH`sgFX$FCeEQ{K>t*)S1s}; zG<~AlD})REL>EG(*6NYDM)p$tsisfb_|DfY3#qW2Ekv%@CKn>M_?{8JbCLXBsvfC~ zM7~2y0DuF8D~219Hzl4;2G%4OES_$^A$|D`?GeQyN{D7lJQzO%O?;&wF}(qAnJnmM zbzJTra21YTS>*_S1Y7sEOWjrH6tfrup47;1;HNQaJI%D?vL7`D6{#myel9g+5In!8 zvF1ziCikf-D&2C@0yal$aF~-tTQr%{))RoF3c#Dg`>rQa51YuMIHA2~tJcd^5VZXA z%MkuJxC(|C|D;r`X5*LLIUvKkFrJS1{&12p0Prj`{w@@Lhcr`xuzJ~P8Ri8-iJ^o7 zn%uB&Zm)*0|IVF(TX&{iPHf+#D4mtf;p$5-(VSIQQC(IIlK-GMx+8uTek48z2IdKG z1^n&o?TjtFu5NhGwe~Kfs`k)AzDOD? z8h4spSjd>Wn|Bz$n46im81G~t=X4j>Cl9ChXFC@-xY{>Vuh<{ime)DdP*+2DIGjhk zDNu4N^?2|OcU=p7^HlTg@E!B8ZE>%s0}h<_kWbDouFv{zjTcb2K(`;xGB)mS$hb41aNPu zE<*;Y0GDF>SOK*WAhtw%oxOi5Q}~(EEuA(AXC(#mr+P>4SMN`>5Oo+N2C3nK6H+L$ z9l%|6Dw$-`V9qi0*8nXgjpoYjSmIMJ_ni4};^*N~0Q`;UgwU$|TcQyuC;4vHqVq_R zI1z@dE#L9a5zx7?16mgfQvV!-;72n(t$z(cj+)YT$H4OJQ}Yt~Q!6ef3h1*Y(uds;QJ z+Npusisz&~oq7e%*2G2TvfP0`a&T0Cxm5-)&%hxaFel_KE@xHo46<&9t($S<#pTA5m zhsxj+wZ{2t9s|Rwq)FEhl3t^R#QdxICJg8Rv7O}{w2(e_Qto8ye~3$>moZ#9EUbk{QGa-Di{xm0G$)X zuxGN$UH<7z-nMoonyJB!LgSTYwFR0V4C_UIxHJ#~dMNa1fcG~5=zq~ur%sUnhn^DQ zv;1FNX-h>XNS**T4A6fzPY8Hc1T?K0g8{dRaa; z{OR>9DhbI6>YRHNlr%6vAfK}H*Fdj7&WLA#`=7KQ0E(&#G8mBm;tx9XcTinrQ&biT z|AOH3S1#QT0P($CR6ALM1LFCowH|Q4(zEH6RrzaRbm`3yclU>@9x%$%DmlmeUj$VM z=^w001q8(7Mri)9{2vBYceDz?6aRyVG+D(j_k$h<1Vk_m5Ou6Mq5`C6Vqt*-k$C@{ zYyS-3l7a-j38DZY4ZTtx{D4BkK@s(D4!`Ye0>svSrbIt>w04`C>Q$EAC4L?U6ThA8 ze`fn60y3>lcfWt>L7)Bnw(o7L)A}!Z%5?#_KM?E!RZ$aG@aCno1QJsD$-R93#eX_4 z4ejzAOYyTVQ~k9t@g0W4fmyTtqm2aP584X~1RW(q`=bke3gGyBd+Yh@y2CWjd4vTp zM}(3>fN~VBGy?;sK1ATS!v0`oIYbN!38+Vlf8^CsG!XT)sjX#gQKno z$2y$dP(;JSi}3B=#0 z`sDK0v3m|0 zz?aWpNITx!K*u-weo@qHN*s;;?TBbHN&vGu+KgOT2AemR+yM@dN#2%jH5L8n6IDL!!a zp@v0tqeJi*YrE{^a+#-3BOh|2oa-y9na1_4OLRb*SKZt{@{PtaKn4duR9A6o6DQw*@ zSb#L%5y1p+3yB;)Lesd9V?Fu8GeHc*J2@pdpXW-cWH4ZWWxh`Zg2Kp?iR>!Sj`0!G ze}-s7wF9|xs9lCBGMd-$XM6-jmcI}&0B220*L0zd_gR(qrO%hHj}X#pskS|f9QZy-+ai3C zBAIA%cv_D~EMV{O9WicCmL#`?3JDJiGnwuvIGTz>N*bk}9TgIg$4`;3LQ($~Z5_6n@Higx1)|q>hSD{CPy*43hC&qhJs%J#x2dnBE~78; z^NL_D#KR5^EUGWZ2`OPMawfDtv(rJ5>qYi>jHNl^>b!i0*}2K%)g<~To!dVEyc1cn zSrQLN)hsG1OLG9QW4b;9>)%to-Q)Om)|E#IpU*-n(r)Bnen}c@7KM66R5%qow52>a zvxqipcH(bv8ud$kb4Z}incVRro~ARk1U*Sd8$Ow3jG`#4$Pf)OdbGv-OW#OZ%+NV1 zDuV?b%rpveIAowhUR%Y}axz74;-z-3N!~QZ8%GjPXPgAUT}{FwX`~}d(k@RTA}*mE zeCK`|(4%n-_0*#}aYV(b<0;`VL$Eh2+qc#+bQCUO8W={h=$#7V z8%C1io$4a5;I8L`>e};BnJcd_q9SS_c7kt~P9{0eNcBEb2&JNw0846mISeqoa0eD;hUg&$=0m~?;hmt=x`FmJP13^ zw%qQp(5rFR)GeyrBP{!8rd;)@d-2wHvElqB}~(YP|aplF3A*mlBRkO z6*z$%M(h(QFaZlXa!41%kS3$06d%rEp_fEt7YAR~8y5|ysb&QRp9cR{;xH9la#cJc zoaYIUfed_=)jAe7YBz)SIU}h~A)1TCT$3-{(JaBSPcRY1^C)gLbr_xhXjp64 z)sQ+C2$QyZw7yoXGp7|T=7c3~HuttOV-M}_Kg$VKJnjJ0uO2g=@PJ>j)4%M80G^rL zdb&^;fmq%O#sb*1AzN8`f8lTp)UM@1Bdh|ZCCr8$*S7lM|MFzr41AYhR{z{4ja_AS zK`5L_I#6vjo1YK7hP1sMY8-aJfR61xC$^KbI6UX9Yk38yy8KAE`vNhyyPG8ac$6H% ze_gYkN#wy=hnyPF!G@tMiW%a|Z(jTe-1+bh+yK*}xC!20+TCeztx3WC|oR{z`Zy@?rUga~I$0fG%IQc$y< zN)=>@2P=QCri&!>X2oDArw$6prTu3+L6`ei3907bV$|4P4&3^GMugxr9Jp0`jK66! zBHvw1=jYtzBRyw}l!iZ{<1-r;Oaq-4SP66qjr$YqrwQ1F6>#!UXD%x2m!OXv$8f1> zqeMi9c7gUfdxCH2-f`FPaTBU*56xdHd0{Ln4wGs*+N+>&_-kuCnc#43L_ajF(`%`YmFn12B)CAuEiJW zbc7GidpVCh{2E=0X*mFD>4v@1E4x}YA6^u{96s3fsTrqlIHP}mJ)!ef_7?o@+Ln>a zs`Ne~qz3{%+gts*^X+`IetNFgxvTdYeeE=$g}M6aZw`13N89(Mp`PneX%~u<#-Vtb zmm>G^_zN4svpXKttAH}-j*zvaYojQ#3YBNlX8|G-;DZ39MR5Yq50WzJzmK~8Lyeng z%8Ob1)#v?X-{&(D8KtivM+kW5z|gNTwyU7m9rvA4VtPlVS~ok@Q`uSCFw1UXAEpEs zMu%rk+a+UdV0ZPFz0ZzCsTe65kH3Xi*D^%HocZIZJ4hcDoRVlZJQ;3Q4|9eDnLaL> z?fIscm_^D{Y1j(r8t|iW>T&mQOjl)75qs2^Gj_UWmQ{*;8|C8mL=LB93IjWXL+X51zETQbv;!7AF-;jJdyXC{`gL zc6>?2IOY;q<0c|oL~rHdj^Mc0(3vRl|F`#*6N~Cgho--;QLljqz`6E2_EOOw;y6rE5fC*V@cHa!~%Xwvcsr-~K}a zoFljWJt}{T!8zYSV{KacQ{nYe)QM?L66Sp8X>Jf4OGJTkXY`zWp}WIdi*Pd~eIEWX zv$7tV{@Mjlih*%dK;e{sGh8{ny>t`z75o95tlT-a=2sauBu7J_z+C$ne*^MWLs7nY zXm@zI@NPUm4U@;~AxwopLMy@eU58}E4jN4ED+Xc{+V$J&ppwQ{}AfhU);d9Cog6&K-zk)E8HD7dzw7X8)2 zN3Eg3#-QkKm(2}Fy(O?={=BBv<2&xg-=_1K(Xqz)fR?|T{NEU3)T6#H7p)IvPuzP& zX@>&-nl!lHS-&CWIqmG?w7Ls&CA{a_`On?jU}WO$i=K^-=c2WZm%(~ z(%>zJ+jpnqEDzM4$ElAKT|8X#K2#E1^Ck!YW8yK}e7auYx3WCJ`1$vc*a?369aYB_ zG4&6-O}gM#3m^xx^2H(&^;sgit7~@; zl2;MljLwL{CuFC0Pwk9`*a%9g%b}OH*>L)ZXWo~gET^|D`gpIC;zB?0`yp6Gs0cOy zIU?O+$&sI{#W^b?X*f2WAuA?Rl>daD4A5-USM3823JI&x>?pwgN5?Ra$_%(p9vN({ULqKXpketdLpRGjoV&vZdIAI52oZ zsF*RZ>AX3xvg^wb90Eal=?ED*;H8IieiN&+NA@V8V%o^BV4^j#GdyhR3%d700X#lX z@H1^tO9KOLLco=0i;({lY}X3MzJd1d(QckLP<-Rdw7M0;tQTokaT!#W!@UOpjlGJA z0T*rNA86FTk0t}b9cHD_6=;GI(%Zk97%b9V*n8<|6@x2+ZKVo))KZ#iG!m~Ot6W%U zet-{Zd*kzo+d=y^HnJS}ZVwq;)YmvQo;N5XHl+GE>(`p!^#NifBDtcs0m>rOgCl(Pk=3$&T}58A%Zr zBMlhJTzLKW0=LVJXRlJ@wl_IT(}15UnRDes27SnLKxn4&o6yEkYVRrFa+m+AX@G2$ z6pBB(L!!7T$E#{j~m+!l}E_{w>!Yp zz%^9jfN{MQ4aY$zV7y?pCN;Z|l4j&&k~E8xzaTfRj1q}wk}o%FBn=16XeY$Z=RFZr z_4}T@Ga4$XKn@QxQ6>Pu))}9hizX~SV*s&A8y5%@6PXfX({9%mI26Fn`xozg(@AGV zADv_g#IR56wo>iE@8NR4D#RT}i~$F}tD>dw`*!z@5%NBCK3`g?p=`-rQargZgLV>k zYh!0DL<_F`C}WYS+2OY!?pE#-(B|~;REjyf?ZlWIN4GhUm7P97;rKShFPwPDv^1Vi zP?PL-qMb#YYlt-dCq?GN1ewK*8~QSRC^Ky6cI}oCR&KmHF))h~`z>yv0>?^QRg@|G z;4*m)t_QyJeS+Paa)$w|`mNfP!xA!dZukrQE({+%eYLqM$nRAD`ekt9L`fKTN!%A0 zw#Q`nnWn4ereYsJQ)8Nc>H!GID*+p zSE{Pf(H_=;uMgx83qtk4G`BUeNh zrhC<;3gYfnsvP+xu&U|}T=0B@2>vHnOd~OG#d`)AOg9%VD>&;;R4$_?Cj@3oQ?c6F_`l3ehj)Tmi6j+N@C1>cv^Z=IiC&mcr)u z@zxE0S|b6V0iUbBPEH-DHP_W*gS;Yp6e3T-9Q0*y)3n!K(A(^&WgkXUe1A#)^*5Aj zXUz&r!RO6c7~N<{R?IZuj&yNsh*H9B2L$#f!k>K2lfO`NA(lYO!MU ztcUoe*CzTtqdXtCV{M*mb88ORzFAg{W2hF+f(;Jp;*HJihfZ=il zRnh>E!B*SebhwC3k2^a8i3SoTL_7=cAP{(Xz^sT*BlHWOCS2T;2XlAK$sF@d8{+Th zTNm@+4g5yz->dU5U}rI?7;q2Q@u`>XT0x><0(0HDr)j;q5U?k^?+6Ap{fU+`+#AQ>zBTg1WjQoh!eM4%-;5->tnbX}=h> zAz+LeKjxqn*>pi0bdxh#dTEEn@`!rXiN&76_7OsIjDz6@)7=OW?7icxe)`;~QieUZ z?Y|aHx6*QNMq)0;GXl#&9n_>+F0JpS&pRWc"e9+JGJZkXFly*x_YMg)k31*tUv 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.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� z0QbjRz{QQL5BP%mnw1aMETVf@?E@|)TP;`t<`nlj?0Um z$Bk<18qXY;(|WO_WO}z0T_?MHm!5ZX(OccWM3~tvOd^8>#Z~0*Xf{U4z#lNlIcLFo zZX(TCg*awfjnmdbe?{fsw58T+fI#?|x_c*NKAf4fRrs3JY#L+S?~ ztX1dmS2RDYq+Du|Ne6msZkG3p4Wt!%qF2BBKXRi0^pZh*#qj5dmuxXz+Pn$~sFNWQEIF{|lWS8-;bx z27{E_{P-oI#8ZT5Zd?^Se?2DD2e@j^20fLqa157!Z>xG31S?cZZOkt15hd`qh||H3 zkWa*jCyey&FxaxL2V8k*Yj*#D4Ep1VEtDQ2vpSFU*L3e_}@sI+4s?p?)X) zkfpKV(R3{o$a998{W$}6K)*Jty`hEsj=mRW0``^fiHU19vnNXN{-9cCctq{HW)1zl zLyaT71&#yn0&oLdeRzS|f*?;Ho5fsxXfHw2;MdEuM7ssC@_?`q>2YY)^sdIb*!Swo zcBGSX&}z}~jtGd&f1=^yy3tM3Umv3-4eN77w2vvxxvw?6?$=)8wA{8HKgJJ|=z#DI ziBCDbK`;Y^N4jd_8pCR~wDz>vLfA4Th>d&RHiy?gz2bxyE`2!<6wdZEEu?nOgDB+A zr|l)F-h;Y;8Ha}hfi~|TbAV7OxUiwtIvx9!SU_(eh#CH+e}s`b72WVN$cP3 zsS376p;P!!f13c`p@*Z^38QFOl{DnB$rh1iDQZ{|P1!Nh)+Tl6q#W1J@clK0Z|t`2 zV4J|YH^Q*Y7tPXs6mj4JEw_VsaU*4KUry7mtl<*~RtJqu=kB9__ILM~X(!(&(nuueUK;E?UNi-6*%%>F#^6-VW*!xt=;hnCu(?=|6J06kFyJ$EWy9P&Ye%Ag(Z&o~u z6_u1dRkaJ}$Xq0cf+Ii{w_)NC6KYR2Y<3LN&6tA$#SUMG?{yR5qIuJINwDjY zHG9bS+sNs>e(E+_M!I2d4=1W~=uEuv2_n-de_tdZ+>i*rxG@>FBB<4rChmektP(rT zXR=2SjjQbb+fJ;ZlAYAwTXzVfu}*10nL9by@0fd? zefQV<&`H)aE!JR;I>1ury0kR#5%3rExl=8k%^+t&6(L^ zDP!&nr9{N)&5$WD*4>-S%mFT>?2I^)e~_|M?#}1ulJUYfH((Ao>-IrLzbz6zh1tjT zHd=-N@?Nwc=wp7Z)cj59n|JZK)}v=0KuFR8jI;!2?=(nrL#Ju0RnbV`@O3%baDOT8 zaXqN`grgOU5`YvOz~)#d?+MQA#gb>y%*0#fUft!_PI7A_Bw7rqdaLHveON?je^QtM zN=~Oy!LEHY04Dt)m|8%&nZDi8E(E^;e#)9=u-LQxtDugk4f;jgdbJxWZm*b z{fcjl($;Zb6YNa^Xid`a0-GGz`W6^_q zif!7TT}wdcwGr3qF55^*oglTGe^3f7LQl{Zdg@Q`A(j`R@jC7B(LHk{90p$8f79(m zALx{je37U07f^qK@Wc=Emte>!=_y#|W)D^0i9;_(wrvRhT8~rvxAbW-kMce*27W1? zNvYWIR-PpjA-5h;OG0IX{Xs6oc_wGY=gCJzaV)zj!$Uf}oEIY|RlVE9f0u=@S`~CL zh^WQzdxkCe_()J4IM`BHPR&-yS zHl&gb4t50fl?aX0)NsXG_-@RB2VBGKst~QrLJ@B>_wn&G;o;iHKrNf3q8*N>jnnX6u(efjQb98+@>#WJ{9i@%DYepY(~TpJ6jG z)n-5StYUWjboNuV>c?XJZS-r8NN)3i_Q9WxW|1_B`Bu0&jZHuMZ49B7x@=q)Sy-K1CwfKuY%c-OyXQTcONYulm zr~+TBvEa_Qx~r(Fe^+xwbT}xo`NO(9YEw0>+Re7!ag7yvROKXLt0}IHD-2$1 zbY>RpsO+2~sr6wJ-u~ATRn4LOS|>zK)lSG(c=r82xLC&*U6xDRQnY7uETnTyb8F{ptr$dfXZ59kaZ+`O4Utdq$4Ov6}1aU+9qn_v7I%BEAIXI+u zp)QZ2nXHiX9Zh{&W%c_zF0qMZ6Y6h*lt&!dA1yr{f6Ctye6RBYz2S!`z66av;_KMG z$)uYnSMJ(UiJoED;H%;;>h;zGZm*q-4o%SMNZN12d?IE7{4{g;Z`>A~a0yv0HtO%E z;P;I|R~7-jGubzVnUwjsMaKkw5lK%3hdG;xR2rOs*$@|nS@BiuEhM!-kl6o<69gO<$CRnz{l ze;3|4FA8*Xx4lfZQ$l#xphcu^OYD7mlr5%2(7L{ldPCa4L)M!3ON0Ei%ZgM#5jqjo zp!j}p@v-a8s*5#sAa?w@p|Y2^f?$F^ydf?-X%w-zD|-Qa$DT_ikGE+fz?NoiN>q@9 z;;7%cWXzJ@A+>F6i!(eC@h#@*&+E0Gf5z#~#~+nUtey^t$uATQc|MJ^0e@+O-1#r? z$x6Oe$QE4Ux!m9KLC326^DmR${E3LH5C$l>B#TM8qwpP7rI;3u)8B`2|E6Ej&@Y%e_H`h zbN%Fa(D_BA5%~stetwzp)qP2fu4vZv75=*jFc&D+7r(c-X!-EMjBUV2<@OXGD851L zhlm#c*XLn83}}D>7F6Khw9&UHRsceFR&~!x2aE0MycWQMg3uK49wJsSsR4y6r>pdL zDB*mVSsy0GdlMNF>?LO0x;Bd>e*pxQmldv8Cj*Hqgg=^+^Ykt3R8&+7!neSya0kfl z5ZJH(^+o^yfJu;bneX)V5qKT}Sdjngy*6}Q3g8(@&12?%v2L#)J2mi-0${C3t0DwjFe-mNOk@JE{ zAcG15VrC}Jc{l&-Sn~fKCr48bcX!yPpu-|!*a7R_h??!R_iI-gb^(WSXwe1P79tQP zS!cnaI(X~Z*-UBVgdoM@)F`r^mhW2U#n2VVWqlQq6_wzWvuPxhOo?1>CXuh9EIJS_ z9Jopu%9uC4qS%>o$9K}Ce@%*tyJEsZwl$F#epoEcg9-5s#JuXE`xsg|cu?E_wAf`> z=RDnaA75fuY{YnWLVmL`Rcyqko$vIC`O!q+3qQR*0r!w? z!#6h-Oq3;~{IfDIygkPA36v{iwP8Ig_3_PD;$Qs4Ype!~JozR|nN-3d(5g6N4mE)_ zJLumbi39Isb8p$2bXSh65dpYG815-3)Z_cpqfh=*jt9JF4%&hRV-*Fs-z@NV*6p@* zg`GLeu+YTj%^#^)e>YdsuAFS0bZVXD4EEXjPh>}=Hhm! z_~Wsp{BMt$dq2N_2Y<{?{BkbG-f~sR-^2dfYX$}q{)6qX6qwss^h~TwQA{A%fe@JO z1pt8mc(u(xf9;FXjsO3CW3I4aF7sfGTRAew`{f783hwnqE9QLneP z*sbijvNp>uW%rukh#!p-I}O7f-x)$1f*pcCEO{<(ZfdTO0mBxr2azbDSmkGKJY8#USM%^+$q_ zcFp0RcRy1VSS8vep>@|$HJ&}_0rLPlE= z4f5LK&bT1;@vgx7Hh=Qrk?1s8RK^;=Q71Hp{O9W#beA^upVj5&3;5jxg46 z#er+l4{r#hXo=1m@m|D|A@+_L;|xJxBSBi=`tTu9q=|AsM=rqxxxchLzZuT35Fz*> z$b*L&_jXXf$Vf_qQauU=K5i;EI-3_9!DK7NzPC$RBj_};;Uw1?fLle|^3B_H#}hcsgs4UIB< z0XHnP3$DOKODI?e0wQmtHKRJ1kv=iAXzTc=%5tQ%$(HIfKAtvucPUP>LXUcfUe#6r zBd65xy^GlF{kOi)$N73~CG6DD(n&@ptMsF6LoJuIt)+7hK(M7ObC5If4ARKar}7;| zIk3PLzEca%FZ*(bo_)d9yX-<_>ns`xX{J#y^w;P)uXJN+*lpf{!EA<<26LbwkL^T4 zZxKJ+n1~vQKxX1vqcXB-R(UcAjEMU9`3$qGy?YN*BeT!0WL_Md$ugN*?288kcWDwe zh&|@SnY8znfO#Fpr14Hc7W#_@M_T1H>n870+e(=1twXIj=?sd*Z?9fghEtQG1$p#^ zyoo7~)2mTSmNKyOX^b(0m{l0MG7LOWuQ8Z1i{G-J_uL=j0`)ws&U-?lZIfht1AmiP zNwz)>NUSbSKKeXn7ssr(>eAdXk%Pv}iLJ7^vqVuqYw+BN9;&^t%a|vK+Ov2eX@v^F ziw?LTxk6q8bIKeRDhlLe(JRQ_AN{cz5G_kl1=7{OM+Mv0pf;$y{WISb=1;yU$Uoyv zSC}MxssH4M{^KJ4SG?&bJQd}SAYhO!_F9F=-li_@uppq|2Vfu||NQ!qMe~7#|3{zA z2lx-z|EZ(K(VTG31p@Mq3-@1jP?HI{!9V_Ai`5Z&U2_5dsv_aOr2fxt{re00&$Ki* zv9>pHbfWubhcy0lCh&cS{*l-EuL_os@G@G+VEGJxD*WSu|1T9x9B3__{#oXr`M-?| z@?Qf>MhFGt<8DCt45#;}t@WP^>A$o$HgPsE`#+ZWcZHy@U}ni;pMV&;h*unAn2A1GK!eOQRbK+Abfukanb+X z+Sty>$;80X$eh;3!j|?=y?;)NKj(RBQT@N=fd9<*-H=7!Nmq-tgLHc*_dl+VU3r#AmUhi&M~+9WmowJK$bj@i@#Ni` zrz;Dl)-+pDQN5pUt&3YNIyOhUd(W<%%ghgtEd*?NCSI+jRpT{4N0v_pO_eC-iRDze zV`PS%+3{kpHSe-FmW12dZ?^~K-(QBqJ$+}#%v^NWt(P2Ho3hx_O~vd!F~=1QT`p%) z-a@rLKT=UN+p4-N5TxoGzt`9a&7t7WOO3*CopJ0vMFBve$uOiY% z3w5%5d|&dhf0U&udh~6n)ODoV&5f_O0|vm5tPw%;cs+#CSr*D^@aA}&+A%}oHMC0d z$-Sx1{F-%fUam~c8K66VBQ)y~etem-Ex2vEH1<8uZQFINQgmg1!0W-#=YB|mmq6?O zdM(eaTzg%c+BCg2(_|j=*wwerVvOyC1*@)DO|5QsY%Ll`*Dz6iBU;9T)7HgB0odP8 zt$mcXa#QWVUeIJDsVN>$pDgtFc_`X9>Ns5vsmiP+n?7q@2QcNQvp{RJU75CFt53yE z-fV9C;uj2fg$DJ%goYBs95rdRjPBOkGK8XR_L&RrZz7=O1;9=o180OPsV#N0E{g2!5bSiN%@Xz;G7?ziV1!jexlgaEw_{d03aXP) zTg2!MVEtuYubgTZoAYTY1E{s=2 z-DBnRZ6#sS0tiL}mIUIas1e!vZp(9$wXf4_^8*F~kbI%^U@=XwsBC<)$&bNKg5pUr)V5%^ycKQh!OAiIRO)IvRCq zzMSCW-2=O|J$pu;zaqj|UR92G8z|%1ei(r@I9~kxWQy`omms-xq5n8RsdfVC`mAHS zn%|7GbRQV@v^6(AkA|TkG{ou9?YcbhttXKb?z6(EVokkyT#(hFROJYL{IYV1k`2A9p;;|EOcfi>M zs3cc>Yq{Qa2S|Dp5=~uKbZ&zRxqH`d&XU|8|k* zUPq>kR)KWnagGYEIpV}M)eAGU^RI!m!QL2)`yOq(HhLYbD9^SqV$$@^&qu+N>yf=tmi{v znT==yB_N5YuLlwv;#|-&7pU1+7VFuV%I22IB2d5x&@Oj8@-QEGsXiO0DnUQBi}8(g>r!=EugIolf{_|? zLfgq%_soVonD_Hl+!!R@r|$*uAqr|tpSfw!nO-60WvB19@jNx_%x&NPCX6F%fX<(6 z))+-9dzNzYYBW!-@HY3j3Dz~Tt1{h8Ncj2MQf!vp@CH?R!eX#)R;iRnRG{=prW&V7PNvLu-?M``Okl_6`5NH2eMfWh+|CWb=+jY$- zIHri{M$Bll&?02a^3G-tDCp-?Llg7fnddwvU3xjnBQPdzmDBRd^Svgtg~K~kBa<3} zi)oIda}Q}*CQbpctX@FXl-qltY6h$o^jPxJXP;Y@F!n?*pIzJAAHUv3JUoowV#gO3C-MT|<{N{5;{ z&G1-LoJ|JMR2^!%i)%U0_P?F9*7952u_+x0LOjRVbY;}l-t;F#>akwUj<$KYO$r{>p9FGZcI*VI9VdLFN;wamRf%wJ#as;3g(m`*3pbAV3iK38@f0Tr%$l$00o4# zGkY0c^{e^%eWQrWdgP^?*B;*i#dL&a)a#4-Rw%#(o^{5~{Sbe54RcB5d}A!8#!Q}; z%1JF&TgT#%MFP-&K{}4euBpZEfqvPgikwk$+0_rD)=SgC z8ocXLL0gK#6g@99^GWG?-i((x1%d0EqhR%etLwGB=4Tqkx z0sZix&1RJB2hiCpP$FZ+II{*S%I&%tvR*MPtNLSeV9rB!^33=r(Bc6IhVUMXi6tQ?0PLT%rw4?k_b`Y>t+-K<6<4NI`mNxUj z4WvGhn_XOe!-?Nhcy>%msCav7&iOq`o#f-{BNC}@L2?~=hVQ;%@%ypk3!88Y8xxtE z{fYp|stJ7Js!I%83baixV8s?f&Orj$3FLE-@{3qyHVxy({pmrOmSV#%X_^(6G`&o_wkF zDBbE{T`=r;=FD4FNT$yqW=HB!=L#kzC;nZE`^s3;OCJQJYN-&T!i`nYH{vZyRpajJ zz0p114iwd6@KqPj9aNY+g-V~y&535y_rO7brqY@Fv3y6>vQYW(GP z5{;w4&{905tg}3d%|SSih3cp8XcF1Qx0k~F9Xi!wEmP4gP58q@E=B=5-~b~I*~xQC zjw8ls1i_ezE@oAhdE|G2hF@~Wz|u-_*%{<8jv;`cUO()a#U=H5hvtITx`O$mqoaUtoLiPHi7GaPxTNlUgaqo<=11Yy*h?$Df)Zw- ziljU3SiEd%eYM+yG0{9Oz{#H0c~5?-_Tker(pcbm@4S;-!L)%!{LjjkRP92PRMnAi zeUY{ZY61QJH3A+u@xbl{Q|W%Web|k7f^F1_R^F~3L$5Lvm$6M-o7WmqIrNR8)5BBp zZw*pN$i=s!mKgNEY5p81%yihH-=lQ7oT~SEEmex|1miH42q8A06M**ODg%9>{CrLf z*+S{8v%*d35D~sDP!Q)$AHm_s27fU-Gu)zPQQw#V4F#F76O;G}rfu52-^w=OJO=tZ zPZt)XF#6{Yde#)+yWAkqnxbD!{J;n5P=1k8g3~Hk;gW#a!CPa+S@&a2}+jH^r;$&Kp@%Qz6Xm=PSeVq=~t(O$AYP) z*VP>46}XI(!UR+Gig?iBK`2rTq_9?#r{fm0t_`3BM=78s3;nIQLiK~Y zC6t%CQ{s@jf$ zfvB{*x4t`wsBx7yvq;1>R?{i(zU#J>tT#Pl&u3Xb^Zh2^kOs*LN>edd{utWm7*l^;@!cP}8X=d0;1PI6ykDLBKbp}D) zZhF2X30v3Gf1paygjtjzi|4>rB-@8P`b<%yC`dw`44|+FMoZ4pSFE)RfJOPKs^l^V zdqgl78R|ezO$+piTDwdHFQP-X?N~LbPR}tMCKV!EB)v9cf7LaSrOS zv>I`;c>BRi((2DoY>u;7Nq9jlC7g=2Fk(?6@nRRCI0sf5X{g7FziSAHJ$~#AhDhh+ z_H)j1s#LAU*WlFcHWJ7}e$-1^;vHs=3{5p=`~t|?oWV*xs<0#@7U)QZ;MRUBHT*o2 zOffZoy&-MPGi}je`WUG-&0Zc?M#W?D;Xp%$y0@g{8$lpiKti4+B`Im!7yd432{>|! zqH9+}C{pysgc?m$hyX|g3{g9y8EFy5 zUxZ|0WQ<6j4hoI3hA7k2k?=TFCu1f6EnRh}=7tkb=>#lKB0s9Z8jx9~zB%Pi>9n!( zxTni}aLh<^XPVhe>V|eJ8hkoDcD#(UrB%Qfsnhh+!UIYmk!)DB>PU5Q(@0||*u)8l ze7D|U{>_|XQK92C&$x_VZaLlu&|{RKBFXTe@F0Dp9(g}TGt!lWGg;0Zu5N-N_2|l! z1gsWAC`CyDlMo5XqHk!81l?)WL_0w)ibqKAx04WN_?2{$Sk zkU#nww}eO$7_qBYlDRb`SrCxGQSsTPbcz241MD2$1y|u4LW?BN;QTruyaH? z9~HY;yeOnRAm-95Dg5A66vv{lZ$xVV46)trn(JfLjl`fy+l>2uMJ(A_ljItYZ^t#l zq`W1UaC2}!(G#itC+Q>atubz==J9$BG0^9aX>%f&wK>H>K!tRC^`T2x`H%3rRl|N5 znM}`zjUg7=mMHCPmY-Uq^DGtIl;j+GRTxQQ<}<2OPI7kd^qyyl^0{kxNvGx4(xF?G2#u=l9Fz zj~y;WkV7LO9L?G-6TO5>i@MehpG>9wIKx{m{D7Fm?4fkR61AcS(q9usKZDVx-JF~6jCV-jzM!1q;BZDI)-cQ$c|kEKe8XbAB_>P;mz*j|3zKjx@zZFt zhjUE%3D9|xQ~6oqmt8GY#Z~AV14`;-ul(V_+iYL+2{Saf!Tnl~oB8z+KqjBGYrchh z5EX{VFHRz}BpH7DkaZV;YkQkde@@6OH(5Da5_0FTtTbhS=Gzg#jZ~eqJpADhIV|Io`pF1G-Hh@J zW%i<(W-+N#xs`o|!3UAS8~`OM#OKEq73!)jo=|0|l+|Ko+%WPAxJ<3KqkuVToUx1w z74#|oE`mRdz*mgnC^{ZpM;|oVoKwh;XFd}L)qA#q)_W6w-t93b36hyUNeavdSxpg- zGp%+ta3{xTIP3=#%4~aZ3JGPRnj+RH^iqLb=J={ct$%Gvg^wCMGzGBAP;9_BiC->k zW?+X22j%`=Gb1Lrr^1I{Ucim-VtyXDW%3i;KPb)$4Z5Rv1@rZzmsDgG!Fo+$Mvp2{ z-0-QyZS_*Og<`kqx9R`NvS;q`yH=_wpXhQQSjQ2_oUhW!)h&|>8@RY)uwb%r{W;@9 z!#8~Mwx3ZcHDYJSdJOk8dwt<@^n-4deMuxil!g#6wsn&kMO?t^{Ij-CWd{NR_wU7g zCktnj|FwqSc6ax`+p=2aS&ZLijX!&Zv2~FaPHY_@qbNbRu?=2#y*2p6x@VwkiieBz zQNsBmR-&|JD01{|6S|e#j*a#r3E8fXx-Rc_oBR^-dYF*^F+^cQr zqYeH`!?Lr{-J&wwwwBDi!txD#iNFJ<=E?0gr)J@yGUs(KXK8D|%)Hw4mr1?DQ}u+` zqrJJxP=Vf>s;Yz?RKhDIzS%kB@}(5`4DZ9n<>wHY0W!j>s-E#W&PAU}+m5GwxAm9v z%3wf^q@--CEBGz>V5e&N+jxb3+NDkel+I5An1Fh{(VPvs`ts+Wkj7-}GL5 zzwx#ICIXY5HLL!0^kQB8NNJ7qQegEn32#HlqiG|U99*C~y-f;-hzFn(9&v=irL1QH z=QVYMQlAOd0zVArpbfP{`!NaC4NnGJpGcD^Sa1&$)+dOg}s`G zV$K0KktA<>!R_Rf73Z#+Yrzq7i@^ebt~wmt%)$KiHe|^@6C?oMbit%JY~EgRNToY$ z^_lcqTOVQIpp7EWA6q!8EqXwKg0x0Ae}p<3Sw@N1Vo<69)j1S4gp{>eHy1K4!2#!B z0)AGw&gMo^YOrk80G}q_d$x>5ahgV`{+qR5>cnJM3$q-&)QUN+BmhGm8vlY=o0YxI-{;#wJYb zh-fwiTM&ULq>+Ioc!L8%{DhtOMcXk~W0?`DOk)tBO>jgp&q#+>t&o)xO!>WgM%Q6< zVc&$XcajqM%TEus0x&PDg@jt*sms2dvrW{ZUjOY?-uT%liFf_*?Dpi@Y*pdEfqO~g}zn;m0yQO(Oq)i&=$9lgnUx%+)W@5y7wQ$+M`tL6*~va8ONi(&?8^5s2nA@f%)2iGEl((QBEQRO z^DC%kah3>>z4}nDaMr?j>6GU~6&uGp4p7+hkYC>{7k(_93)E~r1=HnpS(F4iv|<^o zx^6d2%Ce;(h&)x?git?LR9-=f(f?Rrcs@17TI@f9WOHnZrQ_F2?s2{+TXC3m{u=4Hy}*J})dCfmA9v!8xgAS+ zLgWRTn9x}ewQ8$2{pMnpAfI|zyOMr>MvDEB=>l>4m9KKDj1YbRIJTK(`V#J=l3Wb& zwF%Qx-7Ur=h2Je*JM;&|+~fk&*E4=kvf*!p+AOVd5LDO+nb3r9+pu77#P;zgAkN5>gjjJM2V8r_UNQ(Z{hVYVDW|Dl+_ugUV3G03}c7 z8biWi6!`TrX`_Y*1(+J*a-j-Z8!Qn$42pes_2YPS*Y>j+iPi|aeq^9IJQYoI^4DZQ zoKNY`BH`tY#a9Wk&R&!iJZ>6i-yRW|6xTy+2xED^XwcL5$s!L@C&$u6Ikm>JwoK7% zAxUtT17+^+FjJm1k+iOqe7#@=H$62{wHmrtP8laO@8h$412QZPKIbY&JV#6tuKUg9 zSGs1P%>34iV#t?83&Uq-&+JTr3aNJK$>W^89aX9I&3q=#5dP)%X$9Ht;68YfgDId- zwW#CF#v`#*r*gKRYqSI;yE%a?`ieWSl{=z#Mk2ZvCu4=+W>cW+!T&YLY^LA()_x7hZoUN)9KP(&k~RuM^no|pSm91JE0)Q4CjrPCIGqO z!IrQc**XE?f*`h;2K7-Jz3g^i-t`)N{37<4bL$O~8ra9!GOb`#BCk8Jrd~)VV3Juq z*frTk>A&1s8KdqfjpVgfeDyChUP-9sM3{Q8$HVO6n<86bib92L=v2^`H@X!WYR5e6 z&H$@o=)#LNg7d3;=`FN^)8 z%L}>6*E1~y&mujdkH*Bgb_wAmcij6j!_gNghUpo6#tcpq^mG)P>|VG&)9++s8bzlY zrllLtKSF>)UNqQYRea94->fgCrRgl8;v9>33Sbeg1P6jNot(>R!kD|wy5p$MnFA|1 z+_*anb|7Va)be=NMMs9m&u&R+APwz^0>6G=|fP z0JROT96Rwbu3G(!;w)E#s{M~|(=aY8@NUCRqLkommD-(UNz+5v3#W`GbLOlGE%!&$ z=wmRl`)Ty{EjHX8_+NPAA>*%{@M^Ex>1&sK??l~mCZD9(Ap`YY)im+BO>%E{3~Tr? zigj?1t$rk?*yw`6V>+GryZ`!hHlgbj3m+ zie95L-5?ppVob;3F|ND0l{0X?^ifo*G(L6ewBWC1Gg9PxLmQ9WAD?d{EVMjNfJH}Q zi($eNQetxlW1Qw||N0ujyJNzCktM?dXHBLY)Ah1zwhmc05noHyM#9F0@tNVLG=RKJ zKE!U2+Ys!~fDdsmTRw|azhF``W;p!AW3-LqNS8D_C?z$xPmhTAbM>x{%CM+JaVeIN2QzS(&XH!Z)C71B9**{4q79#S${913JpQ1=hs6EvDekWfjmqfel#e-mZ+=OnFDh@y(ArWsf$jp;} zet|-!Bakm%@l+ojef%u%w#JGfV`Q4jSk*sdjmSZ>(8m+SuuTCiH#q9cMf^IRme4=C zq(mk^Z~~oy-}D_E8*Iw*6QW28(y`e7dRPUtVo>z6rHBBUh&D^3wukARYiq-{nm+SI z!yboN4afs)c&giPaxws73F0ChZA1s@VH9K>dR4qdn;T=(pmcBIh6EYPrVcDI!aLor z8;n6OHVcPj{FI^{F@{0)tCA2kQ?1Tg@Yj36$0RN*@{sR~LP<1o4po@&O5jpSRB64 zwJFQ;pjxOW#pBX@ArQp+>G-!g$aoj*wQ$MqMX=?|g99#hYGc_h)}uZJbm_f%(cdZ2MuyJndS^%I&ETq6(m)ICLs8M=Oneu5KB_y5uOl2T6Z^!7uaivO zK|hX>!3Crq4V_lRPzSon*>6KdJPkDHtBC!iY}0#L45IA&pd_2f(xGJ%peU>2mUAM) zsRyI5K^F{I`=>=)YsO8IV_=h89GO1iWXNrHD!Jcd#kSS7O_a3?3G;B!QWqL%^TA0S z$%v?Dn%(RTfAx-|3U;=YDmEx@$n6a2hFdc zPUA~Ug|*w1m)V=&vCoKMYSKZ;0{sQX+<^?<#i|MfP*PzmqS8}m{$A9yL|#l^1LVG#Mu+O zl;J`-+NTk6E2x0xpi&=%7WY7Zp@wn(w8n&67Jy8~);`>yz+IEtt2z*quI$Lc`84z6 z>-PcRw#6$>hJZs$zcxVO0ISaI3Z!1qingb z;|QLLYQA-;n(BM7!ms$U3O?kd8#@`7{_G6`j=#MiY6XwX{aj8prb!;{Rd2m7r z=J3*`y>cU)!tN%gy1LIXL^ghHlfxGw7XLZkhb%6N$Z70nc2LWc{b#0hWa|yqHVgDd z;PZ|{;IghU$){0LDcKVbN7OTU(k)-t(2DFz`-9Vw_Rw=!>F-dO9o6{6(<*E{q~i>9DW%SrItcR)mmGA9 z^lR7LqY^JDY}Y65JsKx%#ujia8u1(lfNCDXwW`71*G2pTD0T}+Kmlcqln>b| z*c#xfl0fd3sP!yV7P-VgvfotcRzs2h&*fC%r*XP=GRe8>NDrF3UXQ4zU-%SB5E&5xlb3y=1uAu zdu>H08afCL(s0pl8qITt0(&B^tp(#zPEznGoB|1HZw7I@sT2dxctfJvDN^AJ^xAWs z%easfw^BEpzrARMfwRde$_0z;g6B!c=>3!@aHCczQtYH<#3meVH6AloSKYN{pRhyPmnSzSl8E;Xm%HePe8#wxC zyP(a=aqy=VK-<(nr=l&v^z}>^amPwoYoUrlf`K3Ep~k3x{;OabcrT{^Dwqb|i|M}#rh)fj`mcg%;Jujst6&;Awo5f%jtiuYzgdy_o*1U>bNYrvECK2HuP5zY3;-_hS05f@$ErnEtC^8h9_J z|0@Lo*+RWJ>_7t?x%}}HsEpC(Cz4amz@zVK;rNe~j?9PFt{L;*m5Y~!S7MAA= z4I?q1>8hnEfZYNy%)yl(;hrFf<<%%#r7HB@Nu@z+Esqhl?2JrXl}mLZ%HTH}$+@V8 zLlT>_nAwY|qIJ@0OB@6o^Sa!{KC+T{^V}G0G5oQV(Z0Sm~uzcg^9P zFnQe*iK#fsI+964IyHM=W4=A9zuD$>nr09UYp1b{*yL2)qe%eHlwn<-*~GObo7Tv6 zE0z-#`u@*A9G z=7@9mG?HYDjwB#4Z&JQ;Up^7hKdh)biwo8{`BQdh-oZDeaxbc$oKg4rQf|yReZsYe z@EoD|2sy{#GzmFbRR*xC`y_JEM0xYD*zgrhkOq&|R zU;WkAq-JL3Q~O5w{0T5OD|)LtO3nD|+;S5j4#97bpLnb85Q2%b8MlWd8Q+*SxjA6Z<5jX=~haNX-7T(b?P#A z{{r^X?lAp0=a|xd6Iss|-_a+V=0B2IpO;z|Zp1fx?7D;T?AQQ{k*c$+DjiN)O-4cWk-r z(PFo(-(lj^kJcUG)F(2(GBYly=6b{$7wS&R!~gjy@$dih|J*<3 z`u7I%|0R*_KTiuR6Pk?QDj*<32%sPs|44?L0>k{*2J*Wkwtqb*%C)@QmImVADE}Os zAXNx|JF?0rs&0z^HT7QFy0)<{L5C=kAKv`a=O}_c0?oU+vnoxy>V)4}qYSy(v$Hpq zC>-ja*SKB1ADi zqLA-YsIDDM68xCGyov3XIH2J5Bgi;nCO|h*;1!kMFYIR7+fq5O`{rSGy1b%n7h=cPK`3qa6>(ZGgwSri)H(~Ltw5qFUF#L? z-T)7KnfYWA9}q1{7+Z1Fu~{4}Qg^_OGQ+HwZa%kW+)B`mwk+2WwC6FAQnlHkCecZw z%SDYCboP%xsz2}==oP%G$IRlwPxcyipM_nv;hDqB^#~IvwHc382&Trbv_o{Qxs#sF zei__%a9M(MzGkaXy`||{3kYqEP>slH7hA7MoCce&2OhQSoV%?Wn5*g>-y)?eZIm+G z?Qzosm71h)S8L{6C+9>H!rLBMe@a5q&E6=N8R@~~{NAf8(Kya2 zI+{Ib#&g;3+X%+fp3>J0Xu#3u2_3I!*vni1&g|UXO+>WIDqKUmg84Tb@iKOuMyaq3 z8#If^fP)!Ol?NqFrR<{=5%N7`c;#t@!7rw%%ilQmOt3V^Gl{N^vZ0s4w9Uqth#R_0 zYWE0?Po&S{ghA~>)j582Sq2|12^ABLTIt9zR$jW<6l|Pg%LVoSVPLclR z5Q!>!F+1dNqB|2YQoMapbibC`9Q|Vk_`vf?0$7C7&L{kFwFYR~b~!Dwj^RY)yF*CS zPc=Rxv$4#4Y3x!rc{N17SO~?gU?!rW4gnYK{Hj4uoY{cB-MFgpMfJP=oYbbf0E(Ln z@$JULFW8Nv@ZQCev9@r^)8j4i0Hg;A_Wf!om&JJ2dL;XlTCNT}ZiqA}Qo|!n8>^nF zP(Ti!ZcBHkXN=^mEZVZTbZsu9qvhLZ2uL6GNTeN{(GLW?m!NZhx@)pG8mvGle!MD4At%8&b3=Pwj%+@k zPk(~5c^M~0S&+XrweZIRE?<(qI$MrJBa&t20iN{x@Tvnha$TQlLFlHHnD39a&ZNm* zb6{w|FY;n*Ovbk9G0%_n95bv;NIokvLzkxn9_8CD-WJV{z}gt{u$THSX(eo5cWCSL z$c~Ri-UtQ1XBxvt;z)){Of+3m z82=V>ltSMInappA=_A1~(A%5JD4rLg)p@XEvyjD2|HRttu5|h&|5cXoF*Zgj?(ABH zZC{V{7GW8b&H&f-dPSlld%#>09$_&yLg zhy-N284^;f)kkvE4iW2!Kv*%Ym|O(;u0q=*2_fj*$zvYc}}xdc92U zi+}Tx@Zj(ET^dxY!6z1k$(qn3w-aK#~8 zS63}Y8gS>ZsPao0%#9}qubdrVQ0c9^Rg#3{4I@voNHZ;Rn6&CRZT*2n2q}N0 zF#L?TjlzvxTA5HP>LiQV(o44++yv=9vfoW6SzELPV%-!9-ZBi7efV{}BqW;FE}ooC zP+x*9M7_ezY6mb}g}3(wDr%+ZE!c$9@RvxH6$oFx4}?f6gi9u~&W5uR%jasel4|Ue z$nZ1g{ybwM-qAhszJq)7-I8_IHUrr{)&0|u%xW_j=*?oiOI`zCy7@fyxPid7f@&payz!itC8D|zSa}469=}z^ zouB@i5^*|yiLmna6Iv+|0pSs3LOF*KJm^+-j7|AD*5+BaTj$MyGu zX^qwGK^DHboT-y)8u&p6Z{VEop-!sRfV)Z3>7tTt(n10=^PMU0L`OVJvSqU?;ziOt z)yl;&+vm7p>}nd5QLNe#d24kE4Pj|t{v;#XD>>S;elB`58agwv5%t#BF`aZCXlbNqfb=v?hq3?8;K{uB!WuWr z6}3``}8za&p%l?%aw~yoN2Nr{ks;LVV-z)$5Feh>xC`%&Yhl@ zIU$(zkp~|RdoIKb&$53co06G{wKc}Ig4mj4+WuS?qHYMOuj|A@bvhidtEJs8M} zWmTcCmLCht%1Vp8W5qD3vn1xt5_pC)1h!ojN!v#h{bM@2bj2sQ7^b%VN_;A{lEX=hQU_H! zF4Ucxn#84>Bh!DF_GwzH?#J`Xg@&tZ86tXFQ=dc9m*jSAs#@~WSC;kjOcfIoJRr4O zwq>QG@*;DVRFs96n47gegbe5FTN}50knW{41~buh<8BWwWin7(7aANo>9%8>Qhw0 zl9y3w1gZMTndEojDjnpf`3i@8MkY>FL(5>Njc|XBixggkZV>V)abt5^I_zqih14s3 zQ;MB67bJfxICYm)2T>c}0au@?KPwcM6-H@fCVEy5h553@I8@%*5GLRrKb^4dn6BJg7w3$gOGm`oF$5AeM7RKf1-`Xo0Caf2d^E( znq5u%teuZOUrgE;VjK&-EwFZs$Y1X+*X)rD0u>o9RQ7CcYlQ_v%EyVyDwixPWK23G z1F3Qu3gvluT1j1ru<5f}?=p#fbB+#{>8MJtQjtxWfJm+gMWsS zKU04eAa%uw-xV8SRLtas!J+rww`{YP&0DrTAeDaaMDSpU#?-gNo7|nzT5hZ4&CU>0 z?X7e%pUs9^ zOQRT+)-8Ft%$!L=ta#|eW`y?j+rjO_^lpD(sw3;<@5___o{YzvV-+(WZ{H5??yrV- zgX!L)X}Rk5@k9*x+-~Kwi8NPoV$K<$#WGjAzU5JWD3vp2~_6hB4Yl zV?w9=$H(Er;5(0@D1(ln@Big7AKu+v-e10-{yw~Wd!L_^0fphxEMdWzt++rGF0PN( z!il`2SlE8{bcWNL$r@ z5PU88lYo$hXgzMk<4QcP;o~3I7KYbi4XyA*0M|bk!IQB0QY=Hu7W981krI(uN8;Vz z;tM`@;NXK@b`U&~b>2bqZt&~i(}#T&;mY_^P@vcyce_%Q(HJeAb@Dtp?v|QQ+2U6f zpOqRuD!@#-bxgitHl*QrxPEv)*he&WVwYE>EWFn4J!_8b`vAS*33p-M3?AMM-%fx1 zczO4>X362fqGL+dz72nZT>3Vhupjq-N8}YhT-q;ad_|U2IFZ92Cge2LBKq3qp@lJ0 zt$^NPQYfWP*zOxFG|@}^I{S`{OGuM`1%==(A4Tv?v& z0v@LVZ851({FeWo%@620k+R|zo$JaN4?Dw0+9H8alPbixUsk_1wo;f6U%QM;c#>pAA4Z${R#zm2YxL zkzc<<6AaMk5CW6K9oJCbLgl0yWv6@en|_mWGGi_w;OZyf&pspS6Z`Ngq}zKt^RdIa z*cThlOUuOSFOStHswmcPJ^9KFW=M5;T-^a#%Q2-7C-msF1+kQvX&5^A(caP6=y^T! z-P&#$m_2`7e-PI>i6kLtq7_0 zuY;m6dOsqJR`9ET<2hmZuRtgdKj~A=XWW@i+DL|L5l!AQRA-?eYxWc>kmG^w!jUi6 zWx<_(;%xi)LsUj#rotm@UjB$rWo2L#hY5dI78X_6*(`C~cuLYB-!v<8TcP_n9+rT^ zu0pTh@Ni-!W2Ca=F~T;)Y*w^Vf{l#`5MhVsJ}brBvz4=m75d4y5<9q?5{FixBx@`B zq9llXV?|OznbCi2kmmz&SqlyoO64tzBsmxm0)_d?SGY&yN08_S3cLXV$T|JSz+Zp* zNvy1`fOJm@!0C7)k&zFJe*UOrKT=lc2UPMwrzftn#&r@eLxYB*6|SUMN$gW_s?3%W zInZ61JrgklWxlcwpwQsVP=m?t$J)1jIB)x@w*G%r-9Y2UA+_1F`;!J;02>XUFV%G~?%Zg(%52j4 z3~w($BIU$aW1_#MF5XY-&Ejai5|Fodh7xZkmy&qHCF>lNLl4A3@yAmM+XnPUGL|B6 z{N;M#Q7cm#=9x34cTckMRv0L}ITef0nGf5N!6C|=4r{fdMd2jL2Hmg@bK!r;cdkRz z^ZGVgS=7{(N7t@sUeiEP5#tz)=gwzs-|c*+DZZo!d?rNee8vT0A9$cX(>N%fr{m{U z98Kw%Y@E-+N8=~wvx>$aX@q}2t7L;alQHqvZok!~aqRk^obDoVx-x3(UFwmLhm5&s@DEfdsA4XX4|CQ^S0nYu-7bkATX-zM5} zLO(%fFQ69N>+7BNI(?rm(pTwvk-mSGPSYRLQTlzkr5c66L#+|G^8uM^z+5?_)=M)i zIcZ!c_i18dtYvF6419mS#c}PfnIOE=<(nK;4~%~mArArwXT%{*43R7l3Jb9Tc(bMF z1XKJTOu1SRG6_>$%Vw>B2`(=Yv%0(r_tw=@vBdw{Kbenx3Y2gPqmArK3lpAFM~K) z({2j0XqcWkD)`LaY@5(q24j~9i6njWHE*8iQR+vPWLNo&DG=-cR`qqrK10++YUPbF zYATq8gzRYpojI2gZCiLtxyyl*0x|jY^C*fIL^>>2yss_S32%Nh`m6P5K{cmw;Ip8~ znMFy&JGR4WPoIAlmrNOodd=vU30nRYq&6LWZ|MYuv#4-}$>I``MP2`i1_;7N zhk!Lt!|{Jd=aS70Ku|JGI0_OJL}DdD2H?ka$Wl^&;xaXvofUt}?kinFElr!wLH_U? zc_Z#^BFVgQL>CHP|vs_iR6a`UTiVJqiOJHbzumX@+~wXTrU0Pcph`HTye45px_>lCbaNr z#^?{C@8Jo{-zDEd9W}?nQK7D+O!kRvtF1=yN0g=!eHZt3$#JzJrZn4^<9y?K+Or6% zMee$EWYaLbvQm6m$}217m6giMN@?n+G_HTCtgO_mkkqV;w6K=a!a7T#+`7{l0zMt>vDU(GMqjcYk6FBP_XqxoZ5ui2f_1KsI#CS{c^9 zXx`Oz54qzO`N(0XD81=4ONh!$N{jv1@_vDk^LG#g9(E2}hpNn|@M~S%JUJQmO5%T` znkm&IGU;ldsKH^cN}pBQwn_4w_1PlEBnHr1s+`?w=(Z+}=pKsbK433||GBS&x%e*1!F_9_u~TA9&iU%=3~mcZf-l1%)6Ah$yhJuT&KGlOw%p_C0$A z820bGJ=wpEK=ojM>CyH9$q#5Trci%`SQ~8;EwU0yRfyKPPn`Qi)0i1uMRXIb^hHjo z`It>~Ka0MYY7<%zMq@eMrs+XqA!y&(PI*814NC`wg*AfN11~c$0}1-g#;awv37EO*nQumg0;y4kTat7tKRBv?MSIZM0;f|$)LqyssW*R?)P;!7fvyEz!16H&kF>aG6ZngXwSQvM)cYs4(ng_z z=Ks%Y`F+CtqL=Z7U28%1~$@w#FF-HQM1@Yexx%r!x&El?LN&V(h^KEy%V- z9wmDavn$`+SVDl?Tjo70@@_Q*X|eT*=hh>4d5YbAjOrrmdl$v;-M@c9dSQ4#=dSOI zqnNO8)oQO!?_RcDYT~<(l=Xm!9uR!_19GWd?OsqC{-O3cx2TSNK9G8QR*)F9pB8uV zHVC96V=&^_ z4X(c#-|KeMZkHh6nmd053mIr*I{WR?jY|CcxjOM*D#n7y0YPWNiH5XXi&3^(FKIO# zjVm*(Olk_*knLKn0%c|sV5&$;6r{>~N~tR3u95!i@$_xd?aXc(Qp&Tz;Hq=b+H*L! z8h40X?V?5zT2_&2nzmU#P?iYhipSf!j`A~(K-dG>Oocnxi&TG~v2>7W^LmNl-sE~% zMb5jl{4XWew=1TtSFI=ItE;7Pa_l#kGM&gD_9Tk+M_$lm9=L;C9ShA40`Fq z!GjWByz?!U_Lk}flU(V72}U@RUf9(=UU!Ghc+wag?{*jFT7HvlVw{PL$_A9#y({If zCsB5HzuoVgY2;2%r6tiF(EJ*7S`UxyiPAc6PpMD3*wKH|75uDPnf(NB4qaHkWcZ+! zRd!I>A_~rp#mvocCiU)F7+Q$%k6&!Lx&q^0FkP)KtnK!ny$|Q-&LK^m$>9Kah8>+jX@qsdj_jT zwPJn+x!%k-tN_it1jsI$7R(n)o?n*pSHXWwzs}&{>hQeROo5j?+Ril@03zrAh-)r8 zF}5;s8;f$bxm7;Q94p0Ec$+EfgPyKSy;8B>ty!#F{I33aHo!va!LAEFSo?c%Zs9WT z-|MYa+#3a9k1$X!M93{f#6YC#8Mm{xAfL&yaxkCugKn$`^{d9>c}r$~=2N!S=+S>Q zthfUI`O7!q)+#|kc|e-RX^Of zw&$Xl8j68}Egobm7lXmo!wQk8EKh&Cc4jl)$tP1$EDU|vPEQ&hw5dUHML$lDQo3~5 zp@utWt=pr!q(LsGk$GRjP+^^^^<3G~$`*7CQ0dr))Qr#(Ae@y6lgL;|X|y~KSeXGG zMlcPu?T<6@5)a5*PUtN!*q8Qbe^xjb7(e5$cwyx#d^bqnF+Z>bra(z8- zMN#M4Hf(>#a6Pd&DjHPjE*NoE1*0w9mw6{r*GR|i_Lv6DCmuoSpmWyd%c<%5PW~R1 zkCZ{u-ItA3<(rcuCDs9r&t`v%2bu?In4sh~6JF1TFPitoZ>igR%Y#-F z+us`uumRJNwqQE4cPksHe`InxLzW)vd+t{5BzGaI4^>Q+{nkBApLTyOX6VtLPRXsm zynFX^4%7E1v<}0X@!lc{lRzTGce3HOH4i>8em`{BEytmD z55?)KD%)&)REfNE^td>8cqwJ?5EiFE+45Xou;Ol3k)MKcFz!`-rz}FXje2S8Qt3&N z8!Nk-*()Vv3w2Z5=GK2MhE-|Otu;e-_71KZ;G16EO3>Em-HL>Gy=PpBuy3lAsoE_g z`pkU3)>$fvmWu`+zgbXah^!|W-L;oveeVPG8W)F|RMVFCeYg-Za&R#ix+1zip}(Hx zUbur;ydXaST)zd|tstkU8^QVmXS!G@4FRaOx>@>gj*RS7{h=+?72&@mf1L z;)Pp;=)LyE;1F7m&e_FaGCXuI(AXgdfGLSN^Lf9gb74!w5e0UiZI_MgKm-p3J9#6M z&|(F)BMGLKl{?EhL>jT-$m7q~6JE64guv9th+9$ZhI_acsc7>rT>@;*JC#e+hZ#mxfySTJ$tx*Yq zb+LFg{c%_d;Zj9Xzo{mx2x2DF`%Q)s|KAF5c9d@JEs=jHngTQ^a;rDx>M@#Lgd}Us zAHP_1v7?pl9(wqT|M>6S|Mfp~{I&PObFKFuz-r+Z~fH}b$8ie6fu959Zyyu%>ifWLSq z%{Dt0w?ltZK9BDlnTapkRlZYI_9xm==6bF0wq$mo<~_%xN@J%e2xHiGQ}3{vACwJm z;*Zudcq+58X>MYw_h!AlvTnyy&CU~IXcfR`>$UgVc}a|I7$h6p<%r$f1N9?*fL9CZ zvGeecLLmTr8N$*SQ6=90@-m0ue-(vnXdId!Gsu7XQH{M77+4KRoKfdT)8#s;iv+TF zUeNmp^itaz%h@l)A@~~fr+y5FX*qqHM5~whes1mUh9>{D{DS0S0?`WzAQ`8epFA47 zAF$EC74u<9)#Y&7AcsHwo5$A4ci+khz0;%bGSE~Z@Q(t$5Aq6tO%1?Sl|MdTc*~VP zkt=_E{C+*9ufjWde+y_v{@dF(7_emFq8zr3v8|6qTsTd=I%5rHa}mRN!9#D+Dt^ClUult!AP z2DN6X9}C15QB1$7Yn$TocDEd`SiFmet>Kz5MOz5@)Kkk2uJxKFNO1YL6zw~A&z@de znX%Q)(U6(Tt)yWnJ8yr-eYc4Z4U0MvTc*Q)K*dO}hpiOT9hg6r$ELg&KnBV#Shj!Y zuVCMZTgpPkJxEh)mfb;#5h=p)cRDFcq4=#%PU~e+=C}H8GDJuP8HBbS8^>^HvTWPY zjM19OabXNH|DN^$tUyYCgI?#fR})^V#y1GH>FwYggp@M2u#A6fYFp~=+M-cl4Y$RY zDveW4dgnh#r`?n((p^o3!;+W&ms@|A+GAnKn=aC?3ZjpT_VKV+4o|r&d$f%y`V!7( zFLsAXFE|cGaZ|S!w4?2_d-poIdURiZutt*+C_FEAAkBx^rFp>~)fvV%jGkBUy-6~4 zW}R}SSxmQM{HS3y+=H2{Ib!c~gqDI-zNlv{#OA7-_(A3VJjadBh2ZJj3rBxnb4ou; z)$G*?E2I@OwEJ2$*Sh+Fw#M)D2V*O^f5C-IIQ-mQE^Ky-3nLv$VH`(FnXn4lwM^t{ z1%n;pUo?lqypC@+omz7oTYeU>%@KWA?y|>`o;Z|6?2Fz~KOf;Kz%PhLcV=(F8M}oF zXN{ls-^+alS;1k9mvb@SLss~f1%l5Z%LK>r3NlK= zTnIPwg9r!z2G;I9KHzmkoEqrFtt+$HxS~N2a9$y&D^zXm+H0`UE=Yw-l0D-3|@ zr65f-ay7hANtf$$R2T>`3LWu%b5vy_r_Neszro^LG{s}C5p6cP02pMawglv{ zgY4DHtiC|x`k!DJSFtJ|wOP)R8gWTZRR;?3@iTQ{gU+%}r9Qlc5Gp=e>`Z|f z+xYe{t@8p`d zhkc_VpZkLw%-JRix=t^!g_h2=VVOeDY~q>9(4w3hDej%-+U|dmSDTx=IO-2GEp+eV z>7adNcZRiAbm~v$*Jz9&IQkdZtCmLD5Rp53gzOa(R)k{hExL}*uHpZ{yq$mb^lb29 za5y*^{tJW1R^tEF29nj@bgE9Nabv~B0`)|sY9avMiM7rX9sEI(TI!<9;juspq8&bP zw4rGbtAsDnO9_7f*8-whQK4rZXM7v7~6XoIMAIztRFw)$cjJjZe6;0^_g_i$))Y#+8NxGwsK zXT!6Tavq*LgD*F=s`ohGC;=QXqC%4)PTWlml)36yUzG*-r*A?SwE94 zveUuw&wqLI`X5%0G&|2rRgjqZTO1Fr*iJ;{80O3Uhn5rc_Qy$d6$;Skf0hkwP1b?? zH;<0KyS0Cvpv*7FI>|uS&MlyS+&Mb__Hg(Y2Z!AuB6v;?2ZQ5IZ4mroy!wj+mtNUr?@I;?xZ-*jMorAt@btugFNi40C9z<#aIn1pSw>EvI3{q^cVAuK!JhjUd( zGQqLo?apsIH{af-gQSyhS><=k%oV$whvJ)~x>0}3ay4AghJyg>#|MakN-Gk{a}4-l$u9pcE6HYG32tlmxbW5N4cSt^kjTh`Vb!sHCkCeARJ_Lr*n<;Q!on3l7kgR5%-7 z(Pn?|*a9BJGan(2l|K=cJ7iQ5NP+-H@gD47cvBz8P`*nLCNT#94dJZ(cMB6(bdK3S$2Z&ae&HQ9rby53rr^)6H#;ouss1Au0jUyWtE7-NI z^^%yyoqjJ{5NZ#p^F`Sd-8h=<{mzn{=tF=07U@m;q*Ws3P2GPIIy>bsSz67D3 zITUx7Bm0$lfG=ZzIb_^l`lx!d@JB~53_souw)+D8{ubs-qt*@$A6|U?>++}BpC@WQ zx!Md5*wvtbCTl4xB&)g}>l|F$=h$5$h{KzD1>#MkF?*3LY*^s6Zu!k`p~v<~T77?; z9fO0^6TDi+NGm?q=xFjEyg-q%SkQxy=x5Gx|%m?h#qW8i9J`f%2&mr!da zLcET1c1er&C9W4+K&~kqhdS;9+iZ15$zUp^b8DtS6x-LuW4o*6iO?y9E zg5KaQiyw!%QYtelAr8S>nZb3WipH~9>q$1l_VkM}UvzEl7am_Y=RAQRA*RlG(JX&r z3CXQ=7UzBQmZL~osO(Jow zyp7|!`X1NiyIhy)9x4$S9Fu?Bd8h8#R;<-_(IOntw=^A5;bI~oH z8|C78-YU^Rm|FDBgvT)W&biTFo}0)m&bj15^r)gXa+{!ia76S(t)e{Fc6uFy>J*d(%ah0e#3#zPE;bZ>ut{t;GoQ^$QB zg=|{s0*mqlWXPo%yYk1PCw1K)-@ks2jB2h+CqMu4;@!J{6t86)5}nQb1anSFq2ERv z{;1jPeM9}^&^$OSKbJ4W$nzshqv(;#E|;(0x<9;l`|{7PpS^qWgZuLJ%XcrIy?Xgy zU;Kh!-oJkKw`VV3J^O$D)eD^d^5Wm$zx?IJTlekzpQQqQ$opTYeEIq{q1>O}ynOvm zet7vBl5s$V7Jhg^-~Jqr!r2Q#)hOTmjBa=f@a^AU{`ju^+-Gm!zW?ck`})mmME-Wa zfAQy+uWPQqc>ROC(~tD%AKV|`{36Ze?Y@5Y(+lhD&AY$+^5%c<{9f;&VFmP;XRm*F zCEq~pS!aKH_Uio$`CdMK^YRBdv$oGN0V^Phjx=daV}@6wtu`qXtiCCj-uki}Z z1!T9Ca92e)>~`x=3|^9U%V~9vA){`$(pHBJ{){7X`zC*V&}lUr-Q|;LCkkp72}^XUrGYbMC>tzz@< zC-VrYfoW%7_=ty|e$7@xoRiIvAgotV3*TR%g&BBr`m%Kb`K~irFOkG8!jU!+$SKgH zL;x^NGYN{NM=+>G_2T*Q9r9tQvKofHP3kNj#>Vl{Nx~_xxH~>8Nn+;J(7QAj`7^k8!z*> zlDGun#4I%o7SesJX^zqBF8NLIEs{~t=lp+poV1!c2_dSNX3py-kq0rFFpn4Np=Y=y>u9HN_HQf0Xk0sFDcHoi2LR8EOCf4 zLzX1pSyG1yA2$mwfwYlAD8Z{=v2jm1D;Phhf z;H&dtdw^UXqx3!zL+ySaVSEnK8!B#7bLF6O(5c+VMnP9M!(LfA!=5J<(WrlSlnjsJ z6At`QE9S^jmk$Of9J+x%_GG-Ko~X*sZ#$(hMHR7(su9Y3y7+W;9m79Z+al#k7t5q6 zrx1$u3yPH;>KBG=hx%z&Ki#SR)2#k!Q~fK5JU{7rpBidec946UK3Yn=-F%cR`s)VN zcfo+PUXI%8B4GHTeDn!_ZPR}(+oju*L-FhGA6#}v$JsSJFU3neyLj=a`zQ9ubcZ5b z7ti+2Stq^t+8tJf);D?kJ^G(Ey4x_`Hkec zS0gKQO(6HDg#tGLR_K4akf~8@1zVx3hNfeo zu_XNAMCS^`aK%EC`K*i#WT`BOZp#wNb$@(GtJ8J-B@#tz>RCRCI5;8Z1WPiNpc8(B zxp3X*G)dmFkWInO6MhZvcAkOf#NN=)h7O$u~z zae?5uEOVC*%JP4TNOj4uZfVHGmqZd<<*xexA)}wtbANdG3x5`5g>Qd;_8i|Pe)(FM zeRnKmE7yxo^pTO_W|6&@cSo;_(D-Fs9+?^*M?bW?8V zR4b6XEOL7+@&fg5oQwAJusS;_T z;#=?lS{sh_lm(yb5m}ygPdgdD9bErm+8ta^r#8~fFCO%E+(=7qoY*}Zjj{>f6IpYS ze$~2L?zY9|z8sgd98&ctY*vCMTjh&)gtB1|!X}T+L3{9^^?x;1jaNvqgK%g0;|IqN zOIaj#ZFYaHtOoZHhn}3m?F&6>$bfy*#ph0h;Y89V1R!Oc3>h(3%dfS#>^a^eBmue6R!}LB#c6q zk0OioYit_tSSR9f@St4%@nW$ER*Jsqb(Fj`gYJJ%wi7iU+NYEIauI!=|UDHvYsPi_acD%*>|%70epytpm-StyX4?)oSf_=QK{^X*%sR zKh*Zn%j-8ks#t%W#_2lly!!3mhG*rdD3K0{Qu(j0evYb`|GTW;D>wUNwB+l^Qye|L9s4X%I z;NA|6n57EaGjxE-X9MZU)xpKRvyz(~GC4 z!xKdOgTE(L>>Ymf;dclB{52h>lHu^=tQaHGDyE*G9L;_FMxg(6s8T$IzS7Q+G`936?I_ySb^&;C5vkZngkWEP}JY-uU zMr|GYT8bUT8H)p}3KtS-gw6uYGII?>W{)ht4c^|tqT;o^g%G!#a_(E&S`po5^!fb? zKM<5Cc*ttG9jXbK8YVEu6|M*qi zk0ujPxBiW7*|dcrz8@gvs5S_urFnfJ+0_u(kgh$(wY7Z>ZXJWO!P}06uFZeguy*&X zLwr)sf2jjLz2)q)yYmiyy~i%ikueg@COfkVg;@I!QkytG*(dF#EIGk@P^GYTh58K0 z?H-))JGs?_h<>ZG!BQUgexL5Mu7HO$@wrrIM?Mc*mi2M_1m}s0Pcwvo{eopTrd^^= zP^a9(ur`hSM7w=^L- zrT!`tOQ|82(q3UsZx8S#`&LDvAeW1w`1kg6h=;|X7d82QOG1AOt;89EtNE?4plg0N zX~^!?-fLl2^Lt@+6qO74^(S#oV~&p^>x4t$%}(-6bsTD}R|yuMb=QCRc8j&uhxWzk z+3*xGi?8m(FQYB0tqzOAM<*9Cx}p_Og+g4ue2ja80}JhC@c?HX1C2Wwaky{rp&i6%kTqFJfQE+! z4#f&b)9eDi&2;UH%XgzFqj*fr5xkb#g{u9^<)LlMI8*e!&*%Xwx+im-{4ofA1bNN6K zWcE*PsPXVgMVxuJfDdw}hRg|jI65{cYJ)u@CVy%BNrfH1n=XIQJ=WgdWl2r+o?TK4 zvI&+jMhoxrCUeLyfMnT0C%@J_O{VL4{5u&U?nxOIuJqhu)~tv zxEjG_&xqEKzdU~@>{z1v-jNm7?21IA+*%pP!!I+#cNDswNO20z?h`35ZL#ghfZRSd3sQsJu&G(ucCis>iWF z#xw%pLMwSa%tR@)_zhjr zTJUB|&zZ&W4O#jzPh~ZZgOTV<;XVW>j=8^BWy;AFwT=?fpf%os7ABz}-w)u=N8P8#%3v)Sm&Me_pgVqCW2hF-pj{j{S&YG&$usT+7 z&5;WZI&goD9=eP^a>PH$=DMEvJ)vOSg#@wm$3}zRWQlC4IEwF8kf+Lc)oIJ4A`a; zuper8%C%=ub$hc}%)#FvW@1s3mN#WX1mH?fE^mKv{ zml#I^74`X&FEaM_Rx9|3#p5}m8tQUl02nP}wr~XaG5!L2F{Km3E=S^CMl+W?MyY5V z@M{|9vS>{=CTwa+hww4W!1xfzaioj2DU%HFbBG#QPvDcfhIB9q&=(W?j2};@fn1GZ z+>w7oe8@YGP9`HZ90e#F2!l(ujqonLVBv`?7oE(^yc~HGj*CO+DHsdn!^S}i7Wv50 zc1AR)^Q9NljP{c&->2WCI*#s$v(^SP{K;k9Oxsqxakb~4J`=A+Izji3g2cs$qLj%9 zNLzdZq@5DQwUjWn9WA1fejKl4KC;)_D4Kt4=zu$^DQc7hzPqxN^$EMmNiOEmdhrqA zF*yqk4z#ckZ2(`m!LZ1UICAbqUgLC-6Po@wrEL}+N*H+TO?*>MWDg$01fE96!>3}D zW)Xsf`oV$^+|V3IOk*G^ChW{9pU9Bz4#2cL{ptl}fr8JpF*+b~g-RIO8#tI~{FHy8 zEd#i;Qt1R;G@eHhzXf6Y`I@GdCNL22ljaUe5FLRwWf}27zd2jBh@%71Wk4G)o~c11 zbw*}3nrjlcm0|80n%so(fiwMh9GJ>9e)PAH2x%y>JOE)kp>oZKr5rolbE1P|f{T|1p$0X@G%=!caSpWIiOibVnOEP~**5^u_rl8i1*Nh3(zVIpc19BArC^0p#`!h${t~ zLwN=udbI$mLhM*gKS%@S?!?#C5~wBEr4v{UNQzIQ#Z+s#FZtjzdBLTdd?tS|j``qz zltOXgt5ph=0N5LcLK9C8aF0YvhkDBwJ++vw@#>+@iO`fCxxdI z6>*_!6WOq&Rxo*asCk3KfmeT&0Te^rs|Juu8ZF>GTx{PA2ohsZyHGI<7b5_s-Xxe# z8G!A>%Hu>_bSBPA1mF?_c-6;tr49bvB%(g0aYbtzeb*+ME@=wP1-yb|216TQjS05* z$%tkw?H(HcO-5+_GZ4pQvaqQ)L*Pkf6fUsz7>e1(!7=m)Vc#`)8M%LL$_$WjL7ErJ zt>dKRB)Y`fafF&_AnG}-q@#kU7WA*b@HSjSBG_hBE*Gw*dw~VG(h{56gy?bKB?1D;sq|jEo9kMCPcDe1SB`BrXJvBN6f%PGaT@@lc(o{z19h8*glhH zw46xE-=$&r=E$7!jkSzKwPRhUPcuWzH+_9qm~{sABD?J9Bs_mo085z>1kFW%T`>hB z4CaBYqJ=l+n`YwWhJv0M%4~pvPP~c(j;oi@PQzJzxYbD3k3>k~qteNKCTtAK3k|@U z?PA3v2uH>o3@Ky2lv{^p5dS7iPYX|U$qxq)r8%jLp#p2dZL!ZH8^pr3i2i~&=gD*& z3MqJ77jo1HHWGgwDgvR^HQ+wV!N(a$6gYvBPSNANR|=Ost>EF0*HL^G;u!{@ww`)` zVdzUJoi6Z87+7e5sV}kG#SWE@N&-YOIg5^U&345YmL2(Mpa1CN;WLSe8FExfT6A-X zeJMxtfZ!T0Occ}HHS8q8%uo{%j9`__UQQ#dFK&<_#qxh4op+n34tq$72dwdfoid%l zN0$XSQ$kY`gi`}@3G^;Qco59ma9|4UyKe<%L_AGa&J@I~u@Hw4Y*d~h=lLAa+x=0JF>l z0iCkN2SHrPPrjqI7KIuNiS1-Czi6)U3gVmvoQ;4>of?&4&WIjx#1I0O{u0{`F_|8#oWgcS3Ri|gfr6Wu+oWBke~L6u!V+fs;WuKv#jpA|70JQX z2=pVI$#HPAZ44JT;wZ{;riB(D5)ku|76}emw*p9CVJ+~fAfJVI?JSrHU0`Z2^lXL< zEOEGx6ctmzA$wTQ6XR&jmP8BMJQi}KlVE=oL-xY64u{8l{FaYnN0^@lZ)z-nU_68a zI7#B266CWDMgE6_5IEo$=}+lE0J-;n1_{lqNkA@WT5_N3h=Sm&>F?3kI6lTfw>%T7 z*kEdG7xD})*?vjoTmfB1_(BwT%bAjxNQ9&D^eg=3tDH{Y3BAI%#6-g^odqA6W?6rF zA7!rrz|#T%e-)909+-P6c`*{WrniDrgZ>z`aohwtKn5lS@iWS06JU|t^O4&DpRAYH zl7^f9WOs#(|5_xL0QB17s~Bw*rh^2Y2a4%GIipoMf=q$Vlx{;7>~ivZXGs%ijdZRD42%~BW7JtS~PnYl}ODn%JVA0@os)e*+!~!=eS8|BtxYWgzeRFW& zG4yARt!-^>+cvhgZM*$eTie}w%dNMz?QU(`c6xx0Uo$z)#gGD%+YlJ`Du zH2G<3$-uT*>CC(u8xw05`3~kK?uZ!JsS~mY-3<^;7)_GHvihVTzE!IIm(EqFY6u(l zqfs`b{_Hr8{xYdWqD<(j{`Gg>f>mm-P#DtPDmm0Qld8ZWt(SZ!kZW`qd+oGnbP&A8 zpN1O^4BRx|Q0hs8Z;s?7<%z>ZW1aH%p}9z2oWO)6ZQ_WNb)WHde}25l6-HVDpei4` zuu|j{JV7lpxzkW6Gku0m~%yXV(P zPJ8_@d#!T?6pkWE(S&txe9Vxozkht=jT;V5-m!d!a)jlLWd}{y>&ww-MSm3wZ5H|{ zk{z(VlMaDfk8V6XQb&}W3-e71^J7;?moZ(x=8`@z#9_iZf~ZH7so?AcHYtnA||zy=Av;-^C&j&lb@lX4NS(L;`vu?-uS@*P}Scm8O1ss@9#3G54sDbeU5uiTwC z=Fc4ALPjS>M^5;G7dBA)RwkAt8^Tk$r7hevtkb-}gt}n*hy&7J^eO|+#{>a+GXf)6 zp))L$R+O;t3=z18IofFoz_nJ6of(!jq;#*M1`i(A5F*avDo8l({TXX^ogX(zZ*?E6 z#+y04nKTg+4AU(T*`<|Xwv(ti`-FI-Fbc+=vId9vkU4*k6am$^DVH85`jO-R8v%SQ zQVE>CPVqD#o{m7vG!9ug2O{xbpr;T$)w$}xwVrV*@6}vH2QBOw(C?aoFTP3h3m5k% z701t=o5a2+Cs;w9JQ3R-i0i7M)H_#A(F?F>oXqG!ZnhEOlt65^pbP^{TG4~&+nN-J z{wfddw#mF0q3_A&@iSa-dQZuXU<~s?OvO;u)d&HrUhu|5$%1ySp%uvSU6JmN$RH9C zm9pD{MyE{?Q~kHhZ@C3l5iEped6(!?&i{_N5`I%mJ#H*5 z_7#LL?ynjZq?txKBoBMgHi^v9{KO32GCh`NQVLQEcuJDAmV`lP!3?+>W(S&VpS3dx zp$&D6aftV<28H*{;Xs;EX!3(BGGHMR?kon&#aM?GWF&1b0Xj_-TtWQ;v;L?;a6e>K zxbRe&=wvg3e2KWDOXhdKs64Cu0%?Lw#2+TQgK|nH?db&+3B0#fw0qA#>&UdPi^zQf zsE8mSF-)d^qGrfaSrI(p?BhPGV0H!w;nHahHv-Y(@TAAr@)YhQuDn zeUJ`YQ4FSSB4#mul!WD((rp&tg}FkJ*8H2?Cwld0&Jb`&STC?7)rR@ZkiYq{+rrWyq)y6N>_#xRo5at~JNTwk!)`!k&hoy+A6+`BH1t zc@(}t=zeE|ly;vX!wE-okAdvto^GHz6e$sqE>BT zP6c3S49LEy+`tK?e25veDLZ|9DdYHEaugp$44T)a!V7$;pEX+)`;`T1?sY=+-(a2{mg2W_U7XDrq zZb>YX_Rt{b)@rIzP-O>2DA_QR1jPhsmt$l`z|xZcJotVGyNmclziQ3`A-QcHp=A5y zQk@1j910^=Z;5V$m`Z8zoqS`2OGJuel(5EbnDenqGig~o#Ohg8y%d8Y{P|3 z!rfOf4beYmhhlOiS>@I)is@m7JiK#8)`k(&vSEpSXraxQm>sO1&mBK)At5p6aDbi0 z29wc=Y51p!MATw;{#sHFDbu^r5D{0z0)VqS9*v&^wGw8v;@DNK(``i#3Rn7J@B`7I zA_J7z&W!T47q?PMU6nR z`Ym?iI}t?IP;UxPycJA2l)!*ld`<&Fb7@sYTxHw>>EV^J8+P2EO;u!#kceD&af(lm2ze`FDiNTJ zj`g#9lOGb>CFh_V3Y^^}cgYK(6?SjZ^U?* zt?dJTI}*bT`YCHn^MPumBUK5ta}fM2Ck>E~ES)Q)BPR72j4;#&(afuv-PP{_#mkh^ zaVmZak6lfKTZuF!3FZ=U?h;!??1hLw|K#EaO;o7sr)Tvy0mr}&+KMArHnzo{CS6=Pqw_C;(Q&CeVK=sAJ?~0eCv7V z!K%Adx;J!bRz~=EP>Y+NJ0_^nU4!SFDD6@He;$0})E3G7z8 zLQzVuN(cK_-rA?e8v`#WFtkviN+m~h&6!&H@Hs4A8v?w--W4jah}CUWO@~PLV)?&{ zvI@m55=;22T(rmks(C&}Eu@Fx;t+;4t!_lw4Z8a~=R^n945 zrQskfHX~tDtOH6kn^yN#e@`%5%C^zRIC}HA?h)F+n#GM3z+H!V4js%gb`lc0kg6L; zRWo$*93xJUbv{LIRgYR3?%rFvNFGeA-vl*XtlP*?FRzJq*^K|yRanw)Mv(Gc#2d@7 z%?`G=;&hmtNP8X7+WRwUr*(y5cSYJzzM)QCNIV3~t_2L$yab~aR)$x_9!71>MQqyl zOxl9}=)ZO-Yl4yJI1?$qCF9~4g=OtL$9z*hxT39US=2=TlT$T+j6dH93Y1E-b=G01 zROb`8`?eP#RLwemdN#D4x~p2X>a2U!S$BGbW#V0i4j)vlwkXWL*EmIzAa~ZKw400S zuBvL=Q^a<HRJ}cErYcU%3 z2IMtAVA``O{S2Ajk#eEVnxnqqW|tQWZqW*81^f?1gj0&!I7i+to{PSC$^R2lN$>d8 zKexl29)eU+G3EiUA^xAax!#ht%g;Ga&gKN(3yGA_whZg`UH7V4;rKGUHs8;g8ALp< z&+7+m^MVVYu7S{D@ZF(lp(l3r^ZkLQZ2t2i7FTs2NvHe@YWZ{bf#>;Q@pE?J7vLQn zY-*fFU-4<_({w8^57c)o{>8f|vb%KJaDItv^k``)xce%3Z*Y8-9y>R1zOp!>(3jV^ zMkLYD)vqirXzTK0_dFPcZXIa%1EC{Z`^vDfXCH_hh@iJ-zpDE3ewcr8Mq=2$^i>4| z@p%7L1={2AKC}w75ouO@diqR(YutA&Z(K&lzijduj{V6=3wGh=XZxA@O^s{aQ#+@`J(a5PZ5 z|LX5Q2Cwk>|1aDjj)y0> znn*V@fK{|6oMolKYukQXdoB%ju|1rU z+(bLsK*1#^Z?RSSN6y5Qq9PIW*f)FXP%XYq#3$ILa}ynLS=TY|?a$WgCA|2)1b51R zgIY_i*^ILOBR(y@;%U6M2P}7b`{>T^pI&PXpwVBa#LS?0KtV{FywvM$$mQjmBA4AyX;<0hMCFT(gU0;nTU?Jn7e3}PT@-mN)yBF=>jo8}YxZaT~ z5LQ2qn>?!`plZHN;hUQ|VlO<$N9@YNGJ2n(yN&52J@y2N__eC z)`j;C-JDCtelm6`daT`1Bxn0#Ft`=XaHgwT@|e7Ow08EpB#Hn2wB=%YeG~LB<*KW1 zQ&gEPrkzkFIh(elP9owl11rlKOo{L*0HYnTUiMw9PDUf#<&s2lq`2^sYRO0RTPqg! z2dej6^FUimEqToVCDoTyriSov)J zg&oe#p|-1-e>yf9)QVGHKsS9p@JnQ@vTrPZ6X?w`qnE^;8<6`rWF~A6XF`x)16T6; z=N6l;$t^sH@qoKz)!r6*u&%wX{POBQy ztb8e46`MMAcBPeCTT(4fYqQ5ZyMgVe*7sdq49Pio0^kCz4g==QUCxpC<^4r=`lp>+ zYJ|qy+TIxtN2wUZBLM{mydhp@x>qdWl4-q^Cq0fBnTZUCbDDFC2lY zy%mB{GUIB(i9+M)qObX+KQ~(5l9@GOuF4M zm^S^!m5rN5=1w`<=0haYtiv9egVoDyA#rcc5@vnz0oo;sQK;FgJLLWg+$z)r5gbo1 zM4;{CUnmsUa|?#Bo_>Wav*-1ia?-gpzNC`EtlWvM5)ZTQj5{r$>h}W!2~t@C93K-( zUxp*tX4>M?W?ln+b4?9P&If>iut=1`6`r8>1K zJg3%|{4l{E?}SOcyI{V%^ZG-UHt3gBjsE>iX*NInfQc^Zt-e9*-cm2G#i6pN-)Q7> zbHaLT4j&>V7uyE9z7*ljEg?05TmnBb6Ayu%wIKu_>;oZnCmkVF8Bp#`nf{%a2!-74 zbg=8M`!rVsY0de&fIu>Ogz^kjtcK6_Nq7Eesu4~?N^+2zh-}V3nlt?vHwW*6<@rgI z_j2CcH6{*kcWUi^Vd5*gj~daa9b=;+_PPd>V1?%JyU?n?=bkle_$&s6lPJooPRg!y zqLIV2hb5FgO|sv3{s9N%6Y#b+qiP|AQgd?YzZ*YOwe5eUWppa#E|=~F7mWlVu(F{J zGy1IY<@oYcs$y7IaoKF1N)I=%3%b!}jBTAr6~U5OnhY(?Z?!kQTl}3#?@u}QXOH`` z9&f2nHQ3u*dOli}EyI5^G{-%p5!idQH3M`FT@1^G8S7}_6KNHGmzf&`4Jw(*0 zQ5lz^S4vUP^>!Y zg|~TxTavkg{olrU6|j58I^E|>FzIqv`HauGnlWrz)`cIK{t?{7343gNKU#oc2b)mP zN9uL;7m(S*3Ms2!El)(8k3kd;B)Z&;@!r`-4V*n?7yzWsP(}^AhS@Lk;imb2^|#a8 z50)@*jq*3lhR2)kAIe*4r7c_9YbQAiDxj%!1HQG zjtbN2PXOwFkR-}F@?EQbt-O#bs;#y4WA5D4;W=LO(KLsHg!$e*9*8b8 zuNjx}F(uF7vt5j@Ia3gcsqndBGnKs@ zqa@HqE`s!OB=D_~mgp$R5BHMdT>i*tO~Amwj>!P$SCTlBJ3imve==QnDA;58Q<-p3 z8q1$ys&avdl>aVQc-zp-{r_OEre(z)1tRoBw2_CQF3iNy$+gM7n ztin#PCyw$3Has1x&tLtM*9}a~=t(fX*dC78zJIYdWdE~JNwlhA((a9{!m~SpFL?=6 zmge4J&DT>iU{*gU@`V?t&)Em%&_=E-4c#EcO^l@NIcP0vQibP4wFS*AoYfyATW%n1 z7zvinZ>@Qk9{gd{HX_;%O*vqH+x3dtpLvuLGlm>W04v)!Ime6sJGi3|m|=7ViAO zhIA)H6Mirn$5T7;WSThEUs8X92 z%3eC?9(Z=q5(|hL5aNihFymt-aL&n2%?OZ|XvV4c(OipIRC1B|NkJrM_OI3rY`dtr zx)z$tHZOWDTgqpm*(ODJo0}v(m$t*{z#jZAk#zM`Eld=wx2F}ISoU(v56NvqpgH^* zTp9T>hWok4eu$S0M@o1(^T3|jC!Plj&u1TvI!h?@``{JB~l>G}Z$rhVv0!IxrDuxtE)1oy(1v zD$TUKTnMa9yu|P@_)}xqOfcz;f%9L`rCyj zylMz5JN@y@ADacMe}7XUqXt&-U;XxWWMW@WZM)2SK6>9VQrhNJ z`ZOcpaom=?AF{_*FmCK*niTyo2%)X_IVwQGUvEmm%<<3oORWiDg`W; zg_ZiW1t%Bp2T8v3xg1cC-Sr=IcH_@z!Dquoi9?2J-Uur`hO4O3&1|sy4J~km^SreA z;J#`LDC)tdd}8;-kymF1!mqwMFe3Qe_J4Rvdgk9*t8S$nkRm%2Q!3=9!>b*U6?n|T z8P7DuAhrP_3iK;VmXi8Ju)!K4Z(IV7yu`PdYBWxJ2|79=DaXQVKP)?6!s+hr!a+^E z31fdK2}=+t9$`eMK1SJpFLMbKYwtHr)Zp+UUVkJH6P7ZKKHWzX6!3J0I87of@iBN> zKb_U)y!LR5qhwQhz3N=%M2#DP=O0f99_M^@sk8%ZxQlz+QbBmALA~4kER6o}My>w@+^{?})Jr ztn7}LqQxwy#$dX{cEbXeiF3Gr3F>ILNa6?5sEYdz&+qcMile@^7{`;LX8MNBi4Jfa zzn){)BSYHMbTqRklGZmNvams?KD`~5L=(cZzRD)7s+eN*Zgh=Ik z@coX)*sV7H?Z77dJ$-ZWA1V%6at-aNk6*=F&EPRB>s5xfE{U6#s%(vWJEFi)pJeFN zle_8ua#QB?yvus@f_BTKgjH57U)xIYDlW|ohqTXLp6{6H$bDR&Y(etwzUMV3d+RB#cg#Gf+r>1yfh=9VTB>5(&F<)P)wC}Ch}+JkMk=+r;$EgMto5sou6kZ ztZhe*;m!;|pInc!2USfutru|6={+c3ZNk%%k97DELe|U=h8m@V)z0SDSt77fm*XTW zp)A~{oLTOadZ9k!4mrlEx1oqQ*V^QEciGN$^y`!6bpM`{i#Owtu)!F`X*4sk__Itx z;Ra^cU^_Z1ma{?0%juw)<=cGWc+qq=*SoIKx=3`Fxes8>tzX>e0s|DR0}-lXzwE7q zN4qT_Lv|6WBY7~7v`YCAB5D_oR@a)QK6gfbl1uXimP#lPYWDKU*X;7tS}@S7@@#(a z=FA6yeVO{YaQGMz8{WXNu7>2)n-aM!6)(nS;RW;@bGV)zyAidF&J#jwyhg6OvrwC= zmKLA^GCK7$k6}EBDZovJv)99b_s_JB5#|xB7Y*!OTsdlMjrP(nJS;AEC++!TKk?A1 z7(kPIr6KSxRJf}PiX7($-3~D!0e? zamZi&i>tp)IgM|8E3J~54rDeM8S^a$4`r<B>D~*T;Kf?CAzqB&P1&6ajJ$F1IHHt?gfi48U&Tr+p0$eLIP>wc zY3DP4RlD^qz8l*LQNrN4Zn>VOA+_hc74WzJC$(UT%vEVhfr0dgc<= z-51s4515d_4nT(6ca!s_(vH>{Leyo=j6bor4>gkOo~5=8klywfJ};Q_xT(l@cRzkx zc;agkvM)8E&N4tZ3~{shYu9Q`ert!5I8W_77`vhUwXd6+Oz3a-B&GQzx_%Mx?C=%> zMmDZ@ER&aCEfDA%Dq}UZg47MvC=3%rb?Xy5 z50d>3kX7sRd%ub$iJEUYKYwW9u7sg+HVm-m$o+RYJBEcv zytRcr*7PmP$38No#$!dSPP`1Du^dUg1tLUQWMmkLuit8wvA`BVL}UY zVJV0%HzPMWHFt5SrP7xA7s1*emI0;sAq(--flI26Y9jU2D%Pk&0r|tfT|F)$BWjxn-`;JCU6n!jDIOy$@|R%DMe% zGY%OzI1y>{SJwwIju(6$HUsO0d{$CDFrTPefGw?U3N4-v08=~;dn+iXlkWVv&_+-y zS_aB|veHVAkrhgG1KH8WAuLg~TznyeiArH!;`l_Uk;cb5s2|sS--+NA=ivO&O$0Dn zt2lS$pG1z+!n=*c`biNnqG`7I7)cgku?@XtKh%_l*Mmji(o}f-LuM>crkXPmF+5G6C8 zf5m&@+^7tSQ}>~Sq0aiMdrq)yxQ&qI0O?7==^6Clq6?R z=2$9Ic}Q448Z6o&E^ee4xFnS9ADNry2n9~v+rvX}wZf{y6%=E$7OZRqZ2?5wS5|$) zl`x%L-E4hrT$5&P@p)$f*Xf&|*+y5tx9S!;a3Js_nBes~ysC@>NV2k78f#OWv+z*T zu(PREkUK80D+oufg|(esptKBnp)*DotVM*&%uiCbXd0Uv|ESvm|6E}`)@&p8x)*Uw z&pO@rJO|7ASO_1csAQ(+je(8+2m0?boni0`n$3*%aiLVYx;8aOXg_+0(zEy#Q^T#_d7S~y@P?F zHXIX9;ylGBj?`fxlbQic9oxVEKgoM`zadkzq@?5`*c?b0$mmvs*SI~FP7*DYiRw3G zknZ5|ZAQ@Q8IV69^0+aRJ!g%z>`uRx0URnGlRKIKuz;>WG2HBH@VeEBh5m3E3$B@? zf-3`1TNR0-nM0VshC!fi?SNk`|-dPDCX!wMF0~lnlXT77FYk@Uz?FBKTQqO3z{S4=A62D^Xk>PuB`! zHx)5R_mu7B$E5RM;}rhJ<#drM0=gN zdK)1Sz*6`A#yf&DO9KJ$(Y{0p^j%QfInp*uTtadC#c=T9FgP3q-O^-ktwl;S7d8^y z!R_SQhaqdd&9{8U5raOkt}b>32PlFC>|9=XM%QbDt+9(`qT{|ubT4f_=$(T_gFG;; z8mOnTHoEa#QQiC0NqVL)AU19NG0Z8J=VCVV+gz_wga_SAKW7EXzj@wTW_`paX#Naa z71l?SHp6u})DdLRTx03~4n|@z?fTcHooumQN_f!b#x;jnNZ-%Xa z{52%3&x+!no$dsD0#+_PHG)K70(9=ro{V-Ze4)(EpiGELT~W1&sJ@r)9@URskhJEn zQ?{T;YeT!+vsntwzx`k?@Ua7RUPm0w*FoM+u`*h~{+&Q=L&YB&uD$GmB5T3x)_Js2eZ;AP5r1JB3?uY<7m zc+uaCXMO@~GKdQUuD5SrS@A-*aO2OLl-5O`6*pmNk3MF1qm_RgMh!)m4bB_znecGKRWt zv_zCVb{}6t*G{cYKi{2jGO#-N9>HtdwrH42J~4nq$4|jx(y3P^t1dkYUws?TqNX@X zAcTH=(zt9t$Zi|L4Q*(5Rc{(P-YMWloa5ba1Awb~?eZmR^hU0N$oRmJ;gQ&CGpHa6 zx@{e-V#YRzW}MINtFc&Vu9M{IJ>x6Z&O5MTAj-|aYXYPMVZcn@cgJHl$NM&L2pqKz zVF29?@#itIwENEk&Eb!nL-(FX70NpoP&@NO=6Nu7(nCQjF#b0^<uhy4!SXZj-^B{qrn2gTAPj?p6m=-NHpA`8mI?>c3ITUQD8S7ri4lbDyGEx=T=# z+p*VZI?Pq4uMXP=&voE=7l%pPC5q;hS-`4DXw-@%MTm%y*oea-7#hR?_a8T?x;n#9 zp>r(Cl_^Q$*DUjYOD%#4==Jj2M8jtPHRbnW-Z<&A{HcEav|j%_bz*amUV9YACj+&d zd+Uj9y34M;!*y>vXfA?Xgay1*gp}`zeHq2m~$HC!!IrLp9flrsWerI}Pdu067mC9f(PKjFHs0+&aOW)p&w3h4jaQf=b zRf~>f5#Swp)CNCxkd|3zdTVtBd4O#2 zbuu{VU@iU`_9a5f^f4a8422HwsBfoz~!m*BIuQ1LbA6q zP2Ibhn$c+}7TIC~8>lqM6OjzR5Y}8P3oPeTb?1d*1111LeDc}{Vx&%z%@bcT-SVl^Ya8MVt?z8{Cir1xrVq z5B$Roj1RgUS{1YvL=5B|@1X|-9=sKlONfRTVhik{67Hh`Ff#U&dc6cGX63zP#L$z@ zdT&g`zQL?dh=32|c)QrN5_+L{`lxS85nY=}5q(S84;C>Z2S;U$f=&gDN6M9ZMXoxu zhJB3VAJyMJ?zugYpqH>x|1_wh!UY~CCS{&9QI`c#;iyShK%56=j2HbW!?`9DGB@w& zz6IUtcu}1P-h8}OgjGTBzIaZ$EzaU9Iwf_KP?g(e*hqXJ2XZ01mN`>YPQ#OuEPL$?JA z&*FqY+pFkJ1jC580*ejWO($gJd5o+A0Em`-2$;atHmiG*mW}3dJe}c|+A;F@*XgyO zVBWF$TcaqLFOT3S-4--_Ee>Q>Ml_G8Y$#?(Dk3|WAtoq4j+=j+kd7&cDdrVKAXx3M z=}k@|UAE!-T2m@Wkh(7yNG{6S!Rv4Jhp2E*HyM-hJ0vp^W%SLS)7*ug$mS?7pmdLq zTm}F-f^&fTKwW^KNx=9&19X(ZcVF&O8>|4(0Ih%@AY&g@=vysJmIlypPj?x3yMGR~ zwzt*}#e?ZV(#1WwerU<33gLNxAJJ`LfFYPRU;Eg=(%}2T2WW+~TR;W_QHO;>Iu11f z2D#Ke+DuPrxtxG9Qz=BF35X$P9#V}dOD*sVKCn>%yxjzJQ^4d^V}&T5lZl=wR|)0? zWE^Z7^p%3Pd<509jyNv?@-0|6RV-ks=_^!Rt|Qdf5IK@EW=+4<>mf3YgAsn`drswe z-AD0!yM>AQng-9~T+XW|e?rW;D^|l~$o9fuTa8aGAEHClyPj7=OyWl;!axTa7T}j{ zptipesGw22-PPjCGgVmkai(bL!vuM^Trn&$i`uhXqpu4Tmk@uC+#`FK5ID}~HqQ!W zm?MZUkvWTJz_{uGD+U<*1V|yvszLnURicI&UY{*`5cBV*-Hm_7&1m+M_=!PIXiaK| z`1OgP{BPe%55qu>u6Qs&SYdIum;hGi44FV&aZm)gI~*vj&jZ%GFd`^;enI~@943&G z3}k2(2x~o1ON-P^;?wC*yV>B1KnRd=2y75=^Sy34{&C!RC^rx05tkrIiVwlB$lCCH z)shF@OdvVN*dU_j2iD^sYgxd1aUq_1VR z_2;G8&gX5#RyB?%90=dfXpj##;C3qxqFwV_Y4#5MZ$Y9>eu7IMP68xF6o~Gwn@a*; z`EE2Lp$*l25SHp^U)v@&z6FGK4oJ4(U6%I@J#~z$Fd}4ja;?H`Y7gbtp`7flq)!KoDQoB`TeY3oSuRc0H^zpBFo#S6bffCeJKa6&SOvq@ z@>D>+^f)9`3!_Nv{#$1kDu^N&#NnJjy}8e`2ga4+Hzhvlv>JC;==K`6_<~?S3 zjv+@n(A0H;u$mAEm=SgNH1bUL8r#ODx#CE9`sH<@0D1?S6m4bDMgTq&gw)q3v~LOC z&=)VbdJBB>AzFep=X&iie*kYw^#T)F!C zD#jh(56WAVA?#Yw?SR#cLH}9~);5Kl5V zZn0%0r@bFgeHg(&5x>(D-$Eb^AsHy(=UlZVe zE~hZIAglc&sal(^<)*E#m<>(o!xg9?ZO5HZHp`f|tQ9S{N&fa;PkD>JF&Tp_H#d1I_O&y`KlFPIDNNu7VAp91Mk^%#9t$;LLrb^wdI=b}Op-tEK<>f!~;&mA}z ze{U{(&``ThXH}5${twCn`VC$^31h_ERFu_hCZVWS$9WmU7LYo|Th`;Q$!h}*)B0MN zed!iFp{aEfzYK?P_naT(nk;bGdScD?ovT#cNA`TeEk2{?E{gK6QgUkopCKl|%hO=(c8L<>@x31d)(9ivXwc^r*lysU zbZ?7aTK5%$@qSi_i{6V~!ia>D2Ra?J#+*0k)g#F?geCl*TuIDQ_69P~tE7~?N{N)t zBZyInNS6ctUW6_Ye2{@DPnBn_K4Z>lHF$Nehja6Q2zEb~*j3^v1zO9rAw0{rV;DZ5 z^3P6Vkg*PpZqhX?!PM`1dj87J03vtf^-yw{>yRYr4Zfp*?vK?e>3n5Jq0KPv4Z;3w zYlPIbN?A93Myv+)>Ah(E=A-1bM&ZhM0&~6a_jHP^LgG*cC8Vk;*R|U2v_<0qh36XM zY>bc5|87^H@XyXEZ2IRDXKGCR3n)Wj?AF6zlptg9HDjE|#cBzkF@8aX z4qtVXdQ8$JtcMsPo7OPJn>wOqwlTrRK0*#F^HNgJ(`L9w3{Cf@3yE>!SWySQ6_JNz zp}S*byB#*-2J5tqFxX=E6f5?Z{!8vuN%4wTS!gzgk(4x8SoN7)i4*-v8S&E6=AOs~ z-zGIHWsBQ$NH527-IdkzR1GP@NA#G#c^aBkC;;1O*%Z+Q4cnhP;}vEE_^@qm^xeM| z&L~(zW!L>~&LsW0U+~wsTE`%H*+=Nf5i4E!Mf~-A)*Fs{Q&5}+I*S@`+Wwt{Z)-lx z8ybGttH_G$E3`EPC;PTQ-6}8o+a}$~cM1v5AdOjuoVJ2+2lp+{R!O2hRXR`1Trj%g z{9q$wS3Tegfs|9O*IIxJu20$(Qr_227h;gy%7lG8NtTv6%@U&Id0y?wPs--ww)%y! zphEFM*GSO~<`81i9(dW>%{|R2s{`Sm+PmpcLi)fM{kA(4{r2S4p93}pec!OkJ`|(7 zkbpS!8+_tS{xx$s6RCk4bJlN&7hkxo^p@#rVu8Z;{9ADC1^jigjQ6} zJF?^zEWbr@gH!p7u=yUo9W$kqQD_Hj4AO&th@Rt1gCdIQrLpJW+aFd*zJH+m5r>vbi?cCQos+WycH+vJ%xuO0!6NKgj zslE%#+4ny<(gD0axCC&5cFwB6!X7a-3xvJA!WmoRM7kIkBb4gaA@Z{DW59%1FZ0oNghv9E8@cU-vL*M}Sby1+|uVPU%q8DuX?e#Yu zYfbtyTloQv{u9aZ$1xtk3S$Eqr}KStCWqTU_EqN9GH&t?{p~*%G&D!lF=S4MCPOEY z%9d6SY2CF9U6^f8EzUj2d25e@?0S4K8Z$X%PE#h$E9FU>T{=zDARDV82kP`_U3Vc@ zgD+E834z>wo?tiPU6Y5czVD8v9L&TIW)9g+^qB)ZHj*3EO?qj^OJ;$BT85&vPQ(xM z&t{ESH%06Ps69GL<~|*H(IZQ|hnirU9|!_B(*3s!+Tge44Mp(MAhWH?2bU}aCVYW$ zkKK!r5GLMkZm_rVTTy>=!U^6On~e{`3@R-!yMawJL#|0}>YYzf+Pj5b7#r&J9vj;G zg)!?2HI`cCDLN7OPgrfzeh=dTZYw_|y}xF{`U&^a@kk#qguh=|&Vkmi`+)GGax;=s z2h0Z4)KO%m#@Ukgf1mTxY6pfVpc+;6X5eTd!z#=W(IYNf&0wrz>ENu=*yab2u)yRj ziCX6J!Nhn((pf51lMFAE6)h2^LO;nA5o$VR2w~pL+r8UAK4RJTf4)Snh{!xs(C@L6 zhr)3a%(5;KrkPfH!4#`P!K|~-oV9;0=(5=~BG__&M%kxLjyvsW^wTs6tLMe+wMaS_ zHO|f`DQ(ODvD?hDvzYPve$+R8$Oc4ueZNpYj8OWIYe~!6z~QaI<>PA?cxTuYrw`x8 zQwjsxwdechqLMPFyG#Y(lO@=BjReRD@#3ty)|T5?lGzX1FBYe^{RMeV4{ zI3wZjUDYlq{W1>TU!F}<^v!-Dy)EtEee94~(y%UiT=#yA~&Jd|*?tH?V< z9cl57AN_1hC~KQx*nKyGWyhMQUJvh+zSNs+rfc_DcIwQzDI%*G2el8;OT(po1ZxKW z2$shIyNM31&p4$9DP<7WVf*~ zW*yAU@b!d}P+AeV{G8_7L4W;8sDjK3Tr_aseQs+40G^Cwcz#;kFK~4u%;DF+xBgU9 z2S|P^hA1vpWl&kL zPTM=l={|S%$K)-NuLnGrGzP5>mPOpAJ}2~hwpf%e`pj^VtzI`;!D^jExKJKbe{PZe zs%y4%vAV{mImKmWA?Dpy`a2NUT@nwS8g+(w7U|bi=1AMW0cDXs5Sa07eZn5#(>)9C zH7!g8ow*mN7yPs2XZ*ADj?>Zy;7iWE2S1iRCaIH{XuIO@o=+8AZ^{F{7FtByXJN!9 zxO+en+akE?Z~v61jEkhsR~R$J?>s*i!8v-;G83=ABs}msgV?zTM|ufOCJa9m-OiOe z!%SN8+&gRqAT`#&A+goL#kq6UQ`RWjrYU^T;I}ctcKAOjL+4(|kZo??a$LlU+Ue>g zwm?+%5xfP%HYq{_lqZ@=wKIbmTRP*XvmclYheEU-0wee!zeH>Jer%cvX9JM4(g(O- zkXEbTk5^}pru`T8sMc1`uD}x^O7dNP)P599ip;G835E1L`X9u;9eX@&Z9Ugdlre}7 ziMwCst!&)p?_IPf8{Y`%>#$EhY>INu-5yTe=T{`~05Y^E}`4oFlq-P(WAexcGA(w^*wtgz|Pe z`2QK`lENNj$rw-1u$Ut|xb!x)&Ue&I`WJ*~y$TqpRjv zllKM9ZWs0B_rYneou)M&S^Bi;-pZ7ug!;7iJ=TM{Hfy)|FRj_T)~%xRMMFzu#4!DO z=icv5y}p%D6UjXF>t>5%$0^0hgZHfoI(w~w7yr8r1N<^lhUXCF!PP7`t1;fL{&qSk zSKH1P+wG2io784N?NBt)+M`%{d)I_VS^iZziVY>_H>g)=U97rg>AmNHPU6dBA)oR% z2OAUFeySbRZSBW1kG#*&O?IK=6jwTY*YvA;kI{juzjOlIu2}xzs+s(=WpU$A%$z*c zHKj(byw7Hfls}KJ|BNm64|!c4T9{wl7{q+3#(K`SWnSO8F(-4)`GtnM>kAym4+-3@ zv1&f+DtFH!?ZEhDv|JC54GZbssnzx2`HX}12I#Xa+9W3fb#HXV`P*|htYk#kE1$la z+u-8%uuiGbK7e^7FWQ~z?cr5fZg0Rmi7s2_b(r_ya%Ji5y4M#kG;GhT56Inq`@L#r z{ps&V{(7()o#_(%B{Vqa?C=GTJNO+8hb3-Y{;saF$3Jx*UyHCC_BS@uYSx>%R(kOt z(kcQQj#MdasPP`7=TVT)Te-vWr}?XvROZvFSjxu(t^%Ih+3|Bsy-a`K}J&V<{PPMsbXO=>ChO>)lQO4Y~vz(Z5cx_h?Z#g2rWNiR2Vn14KJ!@K=Ax9g^NXYM((eCo{* zi>bOLmp5t9?6wSkl2Fx9(Bx|V>C>cjy=OI(G@a&FuYUa`i1(C{WcXY^A$`H(;TKK? zTK@g&-4rv6KeIU_;*2-Gcinakd^qNbS`$0srjxC)&pFqT9`@!hbDu`E2JJhMdTpa& zMU*7 zSM(Iky3wU(eKTo@d2bM}m5Z`F_FB`M??utatGDeRf8CF=U$r^gc;Y*s?AE_V`*^mk z8g(PF?!p(1viLvvOH$t%v`_48;<#rdPHs(h-u-&!>j&u@8l1i~#b?htw>m$SHzuGr zZ{(+P$4ev1&vaj#rFZDfXWchTG>X{C({k&o3%1-zc6@elk8}RVv>DG9^6o!;eEDI0 zE1RO7T3wrE7*l(&{A#9>V`rG*;_vQ$8hq+nr*qGlk#!v%;TdmO>@{ZDkw3;ya*Ue3 zKYNigy~BQLXWoiVA25c`T%8oJt@Qb6Ku?$U39Fjj0X^lvMQl3kpSZC1@h@}YKlapd z9(k&y?RvG9f5OU}uG6!)^_Y9TCa)m^tg>DYGFRl&#<9k>)XuC*y*^3*;-!0W2d~`t zP&d)rqFISiY;oxRZl%*vsn>qcdbP7~96kB${Mv1lOSdepaE`P*{`h3Y)V#FDC57YZ z20ER=^*Vt?tK4t5rS?2;;Wnu2Wd*7S@-&QY>jX~xZ1~}bwHCju%=;kAW#;ap5MKHF z*0g6w(@fklW4u1HoSv~b#ikps)-@jsSX}5$yONlNRxq;o62(oad+W zU7RcnQry1`%5Yj}ZyQ`YqiWXfr{GA&%FVo@Oy`TWY0YLaZGr6%?=<%`m8)~J6Gt-* zVs<2L;aA(Wet(BinQ(vIj-Q_u_zlZ1@>j{sv3xn~a`6jQXAOR4PiD7~URTWE7@scg z_gj63MP3;`(k3l5`{Hqb%a>0YTWBXeR`_P7oJ+b_e{$<;#AS2s*$b{YpQdI;PTy}) zWc`MxS9q@11BU8X5+>R`ma`;Ui6{kXMbB$TV8N2ICJ%8?`JzJ$}9c4 z3&*_L-);Qp$T7d_HV22`rIzibhHALX4qrSAA_ zg<+|7oa6P4FF&Z8JdeBOyWH-wS8?#k%X+4~?AcGNZ_&aR{e5N9YGrED?Zdlt3x5sU z7c)KN;Dx||wl4~3`DUu2@P*D0dT4~)7dl%uQ!~&_Ra9-^i=)e#-0-*%@oj%^l==>5 z$&o5*w*s1wPSvo)-yRL6$1=F$+xmG$72OGbM+@4RLEOcP=E!}q746BOZbL_BP_?au zZG|)9W22+wwl*h&x_PD=c$bz!@mhI*k>D@FKUBdht898Kmq}-Fh?jGhYpq!p2h3yz zq?Jmc2>!rc?M08yLiFvR8BHpqXx@b*_ItIvB^QeUA1+Q+V8 zaQop5de{KqDr^yBw95n0Rxm_UJP;k!$`esBl*OQg=YV)BXnKrV;eHD=x(>WjJe*>P zzI8%$WZs7=IU{$_EfWy~8z|~XIx|Xc%%>+JVd&o3h=v1nCl;U;Cp4DH=5pjBlubY$ zqDJTNmF-b+Sf#v_Ik zpxd$Z2xT$E_w|$1C3)i!Uj@wz6jjGL$u06sQimZL*yH zME6WaN_e3lmy72d30(_X`U70LlDT9R$>7q(v^RsK#x9A(j?3^?Q?whZ)Rmokwef#S zhUaJ-9m01w@Gq?~XPz_t>y1X?gOgT=4|ka@E+5?)ykO2VPu1%DvdL<{h3P+KXYMdw zptanrFl^?}A$#Yw*_=Xi9d6sM-&J&9X++`NQif;A=uVS%wI0``%9^&r&vkDo9^kDn zob)n1;_-{~JI#Hj*rA%($Qlmlt5C4Pk)Bw&$Q$HmJQ#S!Kt7P*CNkwK88!*=Qy8Z2 ze^GD5#j|T(tKPplv`XGR9vyc(8gQr;| z>IyssMI$O+U*ZxZ>zh7^2>TgIc|9Hbe;hL;E-H-00M$;3LMj2{_4esRd}^ zKN#FhAskPD$D*%_j^kog6yRc?IFLv*9GB?nEu(tVwL!24z@;z51%IXFr(_CoNwD^| z_IN)4bgUmBbTzC>afmL@kOcP*po*gwu?%A@qsOs?#h@=Ffhc|6&>#s>3fdR9 zuq=9h6n8)>tOAM0P|Z|$HjhFX{~eZmB6Tqps0aj#PML}r_z0v`K1~XqV2VqNfwEUB zyv>+PpiXsEBmC+0aq9lqdH(vr!(r^T|h*aJ|fOche3_*DVWFsCBlC&(JOg8 zNJZ=-r{n%dlAr?@)!*q9|LqhC1-r?e06&Ugd1CP?NW&KV9lOYCtI+#`o7+Uk$^}Q4Zldb) zj7Us3N&&NpWw7X6W;`>IAs3U#kNs?myHY3GLtCvVeytoz4oodGqyVZ3)+-P~1TEA*)g^i5V6h%3;uBL&L2j!IlKH zB1mk5EjiM8<86dRCCt03dDpN4{L?ZT+lGNzmj~p*M-6{9Bnw8I!{jo=*kxT^(y?*H zG5!Ea{4<=SN$xfY=y*m{Sad8l*5^{Fa%f9RV?j!ow=gunOvezfOZ{TvbS3N35E9*z z-ypgxu?;T1roqMSm4FmzE3Y0&=PClm)9q;?nQJ^xEbV|6 zqxuZ1pI-S+$)%>YYia;;DtBtZ}Uu9z$^A}ijjnqRvEhy^JM zhn$dTeu|Td1UM-1JmDwE*Lo_}gRv9Q!sIw385bngSI)w;7aW zSknBItQit$gtaE0sLgE0c{yg&9A1F#SqC-@BBJ=nh?pq>EimACLI)0@V-B1&rc^@W z?Q=OVH-WILz(t;%esPyThip1o%!3HjCi5KH$9BlHi1!Ckq@k%>W9Mw|;&e zl31|ECkst_mCzkwqYStGOa;Cl0Pc6Kg}Hu`Tgp{^fdCF{2g;|4EwErKki2Pa zC%0fDv?yVVP*xLYy9c66BhL{*UQqPt2v5WiUuR3~rp03b$}HG9BrnuH%z;7Mosi*1 zvR9Yr)`^Jj90O8~HJuBAi0xRyXOtP~*4dzYMv?Gpq~i5;A7$YZnSV8)=a=mu>oI4> zgw#&wJRxrcTc)Dc_J|(70qj>&fjJ3Y9u=o0R-~G~lNP=-*AfuMTuV81AnEtafEj?S zEhx3*-g5I1w8X?6AhFUUhjU<}z&58S8oZL-^@XBA>F%P9XTO>dO8;l*`o9Z+(qjM; zId?O^he2yS5a9wx4ydF>N}k%Y=0l)jF$8HsIHy1kDXyunx4?8GsKdUc$a2B;;QS!1 zl_+{Vb2(VfM@LyPRqu|j`YzWPF^(_CzIlI1t?gPKFf%@%D@F$+{q-oPd(d4Reu zgg{A3_2GqW45P0 zm`br9T+sFag3&j6ol2xoj|U-?W#CClUx&h8{HP2wknunzElyEiU_|p%-UcD)jj4z( z>N^!tau*2qmF}i!K;wAhjv%OsE21y(H09vo-74v6nu=q^_-S?v_zmN`m1xZVM|LJT z-YjP&EZ$+Lu?wPt&lLT}D{wOPH1R&g!!zEfBo0qiPI!d;uzM+*zHmI%Dx3}$o?JG- zxFoZ2rYU1=Oymhe2o0N+G?LJ^0m|Y;P#$n(uun-&1a}nYHee{&og|C&=&693sT?RG zO4ySmr<1MYAS}vJ1BQZ)NU~rhi2^7=CaK~Dtp7~Hdb`h)Z*l?qR6K|xvVde4Fg#GK z$cmjutiX%5vv~D!Eg|6kvEw+DR1=FKNC}^jC-Z>_Min+1MV<`KbjeAAsWg94`kYCK zu<3%&U397&qDHE|e?h4K++ZYY8gzd%7bgn9_!Ys^HnU?ceL zCoqz4DZ%BRJBEn324HjOMSv;8DC7yB@Zp6`(hVc;)2U@R)W6~n3QaMdaAG}Ok7Iv} zEjXAIcttCYNVtL0%s^|I@sl@?O3w%JOLa!#b>S;LKq`q_CAM<=O6yPP{Hak$DML{Z zAbo@5r$%D-P+5Qnizd0~vK2oT#*+rC1hCOZ_DDq9CsU4oR)ejH+e<{FWdu(w7o`o`Hp$bKxfKBR!BMpo*T2;tj|G*!~zE6q`XkIhMB zxjMP?uv2rSQt%nR``b)2(Nh4t4&*$OW zhMV`&d4neXG(9#lb+eb+`iU(&@#$f?jlL5uu z_hcRnW&68|;G7;F@>iNvqT^_IZ@3pogggLm3Zx)zO`%nehz6-j6~J)+iW5bC)bX?s lq8kzmj>d+f2WBCv*8Q(Pl$5bCvl{%T2A=0nJEj8u^?&|2W|jZ| delta 177536 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