Repository: evcc-io/evcc
Pull request #8879 (2023-07-09 09:44:32)

Plugins: trace xml transformations
Fix https://github.com/evcc-io/evcc/issues/8834

/cc @VolkerK62 


Patch:
diff --git a/.prettierrc.js b/.prettierrc.js
index 5f9a0815..ff9f57ba 100644
--- a/.prettierrc.js
+++ b/.prettierrc.js
@@ -1,3 +1,4 @@
 module.exports = {
   printWidth: 100,
+  trailingComma: "es5"
 };
diff --git a/README.md b/README.md
index 9b188a5e..1aca7472 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,7 @@ To build evcc from source, [Go][1] 1.20 and [Node][2] 18 are required.
 Build and run go backend. The UI becomes available at http://127.0.0.1:7070/
 
 ```sh
+make install-ui
 make ui
 make install
 make
diff --git a/assets/index.html b/assets/index.html
index d36eb099..e65606ca 100644
--- a/assets/index.html
+++ b/assets/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
     <meta charset="utf-8" />
diff --git a/assets/js/components/BatterySettingsModal.vue b/assets/js/components/BatterySettingsModal.vue
index aff148ae..c094ef91 100644
--- a/assets/js/components/BatterySettingsModal.vue
+++ b/assets/js/components/BatterySettingsModal.vue
@@ -364,7 +364,6 @@ export default {
 		bufferStartOptionToSoc(option) {
 			const bufferSoc = this.selectedBufferSoc;
 			const bufferHeight = 100 - bufferSoc;
-			console.log("bufferStartOptionToSoc", { bufferSoc, bufferHeight, option });
 			switch (option) {
 				case "low":
 					return bufferSoc + bufferHeight * 0.2;
diff --git a/assets/js/components/Energyflow/Energyflow.vue b/assets/js/components/Energyflow/Energyflow.vue
index c0f2b67d..3164d0dc 100644
--- a/assets/js/components/Energyflow/Energyflow.vue
+++ b/assets/js/components/Energyflow/Energyflow.vue
@@ -23,20 +23,29 @@
 		<div class="details" :style="{ height: detailsHeight }">
 			<div ref="detailsInner" class="details-inner row">
 				<div class="col-12 d-flex justify-content-between pt-2 mb-4">
-					<div class="d-flex flex-nowrap align-items-center">
+					<div class="d-flex flex-nowrap align-items-center text-truncate">
 						<span class="color-self me-2"
 							><shopicon-filled-square></shopicon-filled-square
 						></span>
-						<span>{{ $t("main.energyflow.selfConsumption") }}</span>
+						<span class="text-nowrap text-truncate">
+							{{ $t("main.energyflow.selfConsumption") }}
+						</span>
 					</div>
-					<div v-if="gridImport > 0" class="d-flex flex-nowrap align-items-center">
-						<span>{{ $t("main.energyflow.gridImport") }}</span>
+					<div
+						v-if="gridImport > 0"
+						class="d-flex flex-nowrap align-items-center text-truncate"
+					>
+						<span class="text-nowrap text-truncate">
+							{{ $t("main.energyflow.gridImport") }}
+						</span>
 						<span class="color-grid ms-2"
 							><shopicon-filled-square></shopicon-filled-square
 						></span>
 					</div>
-					<div v-else class="d-flex flex-nowrap align-items-center">
-						<span>{{ $t("main.energyflow.pvExport") }}</span>
+					<div v-else class="d-flex flex-nowrap align-items-center text-truncate">
+						<span class="text-nowrap text-truncate">
+							{{ $t("main.energyflow.pvExport") }}
+						</span>
 						<span class="color-export ms-2"
 							><shopicon-filled-square></shopicon-filled-square
 						></span>
diff --git a/assets/js/components/Energyflow/EnergyflowEntry.vue b/assets/js/components/Energyflow/EnergyflowEntry.vue
index 6ec3e20c..50c41bf3 100644
--- a/assets/js/components/Energyflow/EnergyflowEntry.vue
+++ b/assets/js/components/Energyflow/EnergyflowEntry.vue
@@ -5,7 +5,7 @@
 			<VehicleIcon v-else-if="isVehicle" :names="vehicleIcons" />
 			<component :is="`shopicon-regular-${icon}`" v-else></component>
 		</span>
-		<span class="text-nowrap flex-grow-1 ms-3">
+		<span class="text-nowrap flex-grow-1 ms-3 text-truncate">
 			{{ name }}
 		</span>
 		<span class="text-end text-nowrap ps-1 fw-bold d-flex">
diff --git a/assets/js/mixins/formatter.js b/assets/js/mixins/formatter.js
index f7f55fcb..624a4e55 100644
--- a/assets/js/mixins/formatter.js
+++ b/assets/js/mixins/formatter.js
@@ -1,3 +1,19 @@
+// list of currencies where energy price should be displayed in subunits (factor 100)
+const ENERGY_PRICE_IN_SUBUNIT = {
+  AUD: "c", // Australian cent
+  BGN: "st", // Bulgarian stotinka
+  BRL: "¢", // Brazilian centavo
+  CAD: "¢", // Canadian cent
+  CHF: "rp", // Swiss Rappen
+  CNY: "f", // Chinese fen
+  EUR: "ct", // Euro cent
+  GBP: "p", // GB pence
+  ILS: "ag", // Israeli agora
+  NZD: "c", // New Zealand cent
+  PLN: "gr", // Polish grosz
+  USD: "¢", // US cent
+};
+
 export default {
   data: function () {
     return {
@@ -201,7 +217,7 @@ export default {
       let value = amout;
       let minimumFractionDigits = 1;
       let maximumFractionDigits = 3;
-      if (["EUR", "USD"].includes(currency)) {
+      if (ENERGY_PRICE_IN_SUBUNIT[currency]) {
         value *= 100;
         minimumFractionDigits = 1;
         maximumFractionDigits = 1;
@@ -217,10 +233,7 @@ export default {
       return price;
     },
     pricePerKWhUnit: function (currency = "EUR", short = false) {
-      let unit = currency;
-      if (["EUR", "USD"].includes(currency)) {
-        unit = "ct";
-      }
+      const unit = ENERGY_PRICE_IN_SUBUNIT[currency] || currency;
       return `${unit}${short ? "" : "/kWh"}`;
     },
     fmtTimeAgo: function (elapsed) {
diff --git a/charger/easee.go b/charger/easee.go
index 04eacb88..317e3aff 100644
--- a/charger/easee.go
+++ b/charger/easee.go
@@ -28,6 +28,7 @@ import (
 	"sync"
 	"time"
 
+	"github.com/cenkalti/backoff/v4"
 	"github.com/evcc-io/evcc/api"
 	"github.com/evcc-io/evcc/charger/easee"
 	"github.com/evcc-io/evcc/core/loadpoint"
@@ -202,7 +203,18 @@ func (c *Easee) chargerSite(charger string) (easee.Site, error) {
 
 // connect creates an HTTP connection to the signalR hub
 func (c *Easee) connect(ts oauth2.TokenSource) func() (signalr.Connection, error) {
-	return func() (signalr.Connection, error) {
+	bo := backoff.NewExponentialBackOff()
+	bo.MaxElapsedTime = time.Minute
+
+	return func() (conn signalr.Connection, err error) {
+		defer func() {
+			if err != nil {
+				time.Sleep(bo.NextBackOff())
+			} else {
+				bo.Reset()
+			}
+		}()
+
 		tok, err := ts.Token()
 		if err != nil {
 			return nil, err
@@ -399,7 +411,6 @@ func (c *Easee) Enable(enable bool) error {
 		targetCurrent = 32
 	}
 
-	c.log.DEBUG.Printf("send command: %s", action)
 	uri := fmt.Sprintf("%s/chargers/%s/commands/%s", easee.API, c.charger, action)
 	if err := c.postJSONAndWait(uri, nil); err != nil {
 		return err
@@ -409,13 +420,7 @@ func (c *Easee) Enable(enable bool) error {
 		return err
 	}
 
-	c.mux.Lock()
-	dynamicChargerCurrent := c.dynamicChargerCurrent
-	c.mux.Unlock()
-
-	c.log.DEBUG.Printf("DCC update received, current: %.3f, dynamicChargerCurrent: %.3f", c.current, dynamicChargerCurrent)
 	if enable {
-		c.log.DEBUG.Printf("send enable, reset current: %.3f", c.current)
 		// reset currents after enable, as easee automatically resets to maxA
 		return c.MaxCurrent(int64(c.current))
 	}
@@ -465,7 +470,6 @@ func (c *Easee) postJSONAndWait(uri string, data any) error {
 }
 
 func (c *Easee) waitForTickResponse(expectedTick int64) error {
-	c.log.TRACE.Printf("wait for tick response: %d", expectedTick)
 	for {
 		select {
 		case cmdResp := <-c.cmdC:
@@ -473,11 +477,9 @@ func (c *Easee) waitForTickResponse(expectedTick int64) error {
 				if !cmdResp.WasAccepted {
 					return fmt.Errorf("command rejected: %d", cmdResp.Ticks)
 				}
-				c.log.TRACE.Printf("received tick response: %d", cmdResp.Ticks)
 				return nil
 			}
 		case <-time.After(10 * time.Second):
-			c.log.TRACE.Printf("tick response timed out: %d", expectedTick)
 			return api.ErrTimeout
 		}
 	}
@@ -485,8 +487,6 @@ func (c *Easee) waitForTickResponse(expectedTick int64) error {
 
 // wait for up to 3s for current become targetCurrent
 func (c *Easee) waitForDynamicChargerCurrent(targetCurrent float64) error {
-	c.log.DEBUG.Printf("wait for DCC update: %.3f", targetCurrent)
-
 	// check any updates received meanwhile
 	c.mux.Lock()
 	if c.dynamicChargerCurrent == targetCurrent {
@@ -506,7 +506,6 @@ func (c *Easee) waitForDynamicChargerCurrent(targetCurrent float64) error {
 			if err != nil {
 				continue
 			}
-			c.log.TRACE.Printf("DCC update received: %.3f (want: %.3f)", value.(float64), targetCurrent)
 			if value.(float64) == targetCurrent {
 				return nil
 			}
@@ -670,8 +669,7 @@ func (c *Easee) updateSmartCharging() {
 
 		uri := fmt.Sprintf("%s/chargers/%s/settings", easee.API, c.charger)
 
-		err := c.postJSONAndWait(uri, data)
-		if err != nil {
+		if err := c.postJSONAndWait(uri, data); err != nil {
 			c.log.WARN.Printf("smart charging: %v", err)
 			return
 		}
diff --git a/charger/easee/identity.go b/charger/easee/identity.go
index f5002453..0c24b5e3 100644
--- a/charger/easee/identity.go
+++ b/charger/easee/identity.go
@@ -35,7 +35,6 @@ func (t *Token) AsOAuth2Token() *oauth2.Token {
 // tokenSource is an oauth2.TokenSource
 type tokenSource struct {
 	*request.Helper
-	oauth2.TokenSource
 }
 
 // TokenSource creates an Easee token source
@@ -54,38 +53,40 @@ func TokenSource(log *util.Logger, user, password string) (oauth2.TokenSource, e
 
 	uri := fmt.Sprintf("%s/%s", API, "accounts/login")
 	req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding)
+	if err != nil {
+		return nil, err
+	}
 
-	if err == nil {
-		var token Token
-		if err = c.DoJSON(req, &token); err == nil {
-			token := token.AsOAuth2Token()
-			ts := oauth.RefreshTokenSource(token, c)
-			c.TokenSource = oauth2.ReuseTokenSourceWithExpiry(token, ts, 15*time.Minute)
-		}
+	var token Token
+	if err := c.DoJSON(req, &token); err != nil {
+		return nil, err
 	}
 
-	return c, err
+	oauthToken := token.AsOAuth2Token()
+	ts := oauth2.ReuseTokenSourceWithExpiry(oauthToken, oauth.RefreshTokenSource(oauthToken, c), 15*time.Minute)
+
+	return ts, nil
 }
 
-func (c *tokenSource) RefreshToken(token *oauth2.Token) (*oauth2.Token, error) {
+func (c *tokenSource) RefreshToken(oauthToken *oauth2.Token) (*oauth2.Token, error) {
 	data := struct {
 		AccessToken  string `json:"accessToken"`
 		RefreshToken string `json:"refreshToken"`
 	}{
-		AccessToken:  token.AccessToken,
-		RefreshToken: token.RefreshToken,
+		AccessToken:  oauthToken.AccessToken,
+		RefreshToken: oauthToken.RefreshToken,
 	}
 
 	uri := fmt.Sprintf("%s/%s", API, "accounts/refresh_token")
 	req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding)
+	if err != nil {
+		return oauthToken, err
+	}
 
-	var res *oauth2.Token
-	if err == nil {
-		var refreshed Token
-		if err = c.DoJSON(req, &refreshed); err == nil {
-			res = refreshed.AsOAuth2Token()
-		}
+	var token Token
+	if err := c.DoJSON(req, &token); err != nil {
+		return oauthToken, err
 	}
 
-	return res, err
+	return token.AsOAuth2Token(), nil
 }
diff --git a/charger/keba-modbus.go b/charger/keba-modbus.go
index 36ef1b6d..1e4c4bbf 100644
--- a/charger/keba-modbus.go
+++ b/charger/keba-modbus.go
@@ -168,10 +168,10 @@ func (wb *Keba) Status() (api.ChargeStatus, error) {
 	}
 
 	switch status := binary.BigEndian.Uint32(b); status {
-	case 0, 3:
+	case 0, 1, 3:
 		return api.StatusA, nil
 
-	case 1, 5:
+	case 5:
 		return api.StatusB, nil
 
 	case 7:
diff --git "a/charger/weidm\303\274ller.go" "b/charger/weidm\303\274ller.go"
new file mode 100644
index 00000000..dd06d59e
--- /dev/null
+++ "b/charger/weidm\303\274ller.go"
@@ -0,0 +1,243 @@
+package charger
+
+// LICENSE
+
+// Copyright (c) 2023 premultiply
+
+// This module is NOT covered by the MIT license. All rights reserved.
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+import (
+	"encoding/binary"
+	"fmt"
+
+	"github.com/evcc-io/evcc/api"
+	"github.com/evcc-io/evcc/util"
+	"github.com/evcc-io/evcc/util/modbus"
+	"github.com/evcc-io/evcc/util/sponsor"
+)
+
+// Weidmüller charger implementation
+type Weidmüller struct {
+	log  *util.Logger
+	conn *modbus.Connection
+	curr uint16
+}
+
+const (
+	wmRegCarStatus    = 301  // GD_ID_EVCC_CAR_STATE CHAR
+	wmRegEvccStatus   = 302  // GD_ID_EVCC_EVSE_STATE UINT16
+	wmRegPhases       = 317  // GD_ID_EVCC_PHASES UINT16
+	wmRegVoltages     = 400  // GD_ID_CM_VOLTAGE_PHASE UINT32
+	wmRegCurrents     = 406  // GD_ID_CM_CURRENT_PHASE UINT32
+	wmRegActivePower  = 418  // GD_ID_CM_ACTIVE_POWER UINT32
+	wmRegTotalEnergy  = 457  // GD_ID_CM_CONSUMED_ENERGY_TOTAL_WH UINT64
+	wmRegCurrentLimit = 702  // GD_ID_AUT_USER_CURRENT_LIMIT UINT16
+	wmRegCardId       = 1000 // GD_ID_RFID_TAG_UID CHAR[21]
+)
+
+func init() {
+	registry.Add("weidmüller", NewWeidmüllerFromConfig)
+}
+
+// NewWeidmüllerFromConfig creates a Weidmüller charger from generic config
+func NewWeidmüllerFromConfig(other map[string]interface{}) (api.Charger, error) {
+	cc := modbus.TcpSettings{
+		ID: 255,
+	}
+
+	if err := util.DecodeOther(other, &cc); err != nil {
+		return nil, err
+	}
+
+	return NewWeidmüller(cc.URI, cc.ID)
+}
+
+// NewWeidmüller creates Weidmüller charger
+func NewWeidmüller(uri string, id uint8) (api.Charger, error) {
+	conn, err := modbus.NewConnection(uri, "", "", 0, modbus.Tcp, id)
+	if err != nil {
+		return nil, err
+	}
+
+	if !sponsor.IsAuthorized() {
+		return nil, api.ErrSponsorRequired
+	}
+
+	log := util.NewLogger("weidmüller")
+	conn.Logger(log.TRACE)
+
+	wb := &Weidmüller{
+		log:  log,
+		conn: conn,
+		curr: 6, // assume min current
+	}
+
+	// get initial state from charger
+	curr, err := wb.getCurrent()
+	if err != nil {
+		return nil, fmt.Errorf("current limit: %w", err)
+	}
+	if curr != 0 {
+		wb.curr = curr
+	}
+
+	return wb, err
+}
+
+func (wb *Weidmüller) setCurrent(current uint16) error {
+	b := make([]byte, 2)
+	binary.BigEndian.PutUint16(b, current)
+
+	_, err := wb.conn.WriteMultipleRegisters(wmRegCurrentLimit, 1, b)
+
+	return err
+}
+
+func (wb *Weidmüller) getCurrent() (uint16, error) {
+	b, err := wb.conn.ReadHoldingRegisters(wmRegCurrentLimit, 1)
+	if err != nil {
+		return 0, err
+	}
+
+	return binary.BigEndian.Uint16(b), nil
+}
+
+// getPhaseValues returns 3 sequential register values
+func (wb *Weidmüller) getPhaseValues(reg uint16) (float64, float64, float64, error) {
+	b, err := wb.conn.ReadHoldingRegisters(reg, 6)
+	if err != nil {
+		return 0, 0, 0, err
+	}
+
+	var res [3]float64
+	for i := 0; i < 3; i++ {
+		res[i] = float64(binary.BigEndian.Uint32(b[4*i:])) / 1e3
+	}
+
+	return res[0], res[1], res[2], nil
+}
+
+// Status implements the api.Charger interface
+func (wb *Weidmüller) Status() (api.ChargeStatus, error) {
+	b, err := wb.conn.ReadHoldingRegisters(wmRegCarStatus, 1)
+	if err != nil {
+		return api.StatusNone, err
+	}
+
+	switch s := string(b[0]); s {
+	case "A", "B", "C":
+		return api.ChargeStatus(s), nil
+	default:
+		return api.StatusNone, fmt.Errorf("invalid status: %s", s)
+	}
+}
+
+// Enabled implements the api.Charger interface
+func (wb *Weidmüller) Enabled() (bool, error) {
+	curr, err := wb.getCurrent()
+
+	return curr != 0, err
+}
+
+// Enable implements the api.Charger interface
+func (wb *Weidmüller) Enable(enable bool) error {
+	var current uint16
+	if enable {
+		current = wb.curr
+	}
+
+	return wb.setCurrent(current)
+}
+
+// MaxCurrent implements the api.Charger interface
+func (wb *Weidmüller) MaxCurrent(current int64) error {
+	if current < 6 {
+		return fmt.Errorf("invalid current %d", current)
+	}
+
+	wb.curr = uint16(current * 10)
+
+	return wb.setCurrent(wb.curr)
+}
+
+var _ api.Meter = (*Weidmüller)(nil)
+
+// CurrentPower implements the api.Meter interface
+func (wb *Weidmüller) CurrentPower() (float64, error) {
+	b, err := wb.conn.ReadHoldingRegisters(wmRegActivePower, 2)
+	if err != nil {
+		return 0, err
+	}
+
+	return float64(binary.BigEndian.Uint32(b)) / 1e3, err
+}
+
+var _ api.MeterEnergy = (*Weidmüller)(nil)
+
+// TotalEnergy implements the api.MeterEnergy interface
+func (wb *Weidmüller) TotalEnergy() (float64, error) {
+	b, err := wb.conn.ReadHoldingRegisters(wmRegTotalEnergy, 2)
+	if err != nil {
+		return 0, err
+	}
+
+	return float64(binary.BigEndian.Uint32(b)) / 1e3, err
+}
+
+var _ api.PhaseCurrents = (*Weidmüller)(nil)
+
+// Currents implements the api.PhaseCurrents interface
+func (wb *Weidmüller) Currents() (float64, float64, float64, error) {
+	return wb.getPhaseValues(wmRegCurrents)
+}
+
+var _ api.PhaseVoltages = (*Weidmüller)(nil)
+
+// Voltages implements the api.PhaseVoltages interface
+func (wb *Weidmüller) Voltages() (float64, float64, float64, error) {
+	return wb.getPhaseValues(wmRegVoltages)
+}
+
+var _ api.Identifier = (*Weidmüller)(nil)
+
+// Identify implements the api.Identifier interface
+func (wb *Weidmüller) Identify() (string, error) {
+	b, err := wb.conn.ReadHoldingRegisters(wmRegCardId, 11)
+	if err != nil {
+		return "", err
+	}
+	return bytesAsString(b), nil
+}
+
+var _ api.PhaseSwitcher = (*Weidmüller)(nil)
+
+// Phases1p3p implements the api.PhaseSwitcher interface
+func (wb *Weidmüller) Phases1p3p(phases int) error {
+	b := make([]byte, 2)
+
+	if phases == 3 {
+		binary.BigEndian.PutUint16(b, 1)
+	}
+
+	_, err := wb.conn.WriteMultipleRegisters(wmRegPhases, 1, b)
+
+	return err
+}
+
+var _ api.Diagnosis = (*Weidmüller)(nil)
+
+// Diagnose implements the api.Diagnosis interface
+func (wb *Weidmüller) Diagnose() {
+
+}
diff --git a/core/loadpoint.go b/core/loadpoint.go
index 145f8a3a..b9ee3080 100644
--- a/core/loadpoint.go
+++ b/core/loadpoint.go
@@ -315,7 +315,7 @@ func (lp *Loadpoint) collectDefaults() {
 		*actionCfg.MaxCurrent = lp.GetMaxCurrent()
 		*actionCfg.MinSoc = lp.GetMinSoc()
 		*actionCfg.TargetSoc = lp.GetTargetSoc()
-		*actionCfg.Priority = lp.Priority()
+		*actionCfg.Priority = lp.GetPriority()
 	} else {
 		lp.log.ERROR.Printf("error allocating action config: %v", err)
 	}
@@ -557,6 +557,9 @@ func (lp *Loadpoint) applyAction(actionCfg api.ActionConfig) {
 	if actionCfg.TargetSoc != nil {
 		lp.SetTargetSoc(*actionCfg.TargetSoc)
 	}
+	if actionCfg.Priority != nil {
+		lp.SetPriority(*actionCfg.Priority)
+	}
 }
 
 // Prepare loadpoint configuration by adding missing helper elements
@@ -603,6 +606,7 @@ func (lp *Loadpoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
 	}
 
 	lp.publish("mode", lp.GetMode())
+	lp.publish("priority", lp.GetPriority())
 	lp.publish(targetSoc, lp.GetTargetSoc())
 	lp.publish(minSoc, lp.GetMinSoc())
 
diff --git a/core/loadpoint/api.go b/core/loadpoint/api.go
index 1e2a33b9..226f505b 100644
--- a/core/loadpoint/api.go
+++ b/core/loadpoint/api.go
@@ -17,7 +17,6 @@ type Controller interface {
 type API interface {
 	// Title returns the defined loadpoint title
 	Title() string
-	Priority() int
 
 	//
 	// status
@@ -30,6 +29,11 @@ type API interface {
 	// settings
 	//
 
+	// GetPriority returns the loadpoint priority
+	GetPriority() int
+	// SetPriority sets the loadpoint priority
+	SetPriority(int)
+
 	// GetMode returns the charge mode
 	GetMode() api.ChargeMode
 	// SetMode sets the charge mode
diff --git a/core/loadpoint/mock.go b/core/loadpoint/mock.go
index 5bc56870..a2c2addb 100644
--- a/core/loadpoint/mock.go
+++ b/core/loadpoint/mock.go
@@ -205,6 +205,20 @@ func (mr *MockAPIMockRecorder) GetPlan(arg0, arg1 interface{}) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPlan", reflect.TypeOf((*MockAPI)(nil).GetPlan), arg0, arg1)
 }
 
+// GetPriority mocks base method.
+func (m *MockAPI) GetPriority() int {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetPriority")
+	ret0, _ := ret[0].(int)
+	return ret0
+}
+
+// GetPriority indicates an expected call of GetPriority.
+func (mr *MockAPIMockRecorder) GetPriority() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPriority", reflect.TypeOf((*MockAPI)(nil).GetPriority))
+}
+
 // GetRemainingDuration mocks base method.
 func (m *MockAPI) GetRemainingDuration() time.Duration {
 	m.ctrl.T.Helper()
@@ -317,20 +331,6 @@ func (mr *MockAPIMockRecorder) HasChargeMeter() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChargeMeter", reflect.TypeOf((*MockAPI)(nil).HasChargeMeter))
 }
 
-// Priority mocks base method.
-func (m *MockAPI) Priority() int {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Priority")
-	ret0, _ := ret[0].(int)
-	return ret0
-}
-
-// Priority indicates an expected call of Priority.
-func (mr *MockAPIMockRecorder) Priority() *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Priority", reflect.TypeOf((*MockAPI)(nil).Priority))
-}
-
 // RemoteControl mocks base method.
 func (m *MockAPI) RemoteControl(arg0 string, arg1 RemoteDemand) {
 	m.ctrl.T.Helper()
@@ -429,6 +429,18 @@ func (mr *MockAPIMockRecorder) SetPhases(arg0 interface{}) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPhases", reflect.TypeOf((*MockAPI)(nil).SetPhases), arg0)
 }
 
+// SetPriority mocks base method.
+func (m *MockAPI) SetPriority(arg0 int) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "SetPriority", arg0)
+}
+
+// SetPriority indicates an expected call of SetPriority.
+func (mr *MockAPIMockRecorder) SetPriority(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPriority", reflect.TypeOf((*MockAPI)(nil).SetPriority), arg0)
+}
+
 // SetTargetEnergy mocks base method.
 func (m *MockAPI) SetTargetEnergy(arg0 float64) {
 	m.ctrl.T.Helper()
diff --git a/core/loadpoint_api.go b/core/loadpoint_api.go
index d313b530..07552264 100644
--- a/core/loadpoint_api.go
+++ b/core/loadpoint_api.go
@@ -18,11 +18,6 @@ func (lp *Loadpoint) Title() string {
 	return lp.Title_
 }
 
-// Priority returns the loadpoint priority
-func (lp *Loadpoint) Priority() int {
-	return lp.Priority_
-}
-
 // GetStatus returns the charging status
 func (lp *Loadpoint) GetStatus() api.ChargeStatus {
 	lp.Lock()
@@ -102,6 +97,26 @@ func (lp *Loadpoint) SetTargetEnergy(energy float64) {
 	}
 }
 
+// GetPriority returns the loadpoint priority
+func (lp *Loadpoint) GetPriority() int {
+	lp.Lock()
+	defer lp.Unlock()
+	return lp.Priority_
+}
+
+// SetPriority sets the loadpoint priority
+func (lp *Loadpoint) SetPriority(prio int) {
+	lp.Lock()
+	defer lp.Unlock()
+
+	lp.log.DEBUG.Println("set priority:", prio)
+
+	if lp.Priority_ != prio {
+		lp.Priority_ = prio
+		lp.publish("priority", prio)
+	}
+}
+
 // GetTargetSoc returns loadpoint charge target soc
 func (lp *Loadpoint) GetTargetSoc() int {
 	lp.Lock()
diff --git a/core/prioritizer/prioritizer.go b/core/prioritizer/prioritizer.go
index 334dac20..346bcfe7 100644
--- a/core/prioritizer/prioritizer.go
+++ b/core/prioritizer/prioritizer.go
@@ -1,15 +1,20 @@
 package prioritizer
 
 import (
+	"fmt"
+
 	"github.com/evcc-io/evcc/core/loadpoint"
+	"github.com/evcc-io/evcc/util"
 )
 
 type Prioritizer struct {
+	log    *util.Logger
 	demand map[loadpoint.API]float64
 }
 
-func New() *Prioritizer {
+func New(log *util.Logger) *Prioritizer {
 	return &Prioritizer{
+		log:    log,
 		demand: make(map[loadpoint.API]float64),
 	}
 }
@@ -21,14 +26,23 @@ func (p *Prioritizer) UpdateChargePowerFlexibility(lp loadpoint.API) {
 }
 
 func (p *Prioritizer) GetChargePowerFlexibility(lp loadpoint.API) float64 {
-	prio := lp.Priority()
+	prio := lp.GetPriority()
+
+	var (
+		reduceBy float64
+		msg      string
+	)
 
-	var reduceBy float64
 	for lp, power := range p.demand {
-		if lp.Priority() < prio {
+		if lp.GetPriority() < prio {
 			reduceBy += power
+			msg += fmt.Sprintf("%.0fW from %s at prio %d, ", power, lp.Title(), lp.GetPriority())
 		}
 	}
 
+	if p.log != nil && reduceBy > 0 {
+		p.log.DEBUG.Printf("lp %s at prio %d gets additional %stotal %.0fW\n", lp.Title(), lp.GetPriority(), msg, reduceBy)
+	}
+
 	return reduceBy
 }
diff --git a/core/site.go b/core/site.go
index dd76a415..390d82b1 100644
--- a/core/site.go
+++ b/core/site.go
@@ -113,7 +113,7 @@ func NewSiteFromConfig(
 	site.loadpoints = loadpoints
 	site.tariffs = tariffs
 	site.coordinator = coordinator.New(log, vehicles)
-	site.prioritizer = prioritizer.New()
+	site.prioritizer = prioritizer.New(log)
 	site.savings = NewSavings(tariffs)
 
 	site.restoreSettings()
diff --git a/core/site_api.go b/core/site_api.go
index c906c9f7..f7d4ba7e 100644
--- a/core/site_api.go
+++ b/core/site_api.go
@@ -145,22 +145,18 @@ func (site *Site) GetTariff(tariff string) api.Tariff {
 		switch {
 		case site.tariffs.Planner != nil:
 			// prio 0: manually set planner tariff
-			site.log.DEBUG.Printf("planner tariff")
 			return site.tariffs.Planner
 
 		case site.tariffs.Grid != nil && site.tariffs.Grid.Type() == api.TariffTypePriceDynamic:
 			// prio 1: dynamic grid tariff
-			site.log.DEBUG.Printf("dynamic grid tariff")
 			return site.tariffs.Grid
 
 		case site.tariffs.Co2 != nil:
 			// prio 2: co2 tariff
-			site.log.DEBUG.Printf("co2 tariff")
 			return site.tariffs.Co2
 
 		default:
 			// prio 3: static grid tariff
-			site.log.DEBUG.Printf("static grid tariff")
 			return site.tariffs.Grid
 		}
 
diff --git a/go.mod b/go.mod
index 73c07246..7451e5dc 100644
--- a/go.mod
+++ b/go.mod
@@ -67,7 +67,7 @@ require (
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/mitchellh/mapstructure v1.5.0
 	github.com/mlnoga/rct v0.1.2-0.20230227143934-71af1fb7dfa1
-	github.com/muka/go-bluetooth v0.0.0-20220219050759-674a63b8741a
+	github.com/muka/go-bluetooth v0.0.0-20221213043340-85dc80edc4e1
 	github.com/mxschmitt/golang-combinations v1.1.0
 	github.com/nicksnyder/go-i18n/v2 v2.2.1
 	github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c
diff --git a/go.sum b/go.sum
index f46b067e..f6b28bcd 100644
--- a/go.sum
+++ b/go.sum
@@ -831,8 +831,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/muka/go-bluetooth v0.0.0-20220219050759-674a63b8741a h1:fnzS9RRQW8B5AgNCxkN0vJ/AoX+Xfqk3sAYon3iVrzA=
-github.com/muka/go-bluetooth v0.0.0-20220219050759-674a63b8741a/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
+github.com/muka/go-bluetooth v0.0.0-20221213043340-85dc80edc4e1 h1:BuVRHr4HHJbk1DHyWkArJ7E8J/VA8ncCr/VLnQFazBo=
+github.com/muka/go-bluetooth v0.0.0-20221213043340-85dc80edc4e1/go.mod h1:dMCjicU6vRBk34dqOmIZm0aod6gUwZXOXzBROqGous0=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
diff --git a/i18n/es.toml b/i18n/es.toml
index 585940aa..e3700a6f 100644
--- a/i18n/es.toml
+++ b/i18n/es.toml
@@ -111,12 +111,12 @@ modalTitle = "¿Necesitas ayuda?"
 primaryActions = "Si algo no funciona como debería, puedes obtener ayuda aqui."
 restartButton = "Reiniciar"
 restartDescription = "¿Has probado de apagar y volver a encender"
-secondaryActions = "¿Sigues sin poder resolver tu problema? Aquí tienes otras opciones más contundentes"
+secondaryActions = "¿Sigues sin poder resolver tu problema? Aquí tienes otras opciones más contundentes."
 
 [help.restart]
 cancel = "Cancelar"
 confirm = "¡Sí, reinicia!"
-description = "Bajo circunstancias normales no debería ser necesario reiniciar. Por favor, considera la posibilidad de reportar un error si necesitas reiniciar evcc regularmente."
+description = "En circunstancias normales no debería ser necesario reiniciar. Por favor, considera la posibilidad de presentar un error si necesita reiniciar evcc de forma regular."
 disclaimer = "Nota: evcc terminará y dependerá del sistema operativo para reiniciar el servicio"
 modalTitle = "¿Seguro que quieres volver a empezar?"
 
diff --git a/i18n/lt.toml b/i18n/lt.toml
index 8e5874f1..edd8a99a 100644
--- a/i18n/lt.toml
+++ b/i18n/lt.toml
@@ -116,7 +116,7 @@ secondaryActions = "Vis dar nepavyksta išspręsti problemos? Čia rasite drasti
 [help.restart]
 cancel = "Atšaukti"
 confirm = "Taip, restartuoti!"
-description = "Įprastai restartavimas neturėtų būti reikalingas. Jei jums reikia vis restartuoti, pasvarstykite - gal derėtų pranešti apie problemą."
+description = "Įprastai restartavimas neturėtų būti reikalingas. Jei jums vis reikia restartuoti, pasvarstykite, gal derėtų pranešti apie problemą."
 disclaimer = "Pastaba: evcc sustos, ir pasitikės operacinės sistemos pagalba paleidžiant iš naujo."
 modalTitle = "Ar tikrai norite restartuoti?"
 
diff --git a/i18n/no.toml b/i18n/no.toml
index 8d04049b..40d89166 100644
--- a/i18n/no.toml
+++ b/i18n/no.toml
@@ -299,6 +299,7 @@ price = "Σ-pris"
 reallyDelete = "Slett denne økten?"
 solar = "Solenergi"
 title = "Ladeøkter"
+total = "Totalt"
 vehicle = "Kjøretøy"
 
 [sessions.csv]
diff --git a/i18n/sv.toml b/i18n/sv.toml
index 0066e72d..a1f75cef 100644
--- a/i18n/sv.toml
+++ b/i18n/sv.toml
@@ -99,7 +99,7 @@ modalTitle = "Är du säker på att du vill starta om?"
 vehicles = "Parkering"
 
 [main.chargingPlan]
-activeLabel = "{tid}"
+activeLabel = "{time}"
 arrivalTab = "Ankomst"
 departureTab = "Avfärd"
 modalTitle = "Laddplan"
diff --git a/i18n/uk.toml b/i18n/uk.toml
index ecdaa6f7..fbc61baf 100644
--- a/i18n/uk.toml
+++ b/i18n/uk.toml
@@ -107,7 +107,7 @@ modalTitle = "Потрібна допомога?"
 primaryActions = "Щось не працює так, як повинно? Це хороші місця, де можна отримати допомогу."
 restartButton = "Перезапустити"
 restartDescription = "Спробували вимкнути і знову увімкнути?"
-secondaryActions = "Все ще не можете вирішити свою проблему? Ось кілька більш жорстких варіантів."
+secondaryActions = "Все ще не можете вирішити свою проблему? Ось кілька жорсткіших варіантів."
 
 [help.restart]
 cancel = "Скасувати"
@@ -289,7 +289,7 @@ avgPrice = "⌀ Ціна"
 co2 = "⌀ CO₂"
 csvMonth = "Завантажити {month} CSV"
 csvTotal = "Завантажити повний CSV"
-date = "Завершено"
+date = "Почати"
 downloadCsv = "Завантажити як CSV"
 energy = "Заряджено"
 loadpoint = "Точка зарядки"
@@ -298,6 +298,7 @@ price = "Σ Ціна"
 reallyDelete = "Ви дійсно хочете видалити цей сеанс?"
 solar = "Сонячна"
 title = "Сеанси зарядки"
+total = "Всього"
 vehicle = "Транспортний засіб"
 
 [sessions.csv]
@@ -314,7 +315,7 @@ vehicle = "Транспортний засіб"
 [sessions.filter]
 allLoadpoints = "всі точки зарядки"
 allVehicles = "всі транспортні засоби"
-filter = "фільтр"
+filter = "Фільтр"
 
 [settings]
 title = "Налаштування"
diff --git a/package-lock.json b/package-lock.json
index 50d9626b..852c27d2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,20 +24,20 @@
         "eslint-config-prettier": "^8.5.0",
         "eslint-plugin-import": "^2.25.3",
         "eslint-plugin-node": "^11.1.0",
-        "eslint-plugin-prettier": "^4.0.0",
+        "eslint-plugin-prettier": "^5.0.0-alpha.1",
         "eslint-plugin-promise": "^6.0.0",
         "eslint-plugin-vue": "^9.3.0",
-        "happy-dom": "^9.5.0",
+        "happy-dom": "^10.0.3",
         "histoire": "^0.16.1",
         "json-to-pretty-yaml": "^1.2.2",
         "markty-toml": "^0.1.1",
-        "prettier": "^2.5.1",
+        "prettier": "^3.0.0",
         "prettier-plugin-toml": "^0.3.1",
         "rollup-plugin-visualizer": "^5.8.3",
         "smoothscroll-polyfill": "^0.4.4",
         "vite": "^4.2.1",
         "vite-plugin-toml": "^0.5.0",
-        "vitest": "^0.32.2",
+        "vitest": "^0.33.0",
         "vue": "^3.2.29",
         "vue-eslint-parser": "^9.1.0",
         "vue-hot-reload-api": "^2.3.4",
@@ -51,6 +51,14 @@
         "npm": ">=8.0.0"
       }
     },
+    "node_modules/@aashutoshrathi/word-wrap": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
+      "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/@akryum/tinypool": {
       "version": "0.3.1",
       "resolved": "https://registry.npmjs.org/@akryum/tinypool/-/tinypool-0.3.1.tgz",
@@ -83,33 +91,33 @@
       }
     },
     "node_modules/@babel/compat-data": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz",
-      "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.6.tgz",
+      "integrity": "sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg==",
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/core": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz",
-      "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==",
+      "version": "7.22.8",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.8.tgz",
+      "integrity": "sha512-75+KxFB4CZqYRXjx4NlR4J7yGvKumBuZTmV4NV6v09dVXXkuYVYLT68N6HCzLvfJ+fWCxQsntNzKwwIXL4bHnw==",
       "dependencies": {
         "@ampproject/remapping": "^2.2.0",
         "@babel/code-frame": "^7.22.5",
-        "@babel/generator": "^7.22.5",
-        "@babel/helper-compilation-targets": "^7.22.5",
+        "@babel/generator": "^7.22.7",
+        "@babel/helper-compilation-targets": "^7.22.6",
         "@babel/helper-module-transforms": "^7.22.5",
-        "@babel/helpers": "^7.22.5",
-        "@babel/parser": "^7.22.5",
+        "@babel/helpers": "^7.22.6",
+        "@babel/parser": "^7.22.7",
         "@babel/template": "^7.22.5",
-        "@babel/traverse": "^7.22.5",
+        "@babel/traverse": "^7.22.8",
         "@babel/types": "^7.22.5",
+        "@nicolo-ribaudo/semver-v6": "^6.3.3",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
-        "json5": "^2.2.2",
-        "semver": "^6.3.0"
+        "json5": "^2.2.2"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -120,9 +128,9 @@
       }
     },
     "node_modules/@babel/generator": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
-      "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
+      "version": "7.22.7",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.7.tgz",
+      "integrity": "sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ==",
       "dependencies": {
         "@babel/types": "^7.22.5",
         "@jridgewell/gen-mapping": "^0.3.2",
@@ -156,15 +164,15 @@
       }
     },
     "node_modules/@babel/helper-compilation-targets": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz",
-      "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.6.tgz",
+      "integrity": "sha512-534sYEqWD9VfUm3IPn2SLcH4Q3P86XL+QvqdC7ZsFrzyyPF3T4XGiVghF6PTYNdWg6pXuoqXxNQAhbYeEInTzA==",
       "dependencies": {
-        "@babel/compat-data": "^7.22.5",
+        "@babel/compat-data": "^7.22.6",
         "@babel/helper-validator-option": "^7.22.5",
-        "browserslist": "^4.21.3",
-        "lru-cache": "^5.1.1",
-        "semver": "^6.3.0"
+        "@nicolo-ribaudo/semver-v6": "^6.3.3",
+        "browserslist": "^4.21.9",
+        "lru-cache": "^5.1.1"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -174,9 +182,9 @@
       }
     },
     "node_modules/@babel/helper-create-class-features-plugin": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.5.tgz",
-      "integrity": "sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.6.tgz",
+      "integrity": "sha512-iwdzgtSiBxF6ni6mzVnZCF3xt5qE6cEA0J7nFt8QOAWZ0zjCFceEgpn3vtb2V7WFR6QzP2jmIFOHMTRo7eNJjQ==",
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.22.5",
         "@babel/helper-environment-visitor": "^7.22.5",
@@ -185,8 +193,8 @@
         "@babel/helper-optimise-call-expression": "^7.22.5",
         "@babel/helper-replace-supers": "^7.22.5",
         "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
-        "@babel/helper-split-export-declaration": "^7.22.5",
-        "semver": "^6.3.0"
+        "@babel/helper-split-export-declaration": "^7.22.6",
+        "@nicolo-ribaudo/semver-v6": "^6.3.3"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -196,13 +204,13 @@
       }
     },
     "node_modules/@babel/helper-create-regexp-features-plugin": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.5.tgz",
-      "integrity": "sha512-1VpEFOIbMRaXyDeUwUfmTIxExLwQ+zkW+Bh5zXpApA3oQedBx9v/updixWxnx/bZpKw7u8VxWjb/qWpIcmPq8A==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.6.tgz",
+      "integrity": "sha512-nBookhLKxAWo/TUCmhnaEJyLz2dekjQvv5SRpE9epWQBcpedWLKt8aZdsuT9XV5ovzR3fENLjRXVT0GsSlGGhA==",
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.22.5",
-        "regexpu-core": "^5.3.1",
-        "semver": "^6.3.0"
+        "@nicolo-ribaudo/semver-v6": "^6.3.3",
+        "regexpu-core": "^5.3.1"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -212,16 +220,15 @@
       }
     },
     "node_modules/@babel/helper-define-polyfill-provider": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.0.tgz",
-      "integrity": "sha512-RnanLx5ETe6aybRi1cO/edaRH+bNYWaryCEmjDDYyNr4wnSzyOp8T0dWipmqVHKEY3AbVKUom50AKSlj1zmKbg==",
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz",
+      "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==",
       "dependencies": {
-        "@babel/helper-compilation-targets": "^7.17.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@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",
-        "semver": "^6.1.2"
+        "resolve": "^1.14.2"
       },
       "peerDependencies": {
         "@babel/core": "^7.4.0-0"
@@ -373,9 +380,9 @@
       }
     },
     "node_modules/@babel/helper-split-export-declaration": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz",
-      "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+      "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
       "dependencies": {
         "@babel/types": "^7.22.5"
       },
@@ -422,12 +429,12 @@
       }
     },
     "node_modules/@babel/helpers": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz",
-      "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz",
+      "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==",
       "dependencies": {
         "@babel/template": "^7.22.5",
-        "@babel/traverse": "^7.22.5",
+        "@babel/traverse": "^7.22.6",
         "@babel/types": "^7.22.5"
       },
       "engines": {
@@ -448,9 +455,9 @@
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
-      "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
+      "version": "7.22.7",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
+      "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
       "bin": {
         "parser": "bin/babel-parser.js"
       },
@@ -746,9 +753,9 @@
       }
     },
     "node_modules/@babel/plugin-transform-async-generator-functions": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.5.tgz",
-      "integrity": "sha512-gGOEvFzm3fWoyD5uZq7vVTD57pPJ3PczPUD/xCFGjzBpUosnklmXyKnGQbbbGs1NPNPskFex0j93yKbHt0cHyg==",
+      "version": "7.22.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz",
+      "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==",
       "dependencies": {
         "@babel/helper-environment-visitor": "^7.22.5",
         "@babel/helper-plugin-utils": "^7.22.5",
@@ -838,18 +845,18 @@
       }
     },
     "node_modules/@babel/plugin-transform-classes": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.5.tgz",
-      "integrity": "sha512-2edQhLfibpWpsVBx2n/GKOz6JdGQvLruZQfGr9l1qes2KQaWswjBzhQF7UDUZMNaMMQeYnQzxwOMPsbYF7wqPQ==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz",
+      "integrity": "sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==",
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.22.5",
-        "@babel/helper-compilation-targets": "^7.22.5",
+        "@babel/helper-compilation-targets": "^7.22.6",
         "@babel/helper-environment-visitor": "^7.22.5",
         "@babel/helper-function-name": "^7.22.5",
         "@babel/helper-optimise-call-expression": "^7.22.5",
         "@babel/helper-plugin-utils": "^7.22.5",
         "@babel/helper-replace-supers": "^7.22.5",
-        "@babel/helper-split-export-declaration": "^7.22.5",
+        "@babel/helper-split-export-declaration": "^7.22.6",
         "globals": "^11.1.0"
       },
       "engines": {
@@ -1221,9 +1228,9 @@
       }
     },
     "node_modules/@babel/plugin-transform-optional-chaining": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.5.tgz",
-      "integrity": "sha512-AconbMKOMkyG+xCng2JogMCDcqW8wedQAqpVIL4cOSescZ7+iW8utC6YDZLMCSUIReEA733gzRSaOSXMAt/4WQ==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz",
+      "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==",
       "dependencies": {
         "@babel/helper-plugin-utils": "^7.22.5",
         "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
@@ -1456,12 +1463,12 @@
       }
     },
     "node_modules/@babel/preset-env": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz",
-      "integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==",
+      "version": "7.22.7",
+      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.7.tgz",
+      "integrity": "sha512-1whfDtW+CzhETuzYXfcgZAh8/GFMeEbz0V5dVgya8YeJyCU6Y/P2Gnx4Qb3MylK68Zu9UiwUvbPMPTpFAOJ+sQ==",
       "dependencies": {
-        "@babel/compat-data": "^7.22.5",
-        "@babel/helper-compilation-targets": "^7.22.5",
+        "@babel/compat-data": "^7.22.6",
+        "@babel/helper-compilation-targets": "^7.22.6",
         "@babel/helper-plugin-utils": "^7.22.5",
         "@babel/helper-validator-option": "^7.22.5",
         "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5",
@@ -1486,13 +1493,13 @@
         "@babel/plugin-syntax-top-level-await": "^7.14.5",
         "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
         "@babel/plugin-transform-arrow-functions": "^7.22.5",
-        "@babel/plugin-transform-async-generator-functions": "^7.22.5",
+        "@babel/plugin-transform-async-generator-functions": "^7.22.7",
         "@babel/plugin-transform-async-to-generator": "^7.22.5",
         "@babel/plugin-transform-block-scoped-functions": "^7.22.5",
         "@babel/plugin-transform-block-scoping": "^7.22.5",
         "@babel/plugin-transform-class-properties": "^7.22.5",
         "@babel/plugin-transform-class-static-block": "^7.22.5",
-        "@babel/plugin-transform-classes": "^7.22.5",
+        "@babel/plugin-transform-classes": "^7.22.6",
         "@babel/plugin-transform-computed-properties": "^7.22.5",
         "@babel/plugin-transform-destructuring": "^7.22.5",
         "@babel/plugin-transform-dotall-regex": "^7.22.5",
@@ -1517,7 +1524,7 @@
         "@babel/plugin-transform-object-rest-spread": "^7.22.5",
         "@babel/plugin-transform-object-super": "^7.22.5",
         "@babel/plugin-transform-optional-catch-binding": "^7.22.5",
-        "@babel/plugin-transform-optional-chaining": "^7.22.5",
+        "@babel/plugin-transform-optional-chaining": "^7.22.6",
         "@babel/plugin-transform-parameters": "^7.22.5",
         "@babel/plugin-transform-private-methods": "^7.22.5",
         "@babel/plugin-transform-private-property-in-object": "^7.22.5",
@@ -1535,11 +1542,11 @@
         "@babel/plugin-transform-unicode-sets-regex": "^7.22.5",
         "@babel/preset-modules": "^0.1.5",
         "@babel/types": "^7.22.5",
-        "babel-plugin-polyfill-corejs2": "^0.4.3",
-        "babel-plugin-polyfill-corejs3": "^0.8.1",
-        "babel-plugin-polyfill-regenerator": "^0.5.0",
-        "core-js-compat": "^3.30.2",
-        "semver": "^6.3.0"
+        "@nicolo-ribaudo/semver-v6": "^6.3.3",
+        "babel-plugin-polyfill-corejs2": "^0.4.4",
+        "babel-plugin-polyfill-corejs3": "^0.8.2",
+        "babel-plugin-polyfill-regenerator": "^0.5.1",
+        "core-js-compat": "^3.31.0"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -1569,9 +1576,9 @@
       "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
     },
     "node_modules/@babel/runtime": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz",
-      "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==",
+      "version": "7.22.6",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz",
+      "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==",
       "dependencies": {
         "regenerator-runtime": "^0.13.11"
       },
@@ -1593,17 +1600,17 @@
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
-      "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
+      "version": "7.22.8",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
+      "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
       "dependencies": {
         "@babel/code-frame": "^7.22.5",
-        "@babel/generator": "^7.22.5",
+        "@babel/generator": "^7.22.7",
         "@babel/helper-environment-visitor": "^7.22.5",
         "@babel/helper-function-name": "^7.22.5",
         "@babel/helper-hoist-variables": "^7.22.5",
-        "@babel/helper-split-export-declaration": "^7.22.5",
-        "@babel/parser": "^7.22.5",
+        "@babel/helper-split-export-declaration": "^7.22.6",
+        "@babel/parser": "^7.22.7",
         "@babel/types": "^7.22.5",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
@@ -1659,9 +1666,9 @@
       }
     },
     "node_modules/@codemirror/lint": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.3.0.tgz",
-      "integrity": "sha512-tzxOVQNoDhhwFNfcTO2IB74wQoWarARcH6gv3YufPpiJ9yhcb7zD6JCkO5+FWARskqRFc8GFa6E+wUyOvADl5A==",
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.4.0.tgz",
+      "integrity": "sha512-6VZ44Ysh/Zn07xrGkdtNfmHCbGSHZzFBdzWi0pbd7chAQ/iUcpLGX99NYRZTa7Ugqg4kEHCqiHhcZnH0gLIgSg==",
       "dependencies": {
         "@codemirror/state": "^6.0.0",
         "@codemirror/view": "^6.0.0",
@@ -1685,9 +1692,9 @@
       }
     },
     "node_modules/@codemirror/view": {
-      "version": "6.14.0",
-      "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.14.0.tgz",
-      "integrity": "sha512-I263FPs4In42MNmrdwN2DfmYPFMVMXgT7o/mxdGp4jv5LPs8i0FOxzmxF5yeeQdYSTztb2ZhmPIu0ahveInVTg==",
+      "version": "6.14.1",
+      "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.14.1.tgz",
+      "integrity": "sha512-ofcsI7lRFo4N0rfnd+V3Gh2boQU3DmaaSKhDOvXUWjeOeuupMXer2e/3i9TUFN7aEIntv300EFBWPEiYVm2svg==",
       "dependencies": {
         "@codemirror/state": "^6.1.4",
         "style-mod": "^4.0.0",
@@ -1695,9 +1702,9 @@
       }
     },
     "node_modules/@esbuild/android-arm": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
-      "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.11.tgz",
+      "integrity": "sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==",
       "cpu": [
         "arm"
       ],
@@ -1710,9 +1717,9 @@
       }
     },
     "node_modules/@esbuild/android-arm64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
-      "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.11.tgz",
+      "integrity": "sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==",
       "cpu": [
         "arm64"
       ],
@@ -1725,9 +1732,9 @@
       }
     },
     "node_modules/@esbuild/android-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
-      "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.11.tgz",
+      "integrity": "sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==",
       "cpu": [
         "x64"
       ],
@@ -1740,9 +1747,9 @@
       }
     },
     "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
-      "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.11.tgz",
+      "integrity": "sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==",
       "cpu": [
         "arm64"
       ],
@@ -1755,9 +1762,9 @@
       }
     },
     "node_modules/@esbuild/darwin-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
-      "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.11.tgz",
+      "integrity": "sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==",
       "cpu": [
         "x64"
       ],
@@ -1770,9 +1777,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
-      "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.11.tgz",
+      "integrity": "sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==",
       "cpu": [
         "arm64"
       ],
@@ -1785,9 +1792,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
-      "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.11.tgz",
+      "integrity": "sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==",
       "cpu": [
         "x64"
       ],
@@ -1800,9 +1807,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
-      "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.11.tgz",
+      "integrity": "sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==",
       "cpu": [
         "arm"
       ],
@@ -1815,9 +1822,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
-      "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.11.tgz",
+      "integrity": "sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==",
       "cpu": [
         "arm64"
       ],
@@ -1830,9 +1837,9 @@
       }
     },
     "node_modules/@esbuild/linux-ia32": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
-      "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.11.tgz",
+      "integrity": "sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==",
       "cpu": [
         "ia32"
       ],
@@ -1845,9 +1852,9 @@
       }
     },
     "node_modules/@esbuild/linux-loong64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
-      "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.11.tgz",
+      "integrity": "sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==",
       "cpu": [
         "loong64"
       ],
@@ -1860,9 +1867,9 @@
       }
     },
     "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
-      "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.11.tgz",
+      "integrity": "sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==",
       "cpu": [
         "mips64el"
       ],
@@ -1875,9 +1882,9 @@
       }
     },
     "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
-      "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.11.tgz",
+      "integrity": "sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==",
       "cpu": [
         "ppc64"
       ],
@@ -1890,9 +1897,9 @@
       }
     },
     "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
-      "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.11.tgz",
+      "integrity": "sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==",
       "cpu": [
         "riscv64"
       ],
@@ -1905,9 +1912,9 @@
       }
     },
     "node_modules/@esbuild/linux-s390x": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
-      "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.11.tgz",
+      "integrity": "sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==",
       "cpu": [
         "s390x"
       ],
@@ -1920,9 +1927,9 @@
       }
     },
     "node_modules/@esbuild/linux-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
-      "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.11.tgz",
+      "integrity": "sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==",
       "cpu": [
         "x64"
       ],
@@ -1935,9 +1942,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
-      "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.11.tgz",
+      "integrity": "sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==",
       "cpu": [
         "x64"
       ],
@@ -1950,9 +1957,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
-      "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.11.tgz",
+      "integrity": "sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==",
       "cpu": [
         "x64"
       ],
@@ -1965,9 +1972,9 @@
       }
     },
     "node_modules/@esbuild/sunos-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
-      "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.11.tgz",
+      "integrity": "sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==",
       "cpu": [
         "x64"
       ],
@@ -1980,9 +1987,9 @@
       }
     },
     "node_modules/@esbuild/win32-arm64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
-      "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.11.tgz",
+      "integrity": "sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==",
       "cpu": [
         "arm64"
       ],
@@ -1995,9 +2002,9 @@
       }
     },
     "node_modules/@esbuild/win32-ia32": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
-      "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.11.tgz",
+      "integrity": "sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==",
       "cpu": [
         "ia32"
       ],
@@ -2010,9 +2017,9 @@
       }
     },
     "node_modules/@esbuild/win32-x64": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
-      "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.11.tgz",
+      "integrity": "sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==",
       "cpu": [
         "x64"
       ],
@@ -2047,13 +2054,13 @@
       }
     },
     "node_modules/@eslint/eslintrc": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
-      "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz",
+      "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==",
       "dependencies": {
         "ajv": "^6.12.4",
         "debug": "^4.3.2",
-        "espree": "^9.5.2",
+        "espree": "^9.6.0",
         "globals": "^13.19.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
@@ -2083,9 +2090,9 @@
       }
     },
     "node_modules/@eslint/js": {
-      "version": "8.43.0",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz",
-      "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==",
+      "version": "8.44.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz",
+      "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==",
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
@@ -2263,6 +2270,17 @@
         "node": ">= 14"
       }
     },
+    "node_modules/@jest/schemas": {
+      "version": "29.6.0",
+      "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz",
+      "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==",
+      "dependencies": {
+        "@sinclair/typebox": "^0.27.8"
+      },
+      "engines": {
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+      }
+    },
     "node_modules/@jridgewell/gen-mapping": {
       "version": "0.3.3",
       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
@@ -2293,9 +2311,9 @@
       }
     },
     "node_modules/@jridgewell/source-map": {
-      "version": "0.3.3",
-      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz",
-      "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==",
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
+      "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
       "peer": true,
       "dependencies": {
         "@jridgewell/gen-mapping": "^0.3.0",
@@ -2335,22 +2353,30 @@
       }
     },
     "node_modules/@lezer/json": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz",
-      "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.1.tgz",
+      "integrity": "sha512-nkVC27qiEZEjySbi6gQRuMwa2sDu2PtfjSgz0A4QF81QyRGm3kb2YRzLcOPcTEtmcwvrX/cej7mlhbwViA4WJw==",
       "dependencies": {
         "@lezer/highlight": "^1.0.0",
         "@lezer/lr": "^1.0.0"
       }
     },
     "node_modules/@lezer/lr": {
-      "version": "1.3.7",
-      "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.7.tgz",
-      "integrity": "sha512-ssHKb3p0MxhJXT2i7UBmgAY1BIM3Uq/D772Qutu3EVmxWIyNMU12nQ0rL3Fhu+MiFtiTzyTmd3xGwEf3ON5PSA==",
+      "version": "1.3.9",
+      "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.9.tgz",
+      "integrity": "sha512-XPz6dzuTHlnsbA5M2DZgjflNQ+9Hi5Swhic0RULdp3oOs3rh6bqGZolosVqN/fQIT8uNiepzINJDnS39oweTHQ==",
       "dependencies": {
         "@lezer/common": "^1.0.0"
       }
     },
+    "node_modules/@nicolo-ribaudo/semver-v6": {
+      "version": "6.3.3",
+      "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
+      "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -2383,6 +2409,53 @@
         "node": ">= 8"
       }
     },
+    "node_modules/@pkgr/utils": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz",
+      "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==",
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "fast-glob": "^3.3.0",
+        "is-glob": "^4.0.3",
+        "open": "^9.1.0",
+        "picocolors": "^1.0.0",
+        "tslib": "^2.6.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/unts"
+      }
+    },
+    "node_modules/@pkgr/utils/node_modules/define-lazy-prop": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+      "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@pkgr/utils/node_modules/open": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz",
+      "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==",
+      "dependencies": {
+        "default-browser": "^4.0.0",
+        "define-lazy-prop": "^3.0.0",
+        "is-inside-container": "^1.0.0",
+        "is-wsl": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/@playwright/test": {
       "version": "1.35.1",
       "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.35.1.tgz",
@@ -2445,6 +2518,11 @@
       "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
       "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ=="
     },
+    "node_modules/@sinclair/typebox": {
+      "version": "0.27.8",
+      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+      "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="
+    },
     "node_modules/@toml-tools/lexer": {
       "version": "0.3.1",
       "resolved": "https://registry.npmjs.org/@toml-tools/lexer/-/lexer-0.3.1.tgz",
@@ -2521,20 +2599,20 @@
       "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA=="
     },
     "node_modules/@types/node": {
-      "version": "20.3.2",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz",
-      "integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw=="
+      "version": "20.4.1",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.1.tgz",
+      "integrity": "sha512-JIzsAvJeA/5iY6Y/OxZbv1lUcc8dNSE77lb2gnBH+/PJ3lFR1Ccvgwl5JWnHAkNHcRsT0TbpVOsiMKZ1F/yyJg=="
     },
     "node_modules/@vitejs/plugin-legacy": {
-      "version": "4.0.5",
-      "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-4.0.5.tgz",
-      "integrity": "sha512-0N1CSAHjFTaxcKC9IcKDWMapmAfGn2mNdbROMf6UW0kypYLzDK8vAAbJIFW0jWvkv2aZfTgNs4KmQxoQDupUuQ==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-4.1.0.tgz",
+      "integrity": "sha512-bLPHaKAKtPq40Cx2Hauz/VE39kStx7gUC21RM+0/OvBgiOlqrK3b1mIMUc4Cak1xLOrK99j174/7xczfu4OLHA==",
       "dependencies": {
-        "@babel/core": "^7.22.5",
-        "@babel/preset-env": "^7.22.5",
+        "@babel/core": "^7.22.6",
+        "@babel/preset-env": "^7.22.6",
         "browserslist": "^4.21.9",
         "core-js": "^3.31.0",
-        "magic-string": "^0.30.0",
+        "magic-string": "^0.30.1",
         "regenerator-runtime": "^0.13.11",
         "systemjs": "^6.14.1"
       },
@@ -2562,12 +2640,12 @@
       }
     },
     "node_modules/@vitest/expect": {
-      "version": "0.32.2",
-      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz",
-      "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==",
+      "version": "0.33.0",
+      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.33.0.tgz",
+      "integrity": "sha512-sVNf+Gla3mhTCxNJx+wJLDPp/WcstOe0Ksqz4Vec51MmgMth/ia0MGFEkIZmVGeTL5HtjYR4Wl/ZxBxBXZJTzQ==",
       "dependencies": {
-        "@vitest/spy": "0.32.2",
-        "@vitest/utils": "0.32.2",
+        "@vitest/spy": "0.33.0",
+        "@vitest/utils": "0.33.0",
         "chai": "^4.3.7"
       },
       "funding": {
@@ -2575,14 +2653,13 @@
       }
     },
     "node_modules/@vitest/runner": {
-      "version": "0.32.2",
-      "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz",
-      "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==",
+      "version": "0.33.0",
+      "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.33.0.tgz",
+      "integrity": "sha512-UPfACnmCB6HKRHTlcgCoBh6ppl6fDn+J/xR8dTufWiKt/74Y9bHci5CKB8tESSV82zKYtkBJo9whU3mNvfaisg==",
       "dependencies": {
-        "@vitest/utils": "0.32.2",
-        "concordance": "^5.0.4",
+        "@vitest/utils": "0.33.0",
         "p-limit": "^4.0.0",
-        "pathe": "^1.1.0"
+        "pathe": "^1.1.1"
       },
       "funding": {
         "url": "https://opencollective.com/vitest"
@@ -2619,13 +2696,13 @@
       }
     },
     "node_modules/@vitest/snapshot": {
-      "version": "0.32.2",
-      "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.32.2.tgz",
-      "integrity": "sha512-JwhpeH/PPc7GJX38vEfCy9LtRzf9F4er7i4OsAJyV7sjPwjj+AIR8cUgpMTWK4S3TiamzopcTyLsZDMuldoi5A==",
+      "version": "0.33.0",
+      "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.33.0.tgz",
+      "integrity": "sha512-tJjrl//qAHbyHajpFvr8Wsk8DIOODEebTu7pgBrP07iOepR5jYkLFiqLq2Ltxv+r0uptUb4izv1J8XBOwKkVYA==",
       "dependencies": {
-        "magic-string": "^0.30.0",
-        "pathe": "^1.1.0",
-        "pretty-format": "^27.5.1"
+        "magic-string": "^0.30.1",
+        "pathe": "^1.1.1",
+        "pretty-format": "^29.5.0"
       },
       "funding": {
         "url": "https://opencollective.com/vitest"
@@ -2637,24 +2714,24 @@
       "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q=="
     },
     "node_modules/@vitest/spy": {
-      "version": "0.32.2",
-      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz",
-      "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==",
+      "version": "0.33.0",
+      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.33.0.tgz",
+      "integrity": "sha512-Kv+yZ4hnH1WdiAkPUQTpRxW8kGtH8VRTnus7ZTGovFYM1ZezJpvGtb9nPIjPnptHbsyIAxYZsEpVPYgtpjGnrg==",
       "dependencies": {
-        "tinyspy": "^2.1.0"
+        "tinyspy": "^2.1.1"
       },
       "funding": {
         "url": "https://opencollective.com/vitest"
       }
     },
     "node_modules/@vitest/utils": {
-      "version": "0.32.2",
-      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz",
-      "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==",
+      "version": "0.33.0",
+      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.33.0.tgz",
+      "integrity": "sha512-pF1w22ic965sv+EN6uoePkAOTkAPWM03Ri/jXNyMIKBb/XHLDPfhLvf/Fa9g0YECevAIz56oVYXhodLvLQ/awA==",
       "dependencies": {
         "diff-sequences": "^29.4.3",
         "loupe": "^2.3.6",
-        "pretty-format": "^27.5.1"
+        "pretty-format": "^29.5.0"
       },
       "funding": {
         "url": "https://opencollective.com/vitest"
@@ -2800,9 +2877,9 @@
       "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
     },
     "node_modules/acorn": {
-      "version": "8.9.0",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
-      "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==",
+      "version": "8.10.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+      "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
       "bin": {
         "acorn": "bin/acorn"
       },
@@ -2996,36 +3073,36 @@
       }
     },
     "node_modules/babel-plugin-polyfill-corejs2": {
-      "version": "0.4.3",
-      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.3.tgz",
-      "integrity": "sha512-bM3gHc337Dta490gg+/AseNB9L4YLHxq1nGKZZSHbhXv4aTYU2MD2cjza1Ru4S6975YLTaL1K8uJf6ukJhhmtw==",
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.4.tgz",
+      "integrity": "sha512-9WeK9snM1BfxB38goUEv2FLnA6ja07UMfazFHzCXUb3NyDZAwfXvQiURQ6guTTMeHcOsdknULm1PDhs4uWtKyA==",
       "dependencies": {
-        "@babel/compat-data": "^7.17.7",
-        "@babel/helper-define-polyfill-provider": "^0.4.0",
-        "semver": "^6.1.1"
+        "@babel/compat-data": "^7.22.6",
+        "@babel/helper-define-polyfill-provider": "^0.4.1",
+        "@nicolo-ribaudo/semver-v6": "^6.3.3"
       },
       "peerDependencies": {
         "@babel/core": "^7.0.0-0"
       }
     },
     "node_modules/babel-plugin-polyfill-corejs3": {
-      "version": "0.8.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.1.tgz",
-      "integrity": "sha512-ikFrZITKg1xH6pLND8zT14UPgjKHiGLqex7rGEZCH2EvhsneJaJPemmpQaIZV5AL03II+lXylw3UmddDK8RU5Q==",
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz",
+      "integrity": "sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ==",
       "dependencies": {
-        "@babel/helper-define-polyfill-provider": "^0.4.0",
-        "core-js-compat": "^3.30.1"
+        "@babel/helper-define-polyfill-provider": "^0.4.1",
+        "core-js-compat": "^3.31.0"
       },
       "peerDependencies": {
         "@babel/core": "^7.0.0-0"
       }
     },
     "node_modules/babel-plugin-polyfill-regenerator": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.0.tgz",
-      "integrity": "sha512-hDJtKjMLVa7Z+LwnTCxoDLQj6wdc+B8dun7ayF2fYieI6OzfuvcLMB32ihJZ4UhCBwNYGl5bg/x/P9cMdnkc2g==",
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.1.tgz",
+      "integrity": "sha512-L8OyySuI6OSQ5hFy9O+7zFjyr4WhAfRjLIOkhQGYl+emwJkd/S4XXT1JpfrgR1jrQ1NcGiOh+yAdGlF8pnC3Jw==",
       "dependencies": {
-        "@babel/helper-define-polyfill-provider": "^0.4.0"
+        "@babel/helper-define-polyfill-provider": "^0.4.1"
       },
       "peerDependencies": {
         "@babel/core": "^7.0.0-0"
@@ -3036,6 +3113,14 @@
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
       "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
     },
+    "node_modules/big-integer": {
+      "version": "1.6.51",
+      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
+      "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
     "node_modules/binary-extensions": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -3052,11 +3137,6 @@
         "url": "https://github.com/sponsors/antfu"
       }
     },
-    "node_modules/blueimp-md5": {
-      "version": "2.19.0",
-      "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz",
-      "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w=="
-    },
     "node_modules/boolbase": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -3080,6 +3160,17 @@
         "@popperjs/core": "^2.11.7"
       }
     },
+    "node_modules/bplist-parser": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
+      "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==",
+      "dependencies": {
+        "big-integer": "^1.6.44"
+      },
+      "engines": {
+        "node": ">= 5.10.0"
+      }
+    },
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -3136,6 +3227,20 @@
       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
       "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
     },
+    "node_modules/bundle-name": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
+      "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==",
+      "dependencies": {
+        "run-applescript": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/cac": {
       "version": "6.7.14",
       "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
@@ -3174,9 +3279,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001508",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001508.tgz",
-      "integrity": "sha512-sdQZOJdmt3GJs1UMNpCCCyeuS2IEGLXnHyAo9yIO5JJDjbjoVRij4M1qep6P6gFpptD1PqIYgzM+gwJbOi92mw==",
+      "version": "1.0.30001514",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001514.tgz",
+      "integrity": "sha512-ENcIpYBmwAAOm/V2cXgM7rZUrKKaqisZl4ZAI520FIkqGXUxJjmaIssbRW5HVVR5tyV6ygTLIm15aU8LUmQSaQ==",
       "funding": [
         {
           "type": "opencollective",
@@ -3349,54 +3454,6 @@
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
     },
-    "node_modules/concordance": {
-      "version": "5.0.4",
-      "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz",
-      "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==",
-      "dependencies": {
-        "date-time": "^3.1.0",
-        "esutils": "^2.0.3",
-        "fast-diff": "^1.2.0",
-        "js-string-escape": "^1.0.1",
-        "lodash": "^4.17.15",
-        "md5-hex": "^3.0.1",
-        "semver": "^7.3.2",
-        "well-known-symbols": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14"
-      }
-    },
-    "node_modules/concordance/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==",
-      "dependencies": {
-        "yallist": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/concordance/node_modules/semver": {
-      "version": "7.5.3",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
-      "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
-      "dependencies": {
-        "lru-cache": "^6.0.0"
-      },
-      "bin": {
-        "semver": "bin/semver.js"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/concordance/node_modules/yallist": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
-    },
     "node_modules/config-chain": {
       "version": "1.1.13",
       "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
@@ -3449,9 +3506,9 @@
       "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
     },
     "node_modules/core-js": {
-      "version": "3.31.0",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.0.tgz",
-      "integrity": "sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==",
+      "version": "3.31.1",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.1.tgz",
+      "integrity": "sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ==",
       "hasInstallScript": true,
       "funding": {
         "type": "opencollective",
@@ -3459,11 +3516,11 @@
       }
     },
     "node_modules/core-js-compat": {
-      "version": "3.31.0",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.0.tgz",
-      "integrity": "sha512-hM7YCu1cU6Opx7MXNu0NuumM0ezNeAeRKadixyiQELWY3vT3De9S4J5ZBMraWV2vZnrE1Cirl0GtFtDtMUXzPw==",
+      "version": "3.31.1",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.1.tgz",
+      "integrity": "sha512-wIDWd2s5/5aJSdpOJHfSibxNODxoGoWOBHt8JSPB41NOE94M7kuTPZCYLOlTtuoXTsBPKobpJ6T+y0SSy5L9SA==",
       "dependencies": {
-        "browserslist": "^4.21.5"
+        "browserslist": "^4.21.9"
       },
       "funding": {
         "type": "opencollective",
@@ -3471,9 +3528,9 @@
       }
     },
     "node_modules/countup.js": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.6.2.tgz",
-      "integrity": "sha512-PRvoilkebwr1MKaRAllyJl2cD7mgunGZWXLaSFL+YqHXlJpjLX7SHTWonRfIx2xg1Xf7SPbo92bOOonSIomRYQ=="
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.7.0.tgz",
+      "integrity": "sha512-IP9nYLGgW//0If73eXQdFlReGhpFGHaStqB1v82FknxnUWueF6HFuuOXySW4sEDMc88PsZL1EOn/NPkfTZalmQ=="
     },
     "node_modules/crelt": {
       "version": "1.0.6",
@@ -3548,17 +3605,6 @@
         "node": ">=12"
       }
     },
-    "node_modules/date-time": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz",
-      "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==",
-      "dependencies": {
-        "time-zone": "^1.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/debug": {
       "version": "4.3.4",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -3596,6 +3642,38 @@
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
     },
+    "node_modules/default-browser": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz",
+      "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==",
+      "dependencies": {
+        "bundle-name": "^3.0.0",
+        "default-browser-id": "^3.0.0",
+        "execa": "^7.1.1",
+        "titleize": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/default-browser-id": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz",
+      "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==",
+      "dependencies": {
+        "bplist-parser": "^0.2.0",
+        "untildify": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/define-lazy-prop": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
@@ -3711,9 +3789,9 @@
       }
     },
     "node_modules/editorconfig/node_modules/semver": {
-      "version": "5.7.1",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "version": "5.7.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+      "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
       "bin": {
         "semver": "bin/semver"
       }
@@ -3729,9 +3807,9 @@
       "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.442",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.442.tgz",
-      "integrity": "sha512-RkrZF//Ya+0aJq2NM3OdisNh5ZodZq1rdXOS96G8DdDgpDKqKE81yTbbQ3F/4CKm1JBPsGu1Lp/akkna2xO06Q=="
+      "version": "1.4.454",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.454.tgz",
+      "integrity": "sha512-pmf1rbAStw8UEQ0sr2cdJtWl48ZMuPD9Sto8HVQOq9vx9j2WgDEN6lYoaqFvqEHYOmGA9oRGn7LqWI9ta0YugQ=="
     },
     "node_modules/emoji-regex": {
       "version": "8.0.0",
@@ -3842,9 +3920,9 @@
       }
     },
     "node_modules/esbuild": {
-      "version": "0.17.19",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
-      "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
+      "version": "0.18.11",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.11.tgz",
+      "integrity": "sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==",
       "hasInstallScript": true,
       "bin": {
         "esbuild": "bin/esbuild"
@@ -3853,28 +3931,28 @@
         "node": ">=12"
       },
       "optionalDependencies": {
-        "@esbuild/android-arm": "0.17.19",
-        "@esbuild/android-arm64": "0.17.19",
-        "@esbuild/android-x64": "0.17.19",
-        "@esbuild/darwin-arm64": "0.17.19",
-        "@esbuild/darwin-x64": "0.17.19",
-        "@esbuild/freebsd-arm64": "0.17.19",
-        "@esbuild/freebsd-x64": "0.17.19",
-        "@esbuild/linux-arm": "0.17.19",
-        "@esbuild/linux-arm64": "0.17.19",
-        "@esbuild/linux-ia32": "0.17.19",
-        "@esbuild/linux-loong64": "0.17.19",
-        "@esbuild/linux-mips64el": "0.17.19",
-        "@esbuild/linux-ppc64": "0.17.19",
-        "@esbuild/linux-riscv64": "0.17.19",
-        "@esbuild/linux-s390x": "0.17.19",
-        "@esbuild/linux-x64": "0.17.19",
-        "@esbuild/netbsd-x64": "0.17.19",
-        "@esbuild/openbsd-x64": "0.17.19",
-        "@esbuild/sunos-x64": "0.17.19",
-        "@esbuild/win32-arm64": "0.17.19",
-        "@esbuild/win32-ia32": "0.17.19",
-        "@esbuild/win32-x64": "0.17.19"
+        "@esbuild/android-arm": "0.18.11",
+        "@esbuild/android-arm64": "0.18.11",
+        "@esbuild/android-x64": "0.18.11",
+        "@esbuild/darwin-arm64": "0.18.11",
+        "@esbuild/darwin-x64": "0.18.11",
+        "@esbuild/freebsd-arm64": "0.18.11",
+        "@esbuild/freebsd-x64": "0.18.11",
+        "@esbuild/linux-arm": "0.18.11",
+        "@esbuild/linux-arm64": "0.18.11",
+        "@esbuild/linux-ia32": "0.18.11",
+        "@esbuild/linux-loong64": "0.18.11",
+        "@esbuild/linux-mips64el": "0.18.11",
+        "@esbuild/linux-ppc64": "0.18.11",
+        "@esbuild/linux-riscv64": "0.18.11",
+        "@esbuild/linux-s390x": "0.18.11",
+        "@esbuild/linux-x64": "0.18.11",
+        "@esbuild/netbsd-x64": "0.18.11",
+        "@esbuild/openbsd-x64": "0.18.11",
+        "@esbuild/sunos-x64": "0.18.11",
+        "@esbuild/win32-arm64": "0.18.11",
+        "@esbuild/win32-ia32": "0.18.11",
+        "@esbuild/win32-x64": "0.18.11"
       }
     },
     "node_modules/escalade": {
@@ -3899,14 +3977,13 @@
       }
     },
     "node_modules/escodegen": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz",
-      "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+      "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
       "dependencies": {
         "esprima": "^4.0.1",
         "estraverse": "^5.2.0",
-        "esutils": "^2.0.2",
-        "optionator": "^0.8.1"
+        "esutils": "^2.0.2"
       },
       "bin": {
         "escodegen": "bin/escodegen.js",
@@ -3919,62 +3996,15 @@
         "source-map": "~0.6.1"
       }
     },
-    "node_modules/escodegen/node_modules/levn": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
-      "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
-      "dependencies": {
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2"
-      },
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/escodegen/node_modules/optionator": {
-      "version": "0.8.3",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
-      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
-      "dependencies": {
-        "deep-is": "~0.1.3",
-        "fast-levenshtein": "~2.0.6",
-        "levn": "~0.3.0",
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2",
-        "word-wrap": "~1.2.3"
-      },
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/escodegen/node_modules/prelude-ls": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-      "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
-    "node_modules/escodegen/node_modules/type-check": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
-      "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
-      "dependencies": {
-        "prelude-ls": "~1.1.2"
-      },
-      "engines": {
-        "node": ">= 0.8.0"
-      }
-    },
     "node_modules/eslint": {
-      "version": "8.43.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz",
-      "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==",
+      "version": "8.44.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz",
+      "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==",
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
         "@eslint-community/regexpp": "^4.4.0",
-        "@eslint/eslintrc": "^2.0.3",
-        "@eslint/js": "8.43.0",
+        "@eslint/eslintrc": "^2.1.0",
+        "@eslint/js": "8.44.0",
         "@humanwhocodes/config-array": "^0.11.10",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
@@ -3986,7 +4016,7 @@
         "escape-string-regexp": "^4.0.0",
         "eslint-scope": "^7.2.0",
         "eslint-visitor-keys": "^3.4.1",
-        "espree": "^9.5.2",
+        "espree": "^9.6.0",
         "esquery": "^1.4.2",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
@@ -4006,7 +4036,7 @@
         "lodash.merge": "^4.6.2",
         "minimatch": "^3.1.2",
         "natural-compare": "^1.4.0",
-        "optionator": "^0.9.1",
+        "optionator": "^0.9.3",
         "strip-ansi": "^6.0.1",
         "strip-json-comments": "^3.1.0",
         "text-table": "^0.2.0"
@@ -4159,20 +4189,28 @@
       }
     },
     "node_modules/eslint-plugin-prettier": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
-      "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
+      "version": "5.0.0-alpha.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0-alpha.2.tgz",
+      "integrity": "sha512-F6YBCbrRzvZwcINw3crm1+/uX/i+rJYaFErPtwCfUoPLywRfY7pwBtI3yMe5OpIotuaiws8cd29oM80ca6NQSQ==",
       "dependencies": {
-        "prettier-linter-helpers": "^1.0.0"
+        "prettier-linter-helpers": "^1.0.0",
+        "synckit": "^0.8.5"
       },
       "engines": {
-        "node": ">=12.0.0"
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/prettier"
       },
       "peerDependencies": {
-        "eslint": ">=7.28.0",
-        "prettier": ">=2.0.0"
+        "@types/eslint": ">=8.0.0",
+        "eslint": ">=8.0.0",
+        "prettier": ">=3.0.0"
       },
       "peerDependenciesMeta": {
+        "@types/eslint": {
+          "optional": true
+        },
         "eslint-config-prettier": {
           "optional": true
         }
@@ -4221,9 +4259,9 @@
       }
     },
     "node_modules/eslint-plugin-vue/node_modules/semver": {
-      "version": "7.5.3",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
-      "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
       "dependencies": {
         "lru-cache": "^6.0.0"
       },
@@ -4388,11 +4426,11 @@
       }
     },
     "node_modules/espree": {
-      "version": "9.5.2",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz",
-      "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==",
+      "version": "9.6.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz",
+      "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==",
       "dependencies": {
-        "acorn": "^8.8.0",
+        "acorn": "^8.9.0",
         "acorn-jsx": "^5.3.2",
         "eslint-visitor-keys": "^3.4.1"
       },
@@ -4458,6 +4496,28 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/execa": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz",
+      "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==",
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^6.0.1",
+        "human-signals": "^4.3.0",
+        "is-stream": "^3.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^5.1.0",
+        "onetime": "^6.0.0",
+        "signal-exit": "^3.0.7",
+        "strip-final-newline": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.18.0 || ^16.14.0 || >=18.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
     "node_modules/extend-shallow": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
@@ -4480,9 +4540,9 @@
       "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="
     },
     "node_modules/fast-glob": {
-      "version": "3.2.12",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
-      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
+      "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==",
       "dependencies": {
         "@nodelib/fs.stat": "^2.0.2",
         "@nodelib/fs.walk": "^1.2.3",
@@ -4740,6 +4800,17 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "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==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/get-symbol-description": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
@@ -4826,13 +4897,13 @@
       }
     },
     "node_modules/globby": {
-      "version": "13.2.0",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.0.tgz",
-      "integrity": "sha512-jWsQfayf13NvqKUIL3Ta+CIqMnvlaIDFveWE/dpOZ9+3AMEJozsxDvKA02zync9UuvOM8rOXzsD5GqKP4OnWPQ==",
+      "version": "13.2.2",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz",
+      "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==",
       "dependencies": {
         "dir-glob": "^3.0.1",
-        "fast-glob": "^3.2.11",
-        "ignore": "^5.2.0",
+        "fast-glob": "^3.3.0",
+        "ignore": "^5.2.4",
         "merge2": "^1.4.1",
         "slash": "^4.0.0"
       },
@@ -4899,9 +4970,9 @@
       }
     },
     "node_modules/happy-dom": {
-      "version": "9.20.3",
-      "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-9.20.3.tgz",
-      "integrity": "sha512-eBsgauT435fXFvQDNcmm5QbGtYzxEzOaX35Ia+h6yP/wwa4xSWZh1CfP+mGby8Hk6Xu59mTkpyf72rUXHNxY7A==",
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-10.0.3.tgz",
+      "integrity": "sha512-WkCP+Z5fX6U5PY+yHP3ElV5D9PoxRAHRWPFq3pG9rg/6Hjf5ak7dozAgSCywsTRUq2qfa8vV8OQvUy5pRXy8EQ==",
       "dependencies": {
         "css.escape": "^1.5.1",
         "entities": "^4.5.0",
@@ -5074,6 +5145,14 @@
         "node": ">= 6"
       }
     },
+    "node_modules/human-signals": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
+      "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
+      "engines": {
+        "node": ">=14.18.0"
+      }
+    },
     "node_modules/iconv-lite": {
       "version": "0.6.3",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -5283,6 +5362,37 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-inside-container": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+      "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+      "dependencies": {
+        "is-docker": "^3.0.0"
+      },
+      "bin": {
+        "is-inside-container": "cli.js"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-inside-container/node_modules/is-docker": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-negative-zero": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
@@ -5355,6 +5465,17 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-stream": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+      "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-string": {
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
@@ -5429,9 +5550,9 @@
       "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
     },
     "node_modules/jiti": {
-      "version": "1.18.2",
-      "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
-      "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==",
+      "version": "1.19.1",
+      "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
+      "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==",
       "bin": {
         "jiti": "bin/jiti.js"
       }
@@ -5467,14 +5588,6 @@
         "node": ">=10"
       }
     },
-    "node_modules/js-string-escape": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
-      "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==",
-      "engines": {
-        "node": ">= 0.8"
-      }
-    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -5697,11 +5810,11 @@
       }
     },
     "node_modules/magic-string": {
-      "version": "0.30.0",
-      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz",
-      "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==",
+      "version": "0.30.1",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
+      "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==",
       "dependencies": {
-        "@jridgewell/sourcemap-codec": "^1.4.13"
+        "@jridgewell/sourcemap-codec": "^1.4.15"
       },
       "engines": {
         "node": ">=12"
@@ -5768,22 +5881,16 @@
         "markty": "0.0.4"
       }
     },
-    "node_modules/md5-hex": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz",
-      "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==",
-      "dependencies": {
-        "blueimp-md5": "^2.10.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
     "node_modules/mdurl": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
       "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
     },
+    "node_modules/merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
+    },
     "node_modules/merge2": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -5823,6 +5930,17 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/mimic-fn": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
+      "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -5911,9 +6029,9 @@
       }
     },
     "node_modules/node-releases": {
-      "version": "2.0.12",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz",
-      "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ=="
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+      "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ=="
     },
     "node_modules/nopt": {
       "version": "6.0.0",
@@ -5937,6 +6055,31 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/npm-run-path": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
+      "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
+      "dependencies": {
+        "path-key": "^4.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/npm-run-path/node_modules/path-key": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+      "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/nth-check": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
@@ -5949,9 +6092,9 @@
       }
     },
     "node_modules/nwsapi": {
-      "version": "2.2.5",
-      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz",
-      "integrity": "sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ=="
+      "version": "2.2.7",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
+      "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ=="
     },
     "node_modules/object-inspect": {
       "version": "1.12.3",
@@ -6021,6 +6164,20 @@
         "wrappy": "1"
       }
     },
+    "node_modules/onetime": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
+      "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
+      "dependencies": {
+        "mimic-fn": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/open": {
       "version": "8.4.2",
       "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
@@ -6038,16 +6195,16 @@
       }
     },
     "node_modules/optionator": {
-      "version": "0.9.1",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
-      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+      "version": "0.9.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
+      "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
       "dependencies": {
+        "@aashutoshrathi/word-wrap": "^1.2.3",
         "deep-is": "^0.1.3",
         "fast-levenshtein": "^2.0.6",
         "levn": "^0.4.1",
         "prelude-ls": "^1.2.1",
-        "type-check": "^0.4.0",
-        "word-wrap": "^1.2.3"
+        "type-check": "^0.4.0"
       },
       "engines": {
         "node": ">= 0.8.0"
@@ -6231,9 +6388,9 @@
       }
     },
     "node_modules/postcss": {
-      "version": "8.4.24",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
-      "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
+      "version": "8.4.25",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
+      "integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
       "funding": [
         {
           "type": "opencollective",
@@ -6278,14 +6435,14 @@
       }
     },
     "node_modules/prettier": {
-      "version": "2.8.8",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
-      "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz",
+      "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==",
       "bin": {
-        "prettier": "bin-prettier.js"
+        "prettier": "bin/prettier.cjs"
       },
       "engines": {
-        "node": ">=10.13.0"
+        "node": ">=14"
       },
       "funding": {
         "url": "https://github.com/prettier/prettier?sponsor=1"
@@ -6323,16 +6480,16 @@
       }
     },
     "node_modules/pretty-format": {
-      "version": "27.5.1",
-      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
-      "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
+      "version": "29.6.1",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.1.tgz",
+      "integrity": "sha512-7jRj+yXO0W7e4/tSJKoR7HRIHLPPjtNaUGG2xxKQnGvPNRkgWcQ0AZX6P4KBRJN4FcTBWb3sa7DVUJmocYuoog==",
       "dependencies": {
-        "ansi-regex": "^5.0.1",
+        "@jest/schemas": "^29.6.0",
         "ansi-styles": "^5.0.0",
-        "react-is": "^17.0.1"
+        "react-is": "^18.0.0"
       },
       "engines": {
-        "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+        "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
       }
     },
     "node_modules/pretty-format/node_modules/ansi-styles": {
@@ -6399,9 +6556,9 @@
       ]
     },
     "node_modules/react-is": {
-      "version": "17.0.2",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
-      "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+      "version": "18.2.0",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+      "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
     },
     "node_modules/readdirp": {
       "version": "3.6.0",
@@ -6603,9 +6760,9 @@
       }
     },
     "node_modules/rollup": {
-      "version": "3.25.3",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.3.tgz",
-      "integrity": "sha512-ZT279hx8gszBj9uy5FfhoG4bZx8c+0A1sbqtr7Q3KNWIizpTdDEPZbV2xcbvHsnFp4MavCQYZyzApJ+virB8Yw==",
+      "version": "3.26.2",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.2.tgz",
+      "integrity": "sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==",
       "bin": {
         "rollup": "dist/bin/rollup"
       },
@@ -6650,6 +6807,102 @@
         "node": ">= 8"
       }
     },
+    "node_modules/run-applescript": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz",
+      "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==",
+      "dependencies": {
+        "execa": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/run-applescript/node_modules/execa": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^6.0.0",
+        "human-signals": "^2.1.0",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.1",
+        "onetime": "^5.1.2",
+        "signal-exit": "^3.0.3",
+        "strip-final-newline": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/run-applescript/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==",
+      "engines": {
+        "node": ">=10.17.0"
+      }
+    },
+    "node_modules/run-applescript/node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/run-applescript/node_modules/mimic-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/run-applescript/node_modules/npm-run-path": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+      "dependencies": {
+        "path-key": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/run-applescript/node_modules/onetime": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+      "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+      "dependencies": {
+        "mimic-fn": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/run-applescript/node_modules/strip-final-newline": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -6733,9 +6986,9 @@
       }
     },
     "node_modules/semver": {
-      "version": "6.3.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
       "bin": {
         "semver": "bin/semver.js"
       }
@@ -6805,6 +7058,11 @@
       "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
       "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g=="
     },
+    "node_modules/signal-exit": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
+    },
     "node_modules/sirv": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz",
@@ -6973,6 +7231,17 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/strip-final-newline": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
+      "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/strip-json-comments": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -7027,6 +7296,21 @@
       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
       "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
     },
+    "node_modules/synckit": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
+      "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==",
+      "dependencies": {
+        "@pkgr/utils": "^2.3.1",
+        "tslib": "^2.5.0"
+      },
+      "engines": {
+        "node": "^14.18.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/unts"
+      }
+    },
     "node_modules/systemjs": {
       "version": "6.14.1",
       "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-6.14.1.tgz",
@@ -7055,23 +7339,15 @@
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
       "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="
     },
-    "node_modules/time-zone": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz",
-      "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==",
-      "engines": {
-        "node": ">=4"
-      }
-    },
     "node_modules/tinybench": {
       "version": "2.5.0",
       "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz",
       "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA=="
     },
     "node_modules/tinypool": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz",
-      "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==",
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.6.0.tgz",
+      "integrity": "sha512-FdswUUo5SxRizcBc6b1GSuLpLjisa8N8qMyYoP3rl+bym+QauhtJP5bvZY1ytt8krKGmMLYIRl36HBZfeAoqhQ==",
       "engines": {
         "node": ">=14.0.0"
       }
@@ -7084,6 +7360,17 @@
         "node": ">=14.0.0"
       }
     },
+    "node_modules/titleize": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz",
+      "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -7304,6 +7591,14 @@
         "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==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/update-browserslist-db": {
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
@@ -7380,13 +7675,13 @@
       }
     },
     "node_modules/vite": {
-      "version": "4.3.9",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
-      "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.2.tgz",
+      "integrity": "sha512-zUcsJN+UvdSyHhYa277UHhiJ3iq4hUBwHavOpsNUGsTgjBeoBlK8eDt+iT09pBq0h9/knhG/SPrZiM7cGmg7NA==",
       "dependencies": {
-        "esbuild": "^0.17.5",
-        "postcss": "^8.4.23",
-        "rollup": "^3.21.0"
+        "esbuild": "^0.18.10",
+        "postcss": "^8.4.24",
+        "rollup": "^3.25.2"
       },
       "bin": {
         "vite": "bin/vite.js"
@@ -7394,12 +7689,16 @@
       "engines": {
         "node": "^14.18.0 || >=16.0.0"
       },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
       "optionalDependencies": {
         "fsevents": "~2.3.2"
       },
       "peerDependencies": {
         "@types/node": ">= 14",
         "less": "*",
+        "lightningcss": "^1.21.0",
         "sass": "*",
         "stylus": "*",
         "sugarss": "*",
@@ -7412,6 +7711,9 @@
         "less": {
           "optional": true
         },
+        "lightningcss": {
+          "optional": true
+        },
         "sass": {
           "optional": true
         },
@@ -7471,34 +7773,33 @@
       }
     },
     "node_modules/vitest": {
-      "version": "0.32.2",
-      "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz",
-      "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==",
+      "version": "0.33.0",
+      "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.33.0.tgz",
+      "integrity": "sha512-1CxaugJ50xskkQ0e969R/hW47za4YXDUfWJDxip1hwbnhUjYolpfUn2AMOulqG/Dtd9WYAtkHmM/m3yKVrEejQ==",
       "dependencies": {
         "@types/chai": "^4.3.5",
         "@types/chai-subset": "^1.3.3",
         "@types/node": "*",
-        "@vitest/expect": "0.32.2",
-        "@vitest/runner": "0.32.2",
-        "@vitest/snapshot": "0.32.2",
-        "@vitest/spy": "0.32.2",
-        "@vitest/utils": "0.32.2",
-        "acorn": "^8.8.2",
+        "@vitest/expect": "0.33.0",
+        "@vitest/runner": "0.33.0",
+        "@vitest/snapshot": "0.33.0",
+        "@vitest/spy": "0.33.0",
+        "@vitest/utils": "0.33.0",
+        "acorn": "^8.9.0",
         "acorn-walk": "^8.2.0",
         "cac": "^6.7.14",
         "chai": "^4.3.7",
-        "concordance": "^5.0.4",
         "debug": "^4.3.4",
         "local-pkg": "^0.4.3",
-        "magic-string": "^0.30.0",
-        "pathe": "^1.1.0",
+        "magic-string": "^0.30.1",
+        "pathe": "^1.1.1",
         "picocolors": "^1.0.0",
-        "std-env": "^3.3.2",
+        "std-env": "^3.3.3",
         "strip-literal": "^1.0.1",
         "tinybench": "^2.5.0",
-        "tinypool": "^0.5.0",
+        "tinypool": "^0.6.0",
         "vite": "^3.0.0 || ^4.0.0",
-        "vite-node": "0.32.2",
+        "vite-node": "0.33.0",
         "why-is-node-running": "^2.2.2"
       },
       "bin": {
@@ -7553,14 +7854,14 @@
       "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q=="
     },
     "node_modules/vitest/node_modules/vite-node": {
-      "version": "0.32.2",
-      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz",
-      "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==",
+      "version": "0.33.0",
+      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.33.0.tgz",
+      "integrity": "sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==",
       "dependencies": {
         "cac": "^6.7.14",
         "debug": "^4.3.4",
-        "mlly": "^1.2.0",
-        "pathe": "^1.1.0",
+        "mlly": "^1.4.0",
+        "pathe": "^1.1.1",
         "picocolors": "^1.0.0",
         "vite": "^3.0.0 || ^4.0.0"
       },
@@ -7626,9 +7927,9 @@
       }
     },
     "node_modules/vue-eslint-parser/node_modules/semver": {
-      "version": "7.5.3",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
-      "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
       "dependencies": {
         "lru-cache": "^6.0.0"
       },
@@ -7675,9 +7976,9 @@
       }
     },
     "node_modules/vue-router": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.2.tgz",
-      "integrity": "sha512-cChBPPmAflgBGmy3tBsjeoe3f3VOSG6naKyY5pjtrqLGbNEXdzCigFUHgBvp9e3ysAtFtEx7OLqcSDh/1Cq2TQ==",
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz",
+      "integrity": "sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==",
       "dependencies": {
         "@vue/devtools-api": "^6.5.0"
       },
@@ -7739,14 +8040,6 @@
         "node": ">=12"
       }
     },
-    "node_modules/well-known-symbols": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz",
-      "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==",
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/whatwg-encoding": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
@@ -7841,14 +8134,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/word-wrap": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
-      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/wrap-ansi": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
diff --git a/package.json b/package.json
index d78fe416..8aaf8cc8 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
   "scripts": {
     "build": "vite build",
     "test": "TZ=Europe/Berlin vitest",
-    "lint": "prettier assets './**/*.{yml,yaml,toml}' --write && eslint assets/**/*.js assets/**/*.vue --fix",
+    "lint": "prettier assets './**/*.{yml,yaml}' --write && eslint assets/**/*.js assets/**/*.vue --fix",
     "dev": "vite",
     "histoire": "histoire dev",
     "playwright": "playwright test --ui"
@@ -29,20 +29,20 @@
     "eslint-config-prettier": "^8.5.0",
     "eslint-plugin-import": "^2.25.3",
     "eslint-plugin-node": "^11.1.0",
-    "eslint-plugin-prettier": "^4.0.0",
+    "eslint-plugin-prettier": "^5.0.0-alpha.1",
     "eslint-plugin-promise": "^6.0.0",
     "eslint-plugin-vue": "^9.3.0",
-    "happy-dom": "^9.5.0",
+    "happy-dom": "^10.0.3",
     "histoire": "^0.16.1",
     "json-to-pretty-yaml": "^1.2.2",
     "markty-toml": "^0.1.1",
-    "prettier": "^2.5.1",
+    "prettier": "^3.0.0",
     "prettier-plugin-toml": "^0.3.1",
     "rollup-plugin-visualizer": "^5.8.3",
     "smoothscroll-polyfill": "^0.4.4",
     "vite": "^4.2.1",
     "vite-plugin-toml": "^0.5.0",
-    "vitest": "^0.32.2",
+    "vitest": "^0.33.0",
     "vue": "^3.2.29",
     "vue-eslint-parser": "^9.1.0",
     "vue-hot-reload-api": "^2.3.4",
diff --git a/provider/const.go b/provider/const.go
index 6db48b8e..6472eeb3 100644
--- a/provider/const.go
+++ b/provider/const.go
@@ -26,7 +26,7 @@ func NewConstFromConfig(other map[string]interface{}) (Provider, error) {
 		return nil, err
 	}
 
-	pipe, err := pipeline.New(cc.Settings)
+	pipe, err := pipeline.New(nil, cc.Settings)
 	if err != nil {
 		return nil, err
 	}
diff --git a/provider/http.go b/provider/http.go
index 931c68d4..2ff66d44 100644
--- a/provider/http.go
+++ b/provider/http.go
@@ -60,8 +60,9 @@ func NewHTTPProviderFromConfig(other map[string]interface{}) (Provider, error) {
 		return nil, err
 	}
 
+	log := util.NewLogger("http")
 	http := NewHTTP(
-		util.NewLogger("http"),
+		log,
 		cc.Method,
 		cc.URI,
 		cc.Insecure,
@@ -80,7 +81,7 @@ func NewHTTPProviderFromConfig(other map[string]interface{}) (Provider, error) {
 
 	if err == nil {
 		var pipe *pipeline.Pipeline
-		pipe, err = pipeline.New(cc.Settings)
+		pipe, err = pipeline.New(log, cc.Settings)
 		http = http.WithPipeline(pipe)
 	}
 
diff --git a/provider/mqtt.go b/provider/mqtt.go
index 2a589e01..986fc7af 100644
--- a/provider/mqtt.go
+++ b/provider/mqtt.go
@@ -53,7 +53,7 @@ func NewMqttFromConfig(other map[string]interface{}) (Provider, error) {
 		m = m.WithRetained()
 	}
 
-	pipe, err := pipeline.New(cc.Settings)
+	pipe, err := pipeline.New(log, cc.Settings)
 	if err == nil {
 		m = m.WithPipeline(pipe)
 	}
diff --git a/provider/pipeline/pipeline.go b/provider/pipeline/pipeline.go
index a040a45b..d99389d3 100644
--- a/provider/pipeline/pipeline.go
+++ b/provider/pipeline/pipeline.go
@@ -9,6 +9,7 @@ import (
 
 	xj "github.com/basgys/goxml2json"
 	"github.com/evcc-io/evcc/provider/javascript"
+	"github.com/evcc-io/evcc/util"
 	"github.com/evcc-io/evcc/util/jq"
 	"github.com/itchyny/gojq"
 	"github.com/robertkrimen/otto"
@@ -16,6 +17,7 @@ import (
 )
 
 type Pipeline struct {
+	log    *util.Logger
 	re     *regexp.Regexp
 	jq     *gojq.Query
 	dflt   string
@@ -35,8 +37,10 @@ type Settings struct {
 	Script  string
 }
 
-func New(cc Settings) (*Pipeline, error) {
-	p := new(Pipeline)
+func New(log *util.Logger, cc Settings) (*Pipeline, error) {
+	p := &Pipeline{
+		log: log,
+	}
 
 	var err error
 	if err == nil && cc.Regex != "" {
@@ -137,6 +141,10 @@ func (p *Pipeline) transformXML(value []byte) []byte {
 		return value
 	}
 
+	if p.log != nil {
+		p.log.TRACE.Println(out.String())
+	}
+
 	return out.Bytes()
 }
 
diff --git a/provider/socket.go b/provider/socket.go
index 4e64287f..61e04a70 100644
--- a/provider/socket.go
+++ b/provider/socket.go
@@ -85,7 +85,7 @@ func NewSocketProviderFromConfig(other map[string]interface{}) (Provider, error)
 	}
 
 	var err error
-	if p.pipeline, err = pipeline.New(cc.Settings); err != nil {
+	if p.pipeline, err = pipeline.New(log, cc.Settings); err != nil {
 		return nil, err
 	}
 
diff --git a/tariff/awattar.go b/tariff/awattar.go
index 3f411914..34c2eb60 100644
--- a/tariff/awattar.go
+++ b/tariff/awattar.go
@@ -30,9 +30,8 @@ func init() {
 
 func NewAwattarFromConfig(other map[string]interface{}) (api.Tariff, error) {
 	cc := struct {
-		embed    `mapstructure:",squash"`
-		Currency string // TODO deprecated
-		Region   string
+		embed  `mapstructure:",squash"`
+		Region string
 	}{
 		Region: "DE",
 	}
@@ -41,10 +40,6 @@ func NewAwattarFromConfig(other map[string]interface{}) (api.Tariff, error) {
 		return nil, err
 	}
 
-	if cc.Currency == "" {
-		cc.Currency = "EUR"
-	}
-
 	t := &Awattar{
 		embed: &cc.embed,
 		log:   util.NewLogger("awattar"),
diff --git a/tariff/elering.go b/tariff/elering.go
index 92eb468a..241597f4 100644
--- a/tariff/elering.go
+++ b/tariff/elering.go
@@ -32,9 +32,8 @@ func init() {
 
 func NewEleringFromConfig(other map[string]interface{}) (api.Tariff, error) {
 	var cc struct {
-		embed    `mapstructure:",squash"`
-		Currency string // TODO deprecated
-		Region   string
+		embed  `mapstructure:",squash"`
+		Region string
 	}
 
 	if err := util.DecodeOther(other, &cc); err != nil {
diff --git a/tariff/fixed.go b/tariff/fixed.go
index cd094339..6f168407 100644
--- a/tariff/fixed.go
+++ b/tariff/fixed.go
@@ -25,9 +25,8 @@ func init() {
 
 func NewFixedFromConfig(other map[string]interface{}) (api.Tariff, error) {
 	var cc struct {
-		Currency string // TODO deprecated
-		Price    float64
-		Zones    []struct {
+		Price float64
+		Zones []struct {
 			Price       float64
 			Days, Hours string
 		}
diff --git a/tariff/tibber.go b/tariff/tibber.go
index 6f991d5d..80a395e1 100644
--- a/tariff/tibber.go
+++ b/tariff/tibber.go
@@ -15,6 +15,7 @@ import (
 )
 
 type Tibber struct {
+	*embed
 	mux     sync.Mutex
 	log     *util.Logger
 	homeID  string
@@ -31,6 +32,7 @@ func init() {
 
 func NewTibberFromConfig(other map[string]interface{}) (api.Tariff, error) {
 	var cc struct {
+		embed  `mapstructure:",squash"`
 		Token  string
 		HomeID string
 		Unit   string
@@ -47,6 +49,7 @@ func NewTibberFromConfig(other map[string]interface{}) (api.Tariff, error) {
 	log := util.NewLogger("tibber").Redact(cc.Token, cc.HomeID)
 
 	t := &Tibber{
+		embed:  &cc.embed,
 		log:    log,
 		homeID: cc.HomeID,
 		client: tibber.NewClient(log, cc.Token),
@@ -116,7 +119,7 @@ func (t *Tibber) rates(pi []tibber.Price) api.Rates {
 		ar := api.Rate{
 			Start: r.StartsAt.Local(),
 			End:   r.StartsAt.Add(time.Hour).Local(),
-			Price: r.Total,
+			Price: t.totalPrice(r.Total),
 		}
 		data = append(data, ar)
 	}
diff --git a/templates/definition/charger/ocpp-elvi.yaml b/templates/definition/charger/ocpp-elvi.yaml
index 2f9f192d..dd168c1a 100644
--- a/templates/definition/charger/ocpp-elvi.yaml
+++ b/templates/definition/charger/ocpp-elvi.yaml
@@ -5,5 +5,25 @@ products:
       generic: Elvi
 params:
   - preset: ocpp
+  - name: meter
+    type: bool
+    default: true
+    description:
+      de: Hat die Wallbox einen integrierten Zähler verbaut?
+      en: The charger has an integrated metering device installed?
+    help:
+      de: Deaktiveren wenn die Wallbox keinen integrierten Zähler verbaut hat
+      en: Deactivate if the charger has no integrated metering device installed
+  - name: meterinterval
+    advanced: true
+    type: duration
+    description:
+      de: Zählerwerte im Intervall anfordern
+      en: Interval for requesting metering values
+    default: 4s
 render: |
   {{ include "ocpp" . }}
+  {{- if ne .meter "false" }}
+  metervalues: Current.Import.L1,Current.Import.L2,Current.Import.L3,Energy.Active.Import.Register,Power.Active.Import,Voltage.L1,Voltage.L2,Voltage.L3
+  meterinterval: {{ .meterinterval }}
+  {{- end }}
diff --git a/templates/definition/charger/ocpp-pulsarplus.yaml b/templates/definition/charger/ocpp-pulsarplus.yaml
index a87597f5..f50c2119 100644
--- a/templates/definition/charger/ocpp-pulsarplus.yaml
+++ b/templates/definition/charger/ocpp-pulsarplus.yaml
@@ -2,7 +2,21 @@ template: pulsarplus
 products:
   - brand: wallbox
     description:
-      generic: Pulsar Plus/ Commander 2/ Copper SB
+      generic: Pulsar Plus / Commander 2 / Copper SB
+requirements:
+  description:
+    de: |
+      Anleitung: https://support.wallbox.com/en/knowledge-base/ocpp-activation-and-setup-guide/
+      * “OCPP aktivieren” (myWallbox app) bzw. den “OCPP-WebSocket-Verbindung” Schalter (myWallbox Portal) aktivieren
+      * URL: ws://[evcc-adresse]:8887/ (Verbindung über das lokale Netzwerk)
+      * Ladepunktidentität: beliebiger Wert (z.B. die Seriennummer der Box), der als *stationid* verwendet wird
+      * Passwort: leer lassen
+    en: |
+      Setup Guide: https://support.wallbox.com/en/knowledge-base/ocpp-activation-and-setup-guide/
+      * Switch on “Enable OCPP” (myWallbox app) or enable the “OCPP WebSocket connection” switch (myWallbox Portal)
+      * URL: ws://[evcc-adresse]:8887/ (local network connection)
+      * Charge Point Identity: Custom value (e.g. serial number of charger) which is reused in configuration as *stationid*
+      * Password: leave empty
 params:
   - preset: ocpp
 render: |
diff --git a/templates/definition/charger/ocpp.yaml b/templates/definition/charger/ocpp.yaml
index d5f41e5a..f524f205 100644
--- a/templates/definition/charger/ocpp.yaml
+++ b/templates/definition/charger/ocpp.yaml
@@ -17,7 +17,7 @@ requirements:
 
       Voraussetzungen:
       * Ggf. zuvor konfigurierte OCPP-Profile (z.B. durch eine andere Backend-Anbindung) in der Wallboxkonfiguration entfernen
-      * Backend-URL (Central System) in der Wallboxkonfiguration: `ws://<evcc-IP-Adresse>:8887/` (evtl noch um `stationid` erweitern)
+      * Backend-URL (Central System) in der Wallboxkonfiguration: `ws://[evcc-adresse]:8887/` (evtl noch um `stationid` erweitern)
       * Protokoll: OCPP-J v1.6, ocpp16j, JSON, Websocket, ws:// o.ä.
       * Keine Verschlüsselung, keine Authentifizierung, kein Passwort
       * Verbindung über das lokale Netzwerk
@@ -32,7 +32,7 @@ requirements:
 
       Requirements:
       * If necessary, remove previously configured OCPP profiles (e.g. used for a different backend connection) in the charger configuration
-      * Backend URL (Central System) in the charger configuration: `ws://<evcc-IP-address>:8887/` (possibly add `stationid`)
+      * Backend URL (Central System) in the charger configuration: `ws://[evcc-adresse]:8887/` (possibly add `stationid`)
       * Protocol: OCPP-J v1.6, ocpp16j, JSON, Websocket, ws:// or similar
       * No encryption, no authentication, no password
       * Local network connection
diff --git a/templates/definition/meter/kostal-piko-mp-plus.yaml b/templates/definition/meter/kostal-piko-mp-plus.yaml
index dce12357..41e9d78a 100644
--- a/templates/definition/meter/kostal-piko-mp-plus.yaml
+++ b/templates/definition/meter/kostal-piko-mp-plus.yaml
@@ -3,6 +3,9 @@ products:
   - brand: Kostal
     description:
       generic: Piko MP Plus
+  - brand: Steca
+    description:
+      generic: coolcept fleX
 linked:
   - template: kostal-ksem-inverter
     usage: grid
diff --git a/templates/definition/meter/mtec-eb-gen2.yaml b/templates/definition/meter/mtec-eb-gen2.yaml
new file mode 100644
index 00000000..5834ac8d
--- /dev/null
+++ b/templates/definition/meter/mtec-eb-gen2.yaml
@@ -0,0 +1,47 @@
+template: mtec-eb-gen2
+products:
+  - brand: M-TEC
+    description:
+      generic: Energy Butler GEN2
+params:
+  - name: usage
+    choice: ["grid", "pv", "battery"]
+  - name: modbus
+    choice: ["rs485"]
+render: |
+  type: custom
+  {{- if eq .usage "grid" }}
+  power:
+    source: modbus
+    {{- include "modbus" . | indent 2 }}
+    register:
+      address: 11000 # Zähler (NVP) Leistung
+      type: holding
+      decode: int32
+  {{- end }}
+  {{- if eq .usage "pv" }}
+  power:
+    source: modbus
+    {{- include "modbus" . | indent 2 }}
+    register:
+      address: 11028 # PV Leistung
+      type: holding
+      decode: uint32
+  {{- end }}
+  {{- if eq .usage "battery" }}
+  power:
+    source: modbus
+    {{- include "modbus" . | indent 2 }}
+    register:
+      address: 40258 # Batterie Leistung
+      type: holding
+      decode: int32
+  soc:
+    source: modbus
+    {{- include "modbus" . | indent 2 }}
+    register:
+      address: 43000 # State of Charge (SOC)
+      type: holding
+      decode: uint16
+      scale: 0.01
+  {{- end }}
diff --git a/templates/definition/meter/mtec-eb-gen3.yaml b/templates/definition/meter/mtec-eb-gen3.yaml
new file mode 100644
index 00000000..5d2fde70
--- /dev/null
+++ b/templates/definition/meter/mtec-eb-gen3.yaml
@@ -0,0 +1,47 @@
+template: mtec-eb-gen3
+products:
+  - brand: M-TEC
+    description:
+      generic: Energy Butler GEN3
+params:
+  - name: usage
+    choice: ["grid", "pv", "battery"]
+  - name: modbus
+    choice: ["rs485"]
+render: |
+  type: custom
+  {{- if eq .usage "grid" }}
+  power:
+    source: modbus
+    {{- include "modbus" . | indent 2 }}
+    register:
+      address: 11000 # Zähler (NVP) Leistung
+      type: holding
+      decode: int32
+  {{- end }}
+  {{- if eq .usage "pv" }}
+  power:
+    source: modbus
+    {{- include "modbus" . | indent 2 }}
+    register:
+      address: 11028 # PV Leistung
+      type: holding
+      decode: uint32
+  {{- end }}
+  {{- if eq .usage "battery" }}
+  power:
+    source: modbus
+    {{- include "modbus" . | indent 2 }}
+    register:
+      address: 30258 # Batterie Leistung
+      type: holding
+      decode: int32
+  soc:
+    source: modbus
+    {{- include "modbus" . | indent 2 }}
+    register:
+      address: 33000 # State of Charge (SOC)
+      type: holding
+      decode: uint16
+      scale: 0.01
+  {{- end }}
diff --git a/templates/definition/meter/sonnenbatterie_eco56.yaml b/templates/definition/meter/sonnenbatterie_eco56.yaml
new file mode 100644
index 00000000..cc51b133
--- /dev/null
+++ b/templates/definition/meter/sonnenbatterie_eco56.yaml
@@ -0,0 +1,54 @@
+template: sonnenbatterie-eco56
+products:
+  - brand: Sonnen
+    description:
+      generic: comfort, eco 5, eco 6, oem 6.5
+params:
+  - name: usage
+    choice: ["grid", "pv", "battery"]
+  - name: host
+  - name: port
+    default: 7979
+  - name: capacity
+    advanced: true
+render: |
+  type: custom
+  {{- if eq .usage "grid" }}
+  power:
+    source: http
+    uri: http://{{ .host }}:{{ .port }}/rest/devices/battery
+    jq: .M39 - .M38 # current purchase - current feed-in at the interconnection point
+  energy:
+    source: http
+    uri: http://{{ .host }}:{{ .port }}/rest/devices/battery
+    jq: .M41 # cumulated purchase since installation
+  {{- end }}
+  {{- if eq .usage "pv" }}
+  power:
+    source: http
+    uri: http://{{ .host }}:{{ .port }}/rest/devices/battery
+    jq: .M03 # current pv power
+  energy:
+    source: http
+    uri: http://{{ .host }}:{{ .port }}/rest/devices/battery
+    jq: .M37 # cumulated pv production since installation of Sonnenbatterie
+  {{- end }}
+  {{- if eq .usage "battery" }}
+  power:
+    source: http
+    uri: http://{{ .host }}:{{ .port }}/rest/devices/battery
+    # M34 current discharging power, S65 max inverter power
+    # M35 current charging power, S65 max inverter power
+    jq: (if .M34 <= .S65 then .M34 else 0 end) - (if .M35 <= .S65 then .M35 else 0 end)
+  energy:
+    source: http
+    uri: http://{{ .host }}:{{ .port }}/rest/devices/battery
+    jq: .M31 # total stored energy over lifetime
+  soc:
+    source: http
+    uri: http://{{ .host }}:{{ .port }}/rest/devices/battery
+    jq: .M30 # SOC relative to usable capacity (.M05 # display SOC)
+  {{- if .capacity }}
+  capacity: {{ .capacity }} # kWh
+  {{- end }}
+  {{- end }}
diff --git a/templates/definition/meter/youless.yaml b/templates/definition/meter/youless.yaml
new file mode 100644
index 00000000..68d076b5
--- /dev/null
+++ b/templates/definition/meter/youless.yaml
@@ -0,0 +1,22 @@
+template: youless
+products:
+  - brand: Youless
+    description:
+      generic: Energy Monitor
+params:
+  - name: usage
+    choice: ["grid"]
+  - name: host
+    required: true
+render: |
+  type: custom
+  power:
+    source: http
+    uri: http://{{ .host }}/e
+    method: GET
+    jq: .[0]|.pwr
+  energy:
+    source: http
+    uri: http://{{ .host }}/e
+    method: GET
+    jq: .[0]|.p1+.p2
diff --git a/templates/definition/vehicle/offline.yaml b/templates/definition/vehicle/offline.yaml
index 31ae4e9a..9c7d9f17 100644
--- a/templates/definition/vehicle/offline.yaml
+++ b/templates/definition/vehicle/offline.yaml
@@ -11,15 +11,6 @@ params:
   - name: capacity
   - name: phases
     advanced: true
-  - name: mode
-    advanced: true
-  - name: minCurrent
-    advanced: true
-  - name: maxCurrent
-    advanced: true
-  - name: identifiers
-    advanced: true
-    type: stringlist
   - preset: vehicle-identify
 render: |
   type: custom
@@ -37,21 +28,4 @@ render: |
   soc:
     source: const
     value: 0
-  onIdentify:
-  {{- if .mode }}
-    mode: {{ .mode }}
-  {{- end }}
-    minSoc: 0 # fixed - no soc available
-    targetSoc: 100 # fixed - no soc available
-  {{- if .minCurrent }}
-    minCurrent: {{ .minCurrent }}
-  {{- end }}
-  {{- if .maxCurrent }}
-    maxCurrent: {{ .maxCurrent }}
-  {{- end }}
-  {{- if (len .identifiers) }}
-  identifiers:
-  {{-   range .identifiers }}
-  - {{ . }}
-  {{-   end }}
-  {{- end }}
+  {{ include "vehicle-identify" . }}
diff --git a/templates/definition/vehicle/seat-cupra.yaml b/templates/definition/vehicle/seat-cupra.yaml
index 4e747b76..3ebd497e 100644
--- a/templates/definition/vehicle/seat-cupra.yaml
+++ b/templates/definition/vehicle/seat-cupra.yaml
@@ -2,7 +2,7 @@ template: cupra
 products:
   - brand: Seat
     description:
-      generic: Cupra Born, My Cupra
+      generic: CupraConnect Gen4 (Born)
 params:
   - preset: vehicle-base
   - preset: vehicle-identify
diff --git a/templates/definition/vehicle/seat.yaml b/templates/definition/vehicle/seat.yaml
index 62b99403..c96cc2b0 100644
--- a/templates/definition/vehicle/seat.yaml
+++ b/templates/definition/vehicle/seat.yaml
@@ -2,8 +2,7 @@ template: seat
 products:
   - brand: Seat
     description:
-      de: Andere
-      en: Others
+      generic: CupraConnect Gen3 (Ateca, Leon, Formentor)
 params:
   - preset: vehicle-base
   - preset: vehicle-identify
diff --git a/templates/docs/charger/elvi_0.yaml b/templates/docs/charger/elvi_0.yaml
index 6be597ce..d5f50936 100644
--- a/templates/docs/charger/elvi_0.yaml
+++ b/templates/docs/charger/elvi_0.yaml
@@ -5,6 +5,7 @@ render:
   - default: |
       type: template
       template: elvi
+      meter: true # Deaktiveren wenn die Wallbox keinen integrierten Zähler verbaut hat (Optional)
     advanced: |
       type: template
       template: elvi
@@ -13,3 +14,5 @@ render:
       idtag: '04E6B78921BBA0' # Token-ID welche für die Freischaltung der Ladevorgänge an den Ladepunkt zurückgesendet wird (Optional)
       connecttimeout: 5m # Optional
       timeout: 2m # Optional
+      meter: true # Deaktiveren wenn die Wallbox keinen integrierten Zähler verbaut hat (Optional)
+      meterinterval: 4s # Optional
diff --git a/templates/docs/charger/ocpp_0.yaml b/templates/docs/charger/ocpp_0.yaml
index bc07979d..2bec794e 100644
--- a/templates/docs/charger/ocpp_0.yaml
+++ b/templates/docs/charger/ocpp_0.yaml
@@ -12,7 +12,7 @@ description: |
 
   Voraussetzungen:
   * Ggf. zuvor konfigurierte OCPP-Profile (z.B. durch eine andere Backend-Anbindung) in der Wallboxkonfiguration entfernen
-  * Backend-URL (Central System) in der Wallboxkonfiguration: `ws://<evcc-IP-Adresse>:8887/` (evtl noch um `stationid` erweitern)
+  * Backend-URL (Central System) in der Wallboxkonfiguration: `ws://[evcc-adresse]:8887/` (evtl noch um `stationid` erweitern)
   * Protokoll: OCPP-J v1.6, ocpp16j, JSON, Websocket, ws:// o.ä.
   * Keine Verschlüsselung, keine Authentifizierung, kein Passwort
   * Verbindung über das lokale Netzwerk
diff --git a/templates/docs/charger/pulsarplus_0.yaml b/templates/docs/charger/pulsarplus_0.yaml
index 60310c72..223fdd72 100644
--- a/templates/docs/charger/pulsarplus_0.yaml
+++ b/templates/docs/charger/pulsarplus_0.yaml
@@ -1,6 +1,13 @@
 product:
   brand: wallbox
-  description: Pulsar Plus/ Commander 2/ Copper SB
+  description: Pulsar Plus / Commander 2 / Copper SB
+description: |
+  Anleitung: https://support.wallbox.com/en/knowledge-base/ocpp-activation-and-setup-guide/
+  * “OCPP aktivieren” (myWallbox app) bzw. den “OCPP-WebSocket-Verbindung” Schalter (myWallbox Portal) aktivieren
+  * URL: ws://[evcc-adresse]:8887/ (Verbindung über das lokale Netzwerk)
+  * Ladepunktidentität: beliebiger Wert (z.B. die Seriennummer der Box), der als *stationid* verwendet wird
+  * Passwort: leer lassen
+
 render:
   - default: |
       type: template
diff --git a/templates/docs/meter/kostal-piko-mp-plus_1.yaml b/templates/docs/meter/kostal-piko-mp-plus_1.yaml
new file mode 100644
index 00000000..304a091b
--- /dev/null
+++ b/templates/docs/meter/kostal-piko-mp-plus_1.yaml
@@ -0,0 +1,10 @@
+product:
+  brand: Steca
+  description: coolcept fleX
+render:
+  - usage: pv
+    default: |
+      type: template
+      template: kostal-piko-mp-plus
+      usage: pv
+      host: 192.0.2.2 # IP-Adresse oder Hostname
diff --git a/templates/docs/meter/mtec-eb-gen2_0.yaml b/templates/docs/meter/mtec-eb-gen2_0.yaml
new file mode 100644
index 00000000..5f76fb89
--- /dev/null
+++ b/templates/docs/meter/mtec-eb-gen2_0.yaml
@@ -0,0 +1,58 @@
+product:
+  brand: M-TEC
+  description: Energy Butler GEN2
+render:
+  - usage: grid
+    default: |
+      type: template
+      template: mtec-eb-gen2
+      usage: grid
+
+      # RS485 via adapter (Modbus RTU)
+      modbus: rs485serial
+      id: 1
+      device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse
+      baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200
+      comset: "8N1" # Kommunikationsparameter für den Adapter
+
+      # RS485 via TCP/IP (Modbus RTU)
+      modbus: rs485tcpip
+      id: 1
+      host: 192.0.2.2 # Hostname
+      port: 502 # Port
+  - usage: pv
+    default: |
+      type: template
+      template: mtec-eb-gen2
+      usage: pv
+
+      # RS485 via adapter (Modbus RTU)
+      modbus: rs485serial
+      id: 1
+      device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse
+      baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200
+      comset: "8N1" # Kommunikationsparameter für den Adapter
+
+      # RS485 via TCP/IP (Modbus RTU)
+      modbus: rs485tcpip
+      id: 1
+      host: 192.0.2.2 # Hostname
+      port: 502 # Port
+  - usage: battery
+    default: |
+      type: template
+      template: mtec-eb-gen2
+      usage: battery
+
+      # RS485 via adapter (Modbus RTU)
+      modbus: rs485serial
+      id: 1
+      device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse
+      baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200
+      comset: "8N1" # Kommunikationsparameter für den Adapter
+
+      # RS485 via TCP/IP (Modbus RTU)
+      modbus: rs485tcpip
+      id: 1
+      host: 192.0.2.2 # Hostname
+      port: 502 # Port
diff --git a/templates/docs/meter/mtec-eb-gen3_0.yaml b/templates/docs/meter/mtec-eb-gen3_0.yaml
new file mode 100644
index 00000000..850d6ee2
--- /dev/null
+++ b/templates/docs/meter/mtec-eb-gen3_0.yaml
@@ -0,0 +1,58 @@
+product:
+  brand: M-TEC
+  description: Energy Butler GEN3
+render:
+  - usage: grid
+    default: |
+      type: template
+      template: mtec-eb-gen3
+      usage: grid
+
+      # RS485 via adapter (Modbus RTU)
+      modbus: rs485serial
+      id: 1
+      device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse
+      baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200
+      comset: "8N1" # Kommunikationsparameter für den Adapter
+
+      # RS485 via TCP/IP (Modbus RTU)
+      modbus: rs485tcpip
+      id: 1
+      host: 192.0.2.2 # Hostname
+      port: 502 # Port
+  - usage: pv
+    default: |
+      type: template
+      template: mtec-eb-gen3
+      usage: pv
+
+      # RS485 via adapter (Modbus RTU)
+      modbus: rs485serial
+      id: 1
+      device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse
+      baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200
+      comset: "8N1" # Kommunikationsparameter für den Adapter
+
+      # RS485 via TCP/IP (Modbus RTU)
+      modbus: rs485tcpip
+      id: 1
+      host: 192.0.2.2 # Hostname
+      port: 502 # Port
+  - usage: battery
+    default: |
+      type: template
+      template: mtec-eb-gen3
+      usage: battery
+
+      # RS485 via adapter (Modbus RTU)
+      modbus: rs485serial
+      id: 1
+      device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse
+      baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200
+      comset: "8N1" # Kommunikationsparameter für den Adapter
+
+      # RS485 via TCP/IP (Modbus RTU)
+      modbus: rs485tcpip
+      id: 1
+      host: 192.0.2.2 # Hostname
+      port: 502 # Port
diff --git a/templates/docs/meter/sonnenbatterie-eco56_0.yaml b/templates/docs/meter/sonnenbatterie-eco56_0.yaml
new file mode 100644
index 00000000..32b4bb75
--- /dev/null
+++ b/templates/docs/meter/sonnenbatterie-eco56_0.yaml
@@ -0,0 +1,44 @@
+product:
+  brand: Sonnen
+  description: comfort, eco 5, eco 6, oem 6.5
+render:
+  - usage: grid
+    default: |
+      type: template
+      template: sonnenbatterie-eco56
+      usage: grid
+      host: 192.0.2.2 # IP-Adresse oder Hostname
+      port: 7979 # Port (Optional)
+    advanced: |
+      type: template
+      template: sonnenbatterie-eco56
+      usage: grid
+      host: 192.0.2.2 # IP-Adresse oder Hostname
+      port: 7979 # Port (Optional)
+  - usage: pv
+    default: |
+      type: template
+      template: sonnenbatterie-eco56
+      usage: pv
+      host: 192.0.2.2 # IP-Adresse oder Hostname
+      port: 7979 # Port (Optional)
+    advanced: |
+      type: template
+      template: sonnenbatterie-eco56
+      usage: pv
+      host: 192.0.2.2 # IP-Adresse oder Hostname
+      port: 7979 # Port (Optional)
+  - usage: battery
+    default: |
+      type: template
+      template: sonnenbatterie-eco56
+      usage: battery
+      host: 192.0.2.2 # IP-Adresse oder Hostname
+      port: 7979 # Port (Optional)
+    advanced: |
+      type: template
+      template: sonnenbatterie-eco56
+      usage: battery
+      host: 192.0.2.2 # IP-Adresse oder Hostname
+      port: 7979 # Port (Optional)
+      capacity: 50 # Akkukapazität in kWh (Optional)
diff --git a/templates/docs/meter/youless_0.yaml b/templates/docs/meter/youless_0.yaml
new file mode 100644
index 00000000..ee9f7460
--- /dev/null
+++ b/templates/docs/meter/youless_0.yaml
@@ -0,0 +1,10 @@
+product:
+  brand: Youless
+  description: Energy Monitor
+render:
+  - usage: grid
+    default: |
+      type: template
+      template: youless
+      usage: grid
+      host: 192.0.2.2 # IP-Adresse oder Hostname
diff --git a/templates/docs/vehicle/cupra_0.yaml b/templates/docs/vehicle/cupra_0.yaml
index b577cb02..c5997bf2 100644
--- a/templates/docs/vehicle/cupra_0.yaml
+++ b/templates/docs/vehicle/cupra_0.yaml
@@ -1,6 +1,6 @@
 product:
   brand: Seat
-  description: Cupra Born, My Cupra
+  description: CupraConnect Gen4 (Born)
 render:
   - default: |
       type: template
diff --git a/templates/docs/vehicle/offline_0.yaml b/templates/docs/vehicle/offline_0.yaml
index d97bed53..407e748f 100644
--- a/templates/docs/vehicle/offline_0.yaml
+++ b/templates/docs/vehicle/offline_0.yaml
@@ -15,10 +15,6 @@ render:
       capacity: 50 # Akkukapazität in kWh (Optional)
       phases: 3 # Die maximale Anzahl der Phasen welche genutzt werden können (Optional)
       mode: # Möglich sind Off, Now, MinPV und PV, oder leer wenn keiner definiert werden soll (Optional)
-      minCurrent: 6 # Definiert die minimale Stromstärke pro angeschlossener Phase mit welcher das Fahrzeug geladen werden soll (Optional)
-      maxCurrent: 16 # Definiert die maximale Stromstärke pro angeschlossener Phase mit welcher das Fahrzeug geladen werden soll (Optional)
-      identifiers: # Kann meist erst später eingetragen werden, siehe: https://docs.evcc.io/docs/guides/vehicles/#erkennung-des-fahrzeugs-an-der-wallbox (Optional)
-      mode: # Möglich sind Off, Now, MinPV und PV, oder leer wenn keiner definiert werden soll (Optional)
       minSoc: 25 # Ladung mit maximaler Geschwindigkeit bis zu dem angegeben Ladestand unabhängig PV-Erzeugung, wenn der Lademodus nicht auf 'Aus' steht (Optional)
       targetSoc: 80 # Bis zu welchem Ladestand (Soc) soll das Fahrzeug geladen werden (Optional)
       minCurrent: 6 # Definiert die minimale Stromstärke pro angeschlossener Phase mit welcher das Fahrzeug geladen werden soll (Optional)
diff --git a/templates/docs/vehicle/seat_0.yaml b/templates/docs/vehicle/seat_0.yaml
index d82ee71e..2fbbaade 100644
--- a/templates/docs/vehicle/seat_0.yaml
+++ b/templates/docs/vehicle/seat_0.yaml
@@ -1,6 +1,6 @@
 product:
   brand: Seat
-  description: Andere
+  description: CupraConnect Gen3 (Ateca, Leon, Formentor)
 render:
   - default: |
       type: template
diff --git a/templates/evcc.io/brands.json b/templates/evcc.io/brands.json
index 092397b8..ed42d065 100644
--- a/templates/evcc.io/brands.json
+++ b/templates/evcc.io/brands.json
@@ -97,6 +97,7 @@
   "Janitza",
   "Kostal",
   "LG",
+  "M-TEC",
   "my-PV",
   "myStrom",
   "OpenEMS",
@@ -126,6 +127,7 @@
   "VARTA",
   "Victron",
   "Volkszähler",
+  "Youless",
   "ZCS Azzurro"
  ],
  "PVBattery": [
@@ -147,6 +149,7 @@
   "IGEN Tech",
   "Kostal",
   "LG",
+  "M-TEC",
   "myStrom",
   "OpenEMS",
   "Powerfox",
@@ -164,6 +167,7 @@
   "Solarwatt",
   "Solax",
   "Sonnen",
+  "Steca",
   "Sungrow",
   "Sunsynk",
   "Tesla",
diff --git a/util/telemetry/charge.go b/util/telemetry/charge.go
index dde411d9..2822a2c5 100644
--- a/util/telemetry/charge.go
+++ b/util/telemetry/charge.go
@@ -92,7 +92,7 @@ func Persist(log *util.Logger) {
 // upload executes the actual upload.
 // Lock must be held when calling upload.
 func upload(log *util.Logger, chargePower, greenPower float64) error {
-	log.DEBUG.Printf("telemetry: charge: Δ%.0f/%.0fWh @ %.0fW", accGreenEnergy*1e3, accChargeEnergy*1e3, chargePower)
+	log.TRACE.Printf("telemetry: charge: Δ%.0f/%.0fWh @ %.0fW", accGreenEnergy*1e3, accChargeEnergy*1e3, chargePower)
 
 	data := InstanceChargeProgress{
 		InstanceID: instanceID,
diff --git a/vehicle/porsche.go b/vehicle/porsche.go
index acb0e5e2..b4288990 100644
--- a/vehicle/porsche.go
+++ b/vehicle/porsche.go
@@ -65,13 +65,7 @@ func NewPorscheFromConfig(other map[string]interface{}) (api.Vehicle, error) {
 		return nil, errors.New("vehicle is not paired with the My Porsche account")
 	}
 
-	// get eMobility capabilities
-	emobIdentity := porsche.NewIdentity(log)
-	if err := emobIdentity.Login(porsche.EmobilityOAuth2Config, cc.User, cc.Password); err != nil {
-		return nil, fmt.Errorf("emobility login failed: %w", err)
-	}
-
-	emobApi := porsche.NewEmobilityAPI(log, emobIdentity)
+	emobApi := porsche.NewEmobilityAPI(log, identity)
 	capabilities, err := emobApi.Capabilities(cc.VIN)
 	if err != nil {
 		return nil, err
diff --git a/vehicle/porsche/api_emobility.go b/vehicle/porsche/api_emobility.go
index 7d8deacc..ba7935dc 100644
--- a/vehicle/porsche/api_emobility.go
+++ b/vehicle/porsche/api_emobility.go
@@ -27,7 +27,7 @@ func NewEmobilityAPI(log *util.Logger, identity oauth2.TokenSource) *EmobilityAP
 			Base:   v.Client.Transport,
 		},
 		Decorator: transport.DecorateHeaders(map[string]string{
-			"apikey": EmobilityOAuth2Config.ClientID,
+			"apikey": ClientID,
 		}),
 	}
 
diff --git a/vehicle/porsche/identity.go b/vehicle/porsche/identity.go
index 09aa7b98..4609d0e1 100644
--- a/vehicle/porsche/identity.go
+++ b/vehicle/porsche/identity.go
@@ -20,28 +20,20 @@ import (
 
 const (
 	OAuthURI = "https://identity.porsche.com"
+	ClientID = "UYsK00My6bCqJdbQhTQ0PbWmcSdIAMig"
 )
 
 // https://identity.porsche.com/.well-known/openid-configuration
 var (
-	endpoint = oauth2.Endpoint{
-		AuthURL:   OAuthURI + "/authorize",
-		TokenURL:  OAuthURI + "/oauth/token",
-		AuthStyle: oauth2.AuthStyleInParams,
-	}
-
 	OAuth2Config = &oauth2.Config{
-		ClientID:    "UYsK00My6bCqJdbQhTQ0PbWmcSdIAMig",
+		ClientID:    ClientID,
 		RedirectURL: "https://my.porsche.com/",
-		Endpoint:    endpoint,
-		Scopes:      []string{"openid", "offline_access"},
-	}
-
-	EmobilityOAuth2Config = &oauth2.Config{
-		ClientID:    OAuth2Config.ClientID,
-		RedirectURL: "https://my.porsche.com/myservices/auth/auth.html",
-		Endpoint:    endpoint,
-		Scopes:      []string{"openid", "offline_access"},
+		Endpoint: oauth2.Endpoint{
+			AuthURL:   OAuthURI + "/authorize",
+			TokenURL:  OAuthURI + "/oauth/token",
+			AuthStyle: oauth2.AuthStyleInParams,
+		},
+		Scopes: []string{"openid", "offline_access"},
 	}
 )
 


Test patch:
diff --git a/assets/js/mixins/formatter.test.js b/assets/js/mixins/formatter.test.js
index b4b804ec..2162c451 100644
--- a/assets/js/mixins/formatter.test.js
+++ b/assets/js/mixins/formatter.test.js
@@ -31,9 +31,10 @@ describe("fmtPricePerKWh", () => {
   test("should format with units", () => {
     expect(fmt.fmtPricePerKWh(0.2, "EUR")).eq("20,0 ct/kWh");
     expect(fmt.fmtPricePerKWh(0.2, "EUR", true)).eq("20,0 ct");
-    expect(fmt.fmtPricePerKWh(0.234, "USD")).eq("23,4 ct/kWh");
+    expect(fmt.fmtPricePerKWh(0.234, "USD")).eq("23,4 ¢/kWh");
     expect(fmt.fmtPricePerKWh(1234, "SEK")).eq("1.234,0 SEK/kWh");
     expect(fmt.fmtPricePerKWh(0.2, "EUR", false, false)).eq("20,0");
+    expect(fmt.fmtPricePerKWh(0.123, "CHF")).eq("12,3 rp/kWh");
   });
 });
 
@@ -41,8 +42,9 @@ describe("pricePerKWhUnit", () => {
   test("should return correct unit", () => {
     expect(fmt.pricePerKWhUnit("EUR")).eq("ct/kWh");
     expect(fmt.pricePerKWhUnit("EUR", true)).eq("ct");
-    expect(fmt.pricePerKWhUnit("USD")).eq("ct/kWh");
+    expect(fmt.pricePerKWhUnit("USD")).eq("¢/kWh");
     expect(fmt.pricePerKWhUnit("SEK")).eq("SEK/kWh");
     expect(fmt.pricePerKWhUnit("SEK", true)).eq("SEK");
+    expect(fmt.pricePerKWhUnit("CHF")).eq("rp/kWh");
   });
 });
diff --git a/core/prioritizer/prioritizer_test.go b/core/prioritizer/prioritizer_test.go
index f3d322c6..cb533718 100644
--- a/core/prioritizer/prioritizer_test.go
+++ b/core/prioritizer/prioritizer_test.go
@@ -11,13 +11,15 @@ import (
 func TestPrioritzer(t *testing.T) {
 	ctrl := gomock.NewController(t)
 
-	p := New()
+	p := New(nil)
 
 	lo := loadpoint.NewMockAPI(ctrl)
-	lo.EXPECT().Priority().Return(0).AnyTimes()
+	lo.EXPECT().Title().AnyTimes()
+	lo.EXPECT().GetPriority().Return(0).AnyTimes()
 
 	hi := loadpoint.NewMockAPI(ctrl)
-	hi.EXPECT().Priority().Return(1).AnyTimes()
+	hi.EXPECT().Title().AnyTimes()
+	hi.EXPECT().GetPriority().Return(1).AnyTimes()
 
 	// no additional power available
 	lo.EXPECT().GetChargePowerFlexibility().Return(300.0)