From 87ec698b966a6e6100435d0799b1f6d552232f82 Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Mon, 10 Feb 2025 16:50:36 +1100
Subject: [PATCH 1/9] fix: unquarantine dylib after download

---
 .../Coder Desktop/Coder_Desktop.entitlements  |  6 ---
 .../Coder Desktop/NetworkExtension.swift      |  9 ++--
 Coder Desktop/Coder Desktop/VPNService.swift  |  9 ++--
 .../Coder Desktop/Views/VPNMenu.swift         | 28 ++++++++----
 .../Coder Desktop/Views/VPNState.swift        | 21 ++++++---
 .../Coder Desktop/XPCInterface.swift          | 35 +++++++++++++++
 .../Coder DesktopTests/VPNStateTests.swift    |  9 ++--
 Coder Desktop/VPN/Manager.swift               | 42 +++++++++++++++++-
 Coder Desktop/VPN/PacketTunnelProvider.swift  | 44 ++++++++++++++-----
 Coder Desktop/VPNLib/Util.swift               |  6 +--
 Coder Desktop/VPNLib/XPC.swift                |  1 +
 Coder Desktop/project.yml                     |  3 --
 12 files changed, 161 insertions(+), 52 deletions(-)

diff --git a/Coder Desktop/Coder Desktop/Coder_Desktop.entitlements b/Coder Desktop/Coder Desktop/Coder_Desktop.entitlements
index 7d90a16..0d80c22 100644
--- a/Coder Desktop/Coder Desktop/Coder_Desktop.entitlements	
+++ b/Coder Desktop/Coder Desktop/Coder_Desktop.entitlements	
@@ -8,15 +8,9 @@
 	</array>
 	<key>com.apple.developer.system-extension.install</key>
 	<true/>
-	<key>com.apple.security.app-sandbox</key>
-	<true/>
 	<key>com.apple.security.application-groups</key>
 	<array>
 		<string>$(TeamIdentifierPrefix)com.coder.Coder-Desktop</string>
 	</array>
-	<key>com.apple.security.files.user-selected.read-only</key>
-	<true/>
-	<key>com.apple.security.network.client</key>
-	<true/>
 </dict>
 </plist>
diff --git a/Coder Desktop/Coder Desktop/NetworkExtension.swift b/Coder Desktop/Coder Desktop/NetworkExtension.swift
index 16d18bb..effd194 100644
--- a/Coder Desktop/Coder Desktop/NetworkExtension.swift	
+++ b/Coder Desktop/Coder Desktop/NetworkExtension.swift	
@@ -24,12 +24,13 @@ enum NetworkExtensionState: Equatable {
 /// An actor that handles configuring, enabling, and disabling the VPN tunnel via the
 /// NetworkExtension APIs.
 extension CoderVPNService {
-    func hasNetworkExtensionConfig() async -> Bool {
+    func loadNetworkExtensionConfig() async {
         do {
-            _ = try await getTunnelManager()
-            return true
+            let tm = try await getTunnelManager()
+            neState = .disabled
+            serverAddress = tm.protocolConfiguration?.serverAddress
         } catch {
-            return false
+            neState = .unconfigured
         }
     }
 
diff --git a/Coder Desktop/Coder Desktop/VPNService.swift b/Coder Desktop/Coder Desktop/VPNService.swift
index 657d994..9d8abb8 100644
--- a/Coder Desktop/Coder Desktop/VPNService.swift	
+++ b/Coder Desktop/Coder Desktop/VPNService.swift	
@@ -63,15 +63,13 @@ final class CoderVPNService: NSObject, VPNService {
     // only stores a weak reference to the delegate.
     var systemExtnDelegate: SystemExtensionDelegate<CoderVPNService>?
 
+    var serverAddress: String?
+
     override init() {
         super.init()
         installSystemExtension()
         Task {
-            neState = if await hasNetworkExtensionConfig() {
-                .disabled
-            } else {
-                .unconfigured
-            }
+            await loadNetworkExtensionConfig()
         }
         xpc.connect()
         xpc.getPeerState()
@@ -115,6 +113,7 @@ final class CoderVPNService: NSObject, VPNService {
     func configureTunnelProviderProtocol(proto: NETunnelProviderProtocol?) {
         Task {
             if let proto {
+                serverAddress = proto.serverAddress
                 await configureNetworkExtension(proto: proto)
                 // this just configures the VPN, it doesn't enable it
                 tunnelState = .disabled
diff --git a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift
index 26266c8..759bce8 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
@@ -31,13 +31,7 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
                 Text("Workspace Agents")
                     .font(.headline)
                     .foregroundColor(.gray)
-                if session.hasSession {
-                    VPNState<VPN>()
-                } else {
-                    Text("Sign in to use CoderVPN")
-                        .font(.body)
-                        .foregroundColor(.gray)
-                }
+                VPNState<VPN, S>()
             }.padding([.horizontal, .top], Theme.Size.trayInset)
             Agents<VPN, S>()
             // Trailing stack
@@ -52,7 +46,15 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
                     }.buttonStyle(.plain)
                     TrayDivider()
                 }
-                AuthButton<VPN, S>()
+                if vpn.state == .failed(.systemExtensionError(.needsUserApproval)) {
+                    Button {
+                        openSystemExtensionSettings()
+                    } label: {
+                        ButtonRowView { Text("Open System Preferences") }
+                    }.buttonStyle(.plain)
+                } else {
+                    AuthButton<VPN, S>()
+                }
                 Button {
                     openSettings()
                     appActivate()
@@ -84,10 +86,18 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
     private var vpnDisabled: Bool {
         !session.hasSession ||
             vpn.state == .connecting ||
-            vpn.state == .disconnecting
+            vpn.state == .disconnecting ||
+            vpn.state == .failed(.systemExtensionError(.needsUserApproval))
     }
 }
 
+func openSystemExtensionSettings() {
+    // TODO: Check this still works in a new macOS version
+    // https://gist.github.com/rmcdongit/f66ff91e0dad78d4d6346a75ded4b751?permalink_comment_id=5261757
+    // swiftlint:disable:next line_length
+    NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.ExtensionsPreferences?extensionPointIdentifier=com.apple.system_extension.network_extension.extension-point")!)
+}
+
 #Preview {
     VPNMenu<PreviewVPN, PreviewSession>().frame(width: 256)
         .environmentObject(PreviewVPN())
diff --git a/Coder Desktop/Coder Desktop/Views/VPNState.swift b/Coder Desktop/Coder Desktop/Views/VPNState.swift
index 1710203..706b8cf 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNState.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNState.swift	
@@ -1,18 +1,27 @@
 import SwiftUI
 
-struct VPNState<VPN: VPNService>: View {
+struct VPNState<VPN: VPNService, S: Session>: View {
     @EnvironmentObject var vpn: VPN
+    @EnvironmentObject var session: S
 
     let inspection = Inspection<Self>()
 
     var body: some View {
         Group {
-            switch vpn.state {
-            case .disabled:
-                Text("Enable CoderVPN to see agents")
+            switch (vpn.state, session.hasSession) {
+            case (.failed(.systemExtensionError(.needsUserApproval)), _):
+                Text("Awaiting System Extension Approval")
+                    .font(.body)
+                    .foregroundStyle(.gray)
+            case (_, false):
+                Text("Sign in to use CoderVPN")
                     .font(.body)
                     .foregroundColor(.gray)
-            case .connecting, .disconnecting:
+            case (.disabled, _):
+                Text("Enable CoderVPN to see agents")
+                    .font(.body)
+                    .foregroundStyle(.gray)
+            case (.connecting, _), (.disconnecting, _):
                 HStack {
                     Spacer()
                     ProgressView(
@@ -20,7 +29,7 @@ struct VPNState<VPN: VPNService>: View {
                     ).padding()
                     Spacer()
                 }
-            case let .failed(vpnErr):
+            case let (.failed(vpnErr), _):
                 Text("\(vpnErr.description)")
                     .font(.headline)
                     .foregroundColor(.red)
diff --git a/Coder Desktop/Coder Desktop/XPCInterface.swift b/Coder Desktop/Coder Desktop/XPCInterface.swift
index 74baab5..73586ca 100644
--- a/Coder Desktop/Coder Desktop/XPCInterface.swift	
+++ b/Coder Desktop/Coder Desktop/XPCInterface.swift	
@@ -64,4 +64,39 @@ import VPNLib
             svc.onExtensionPeerUpdate(data)
         }
     }
+
+    // The NE has verified the dylib and knows better than Gatekeeper
+    func removeQuarantine(path: String, reply: @escaping (Bool) -> Void) {
+        let reply = CallbackWrapper(reply)
+        Task { @MainActor in
+            let prompt = """
+            Coder Desktop wants to execute code downloaded from \
+            \(svc.serverAddress ?? "the Coder deployment"). The code has been \
+            verified to be signed by Coder.
+            """
+            let source = """
+            do shell script "xattr -d com.apple.quarantine \(path)" \
+            with prompt "\(prompt)" \
+            with administrator privileges
+            """
+            let success = await withCheckedContinuation { continuation in
+                guard let script = NSAppleScript(source: source) else {
+                    continuation.resume(returning: false)
+                    return
+                }
+                // Run on a background thread
+                Task.detached {
+                    var error: NSDictionary?
+                    script.executeAndReturnError(&error)
+                    if let error {
+                        self.logger.error("AppleScript error: \(error)")
+                        continuation.resume(returning: false)
+                    } else {
+                        continuation.resume(returning: true)
+                    }
+                }
+            }
+            reply(success)
+        }
+    }
 }
diff --git a/Coder Desktop/Coder DesktopTests/VPNStateTests.swift b/Coder Desktop/Coder DesktopTests/VPNStateTests.swift
index 4d630cd..298bacd 100644
--- a/Coder Desktop/Coder DesktopTests/VPNStateTests.swift	
+++ b/Coder Desktop/Coder DesktopTests/VPNStateTests.swift	
@@ -7,13 +7,16 @@ import ViewInspector
 @Suite(.timeLimit(.minutes(1)))
 struct VPNStateTests {
     let vpn: MockVPNService
-    let sut: VPNState<MockVPNService>
+    let session: MockSession
+    let sut: VPNState<MockVPNService, MockSession>
     let view: any View
 
     init() {
         vpn = MockVPNService()
-        sut = VPNState<MockVPNService>()
-        view = sut.environmentObject(vpn)
+        sut = VPNState<MockVPNService, MockSession>()
+        session = MockSession()
+        session.hasSession = true
+        view = sut.environmentObject(vpn).environmentObject(session)
     }
 
     @Test
diff --git a/Coder Desktop/VPN/Manager.swift b/Coder Desktop/VPN/Manager.swift
index c938818..13afbd0 100644
--- a/Coder Desktop/VPN/Manager.swift	
+++ b/Coder Desktop/VPN/Manager.swift	
@@ -46,6 +46,11 @@ actor Manager {
         } catch {
             throw .validation(error)
         }
+
+        // HACK: The downloaded dylib may be quarantined, but we've validated it's signature
+        // so it's safe to execute. However, this SE must be sandboxed, so we defer to the app.
+        try await removeQuarantine(dest)
+
         do {
             try tunnelHandle = TunnelHandle(dylibPath: dest)
         } catch {
@@ -85,7 +90,13 @@ actor Manager {
         } catch {
             logger.error("tunnel read loop failed: \(error.localizedDescription, privacy: .public)")
             try await tunnelHandle.close()
-            ptp.cancelTunnelWithError(error)
+            ptp.cancelTunnelWithError(
+                NSError(
+                    domain: "\(Bundle.main.bundleIdentifier!).Manager",
+                    code: -1,
+                    userInfo: [NSLocalizedDescriptionKey: "Tunnel read loop failed: \(error.localizedDescription)"]
+                )
+            )
             return
         }
         logger.info("tunnel read loop exited")
@@ -227,6 +238,9 @@ enum ManagerError: Error {
     case serverInfo(String)
     case errorResponse(msg: String)
     case noTunnelFileDescriptor
+    case noApp
+    case permissionDenied
+    case tunnelFail(any Error)
 
     var description: String {
         switch self {
@@ -248,6 +262,12 @@ enum ManagerError: Error {
             msg
         case .noTunnelFileDescriptor:
             "Could not find a tunnel file descriptor"
+        case .noApp:
+            "The VPN must be started with the app open during first-time setup."
+        case .permissionDenied:
+            "Permission was not granted to execute the CoderVPN dylib"
+        case let .tunnelFail(err):
+            "Failed to communicate with dylib over tunnel: \(err)"
         }
     }
 }
@@ -272,3 +292,23 @@ func writeVpnLog(_ log: Vpn_Log) {
     let fields = log.fields.map { "\($0.name): \($0.value)" }.joined(separator: ", ")
     logger.log(level: level, "\(log.message, privacy: .public): \(fields, privacy: .public)")
 }
+
+private func removeQuarantine(_ dest: URL) async throws(ManagerError) {
+    var flag: AnyObject?
+    let file = NSURL(fileURLWithPath: dest.path)
+    try? file.getResourceValue(&flag, forKey: kCFURLQuarantinePropertiesKey as URLResourceKey)
+    if flag != nil {
+        guard let conn = globalXPCListenerDelegate.conn else {
+            throw .noApp
+        }
+        // Wait for unsandboxed app to accept our file
+        let success = await withCheckedContinuation { [dest] continuation in
+            conn.removeQuarantine(path: dest.path) { success in
+                continuation.resume(returning: success)
+            }
+        }
+        if !success {
+            throw .permissionDenied
+        }
+    }
+}
diff --git a/Coder Desktop/VPN/PacketTunnelProvider.swift b/Coder Desktop/VPN/PacketTunnelProvider.swift
index 3cad498..71304dd 100644
--- a/Coder Desktop/VPN/PacketTunnelProvider.swift	
+++ b/Coder Desktop/VPN/PacketTunnelProvider.swift	
@@ -43,26 +43,45 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
         return nil
     }
 
+    // swiftlint:disable:next function_body_length
     override func startTunnel(
         options _: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void
     ) {
         logger.info("startTunnel called")
         guard manager == nil else {
             logger.error("startTunnel called with non-nil Manager")
-            completionHandler(PTPError.alreadyRunning)
+            completionHandler(
+                NSError(
+                    domain: "\(Bundle.main.bundleIdentifier!).PTP",
+                    code: -1,
+                    userInfo: [NSLocalizedDescriptionKey: "Already running"]
+                )
+            )
             return
         }
         guard let proto = protocolConfiguration as? NETunnelProviderProtocol,
               let baseAccessURL = proto.serverAddress
         else {
             logger.error("startTunnel called with nil protocolConfiguration")
-            completionHandler(PTPError.missingConfiguration)
+            completionHandler(
+                NSError(
+                    domain: "\(Bundle.main.bundleIdentifier!).PTP",
+                    code: -1,
+                    userInfo: [NSLocalizedDescriptionKey: "Missing Configuration"]
+                )
+            )
             return
         }
         // HACK: We can't write to the system keychain, and the NE can't read the user keychain.
         guard let token = proto.providerConfiguration?["token"] as? String else {
             logger.error("startTunnel called with nil token")
-            completionHandler(PTPError.missingToken)
+            completionHandler(
+                NSError(
+                    domain: "\(Bundle.main.bundleIdentifier!).PTP",
+                    code: -1,
+                    userInfo: [NSLocalizedDescriptionKey: "Missing Token"]
+                )
+            )
             return
         }
         logger.debug("retrieved token & access URL")
@@ -70,7 +89,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
         Task {
             do throws(ManagerError) {
                 logger.debug("creating manager")
-                manager = try await Manager(
+                let manager = try await Manager(
                     with: self,
                     cfg: .init(
                         apiToken: token, serverUrl: .init(string: baseAccessURL)!
@@ -78,12 +97,19 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
                 )
                 globalXPCListenerDelegate.vpnXPCInterface.manager = manager
                 logger.debug("starting vpn")
-                try await manager!.startVPN()
+                try await manager.startVPN()
                 logger.info("vpn started")
+                self.manager = manager
                 completionHandler(nil)
             } catch {
                 logger.error("error starting manager: \(error.description, privacy: .public)")
-                completionHandler(error as NSError)
+                completionHandler(
+                    NSError(
+                        domain: "\(Bundle.main.bundleIdentifier!).Manager",
+                        code: -1,
+                        userInfo: [NSLocalizedDescriptionKey: error.description]
+                    )
+                )
             }
         }
     }
@@ -152,9 +178,3 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
         try await setTunnelNetworkSettings(currentSettings)
     }
 }
-
-enum PTPError: Error {
-    case alreadyRunning
-    case missingConfiguration
-    case missingToken
-}
diff --git a/Coder Desktop/VPNLib/Util.swift b/Coder Desktop/VPNLib/Util.swift
index ff31e4f..e471633 100644
--- a/Coder Desktop/VPNLib/Util.swift	
+++ b/Coder Desktop/VPNLib/Util.swift	
@@ -1,11 +1,11 @@
 public struct CallbackWrapper<T, U>: @unchecked Sendable {
-    private let block: (T?) -> U
+    private let block: (T) -> U
 
-    public init(_ block: @escaping (T?) -> U) {
+    public init(_ block: @escaping (T) -> U) {
         self.block = block
     }
 
-    public func callAsFunction(_ error: T?) -> U {
+    public func callAsFunction(_ error: T) -> U {
         block(error)
     }
 }
diff --git a/Coder Desktop/VPNLib/XPC.swift b/Coder Desktop/VPNLib/XPC.swift
index eda8ab0..dc79651 100644
--- a/Coder Desktop/VPNLib/XPC.swift	
+++ b/Coder Desktop/VPNLib/XPC.swift	
@@ -10,4 +10,5 @@ import Foundation
 @objc public protocol VPNXPCClientCallbackProtocol {
     // data is a serialized `Vpn_PeerUpdate`
     func onPeerUpdate(_ data: Data)
+    func removeQuarantine(path: String, reply: @escaping (Bool) -> Void)
 }
diff --git a/Coder Desktop/project.yml b/Coder Desktop/project.yml
index 255bc53..54ce06a 100644
--- a/Coder Desktop/project.yml	
+++ b/Coder Desktop/project.yml	
@@ -116,9 +116,6 @@ targets:
         com.apple.developer.networking.networkextension:
           - packet-tunnel-provider
         com.apple.developer.system-extension.install: true
-        com.apple.security.app-sandbox: true
-        com.apple.security.files.user-selected.read-only: true
-        com.apple.security.network.client: true
         com.apple.security.application-groups:
           - $(TeamIdentifierPrefix)com.coder.Coder-Desktop
     settings:

From 024d7e3d7989dba236c0cf871b3ce7133d6e7a44 Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Mon, 10 Feb 2025 19:18:40 +1100
Subject: [PATCH 2/9] capitalization

---
 Coder Desktop/Coder Desktop/Views/AuthButton.swift  | 2 +-
 Coder Desktop/Coder Desktop/Views/VPNMenu.swift     | 2 +-
 Coder Desktop/Coder Desktop/Views/VPNState.swift    | 2 +-
 Coder Desktop/Coder DesktopTests/VPNMenuTests.swift | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Coder Desktop/Coder Desktop/Views/AuthButton.swift b/Coder Desktop/Coder Desktop/Views/AuthButton.swift
index cfab088..de10208 100644
--- a/Coder Desktop/Coder Desktop/Views/AuthButton.swift	
+++ b/Coder Desktop/Coder Desktop/Views/AuthButton.swift	
@@ -17,7 +17,7 @@ struct AuthButton<VPN: VPNService, S: Session>: View {
             }
         } label: {
             ButtonRowView {
-                Text(session.hasSession ? "Sign Out" : "Sign In")
+                Text(session.hasSession ? "Sign out" : "Sign in")
             }
         }.buttonStyle(.plain)
     }
diff --git a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift
index 759bce8..9137ac5 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
@@ -50,7 +50,7 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
                     Button {
                         openSystemExtensionSettings()
                     } label: {
-                        ButtonRowView { Text("Open System Preferences") }
+                        ButtonRowView { Text("Approve in System Settings") }
                     }.buttonStyle(.plain)
                 } else {
                     AuthButton<VPN, S>()
diff --git a/Coder Desktop/Coder Desktop/Views/VPNState.swift b/Coder Desktop/Coder Desktop/Views/VPNState.swift
index 706b8cf..4afc6c2 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNState.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNState.swift	
@@ -10,7 +10,7 @@ struct VPNState<VPN: VPNService, S: Session>: View {
         Group {
             switch (vpn.state, session.hasSession) {
             case (.failed(.systemExtensionError(.needsUserApproval)), _):
-                Text("Awaiting System Extension Approval")
+                Text("Awaiting System Extension approval")
                     .font(.body)
                     .foregroundStyle(.gray)
             case (_, false):
diff --git a/Coder Desktop/Coder DesktopTests/VPNMenuTests.swift b/Coder Desktop/Coder DesktopTests/VPNMenuTests.swift
index 4b446ac..b0484a9 100644
--- a/Coder Desktop/Coder DesktopTests/VPNMenuTests.swift	
+++ b/Coder Desktop/Coder DesktopTests/VPNMenuTests.swift	
@@ -27,7 +27,7 @@ struct VPNMenuTests {
                 let toggle = try view.find(ViewType.Toggle.self)
                 #expect(toggle.isDisabled())
                 #expect(throws: Never.self) { try view.find(text: "Sign in to use CoderVPN") }
-                #expect(throws: Never.self) { try view.find(button: "Sign In") }
+                #expect(throws: Never.self) { try view.find(button: "Sign in") }
             }
         }
     }

From e64ea22eeb66dacc3323fc757839f391ddbc8dbf Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Tue, 11 Feb 2025 22:10:58 +1100
Subject: [PATCH 3/9] review

---
 .../Coder Desktop/Views/VPNMenu.swift         |  3 +-
 Coder Desktop/VPN/Manager.swift               |  6 +---
 Coder Desktop/VPN/PacketTunnelProvider.swift  | 31 +++----------------
 Coder Desktop/VPNLib/Util.swift               |  8 +++++
 4 files changed, 15 insertions(+), 33 deletions(-)

diff --git a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift
index 9137ac5..3f253e1 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
@@ -92,8 +92,9 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
 }
 
 func openSystemExtensionSettings() {
-    // TODO: Check this still works in a new macOS version
+    // Sourced from:
     // https://gist.github.com/rmcdongit/f66ff91e0dad78d4d6346a75ded4b751?permalink_comment_id=5261757
+    // We'll need to ensure this continues to work in future macOS versions
     // swiftlint:disable:next line_length
     NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.ExtensionsPreferences?extensionPointIdentifier=com.apple.system_extension.network_extension.extension-point")!)
 }
diff --git a/Coder Desktop/VPN/Manager.swift b/Coder Desktop/VPN/Manager.swift
index 13afbd0..58a65b5 100644
--- a/Coder Desktop/VPN/Manager.swift	
+++ b/Coder Desktop/VPN/Manager.swift	
@@ -91,11 +91,7 @@ actor Manager {
             logger.error("tunnel read loop failed: \(error.localizedDescription, privacy: .public)")
             try await tunnelHandle.close()
             ptp.cancelTunnelWithError(
-                NSError(
-                    domain: "\(Bundle.main.bundleIdentifier!).Manager",
-                    code: -1,
-                    userInfo: [NSLocalizedDescriptionKey: "Tunnel read loop failed: \(error.localizedDescription)"]
-                )
+                makeNSError(suffix: "Manager", desc: "Tunnel read loop failed: \(error.localizedDescription)")
             )
             return
         }
diff --git a/Coder Desktop/VPN/PacketTunnelProvider.swift b/Coder Desktop/VPN/PacketTunnelProvider.swift
index 71304dd..0102295 100644
--- a/Coder Desktop/VPN/PacketTunnelProvider.swift	
+++ b/Coder Desktop/VPN/PacketTunnelProvider.swift	
@@ -43,45 +43,26 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
         return nil
     }
 
-    // swiftlint:disable:next function_body_length
     override func startTunnel(
         options _: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void
     ) {
         logger.info("startTunnel called")
         guard manager == nil else {
             logger.error("startTunnel called with non-nil Manager")
-            completionHandler(
-                NSError(
-                    domain: "\(Bundle.main.bundleIdentifier!).PTP",
-                    code: -1,
-                    userInfo: [NSLocalizedDescriptionKey: "Already running"]
-                )
-            )
+            completionHandler(makeNSError(suffix: "PTP", desc: "Already running"))
             return
         }
         guard let proto = protocolConfiguration as? NETunnelProviderProtocol,
               let baseAccessURL = proto.serverAddress
         else {
             logger.error("startTunnel called with nil protocolConfiguration")
-            completionHandler(
-                NSError(
-                    domain: "\(Bundle.main.bundleIdentifier!).PTP",
-                    code: -1,
-                    userInfo: [NSLocalizedDescriptionKey: "Missing Configuration"]
-                )
-            )
+            completionHandler(makeNSError(suffix: "PTP", desc: "Missing Configuration"))
             return
         }
         // HACK: We can't write to the system keychain, and the NE can't read the user keychain.
         guard let token = proto.providerConfiguration?["token"] as? String else {
             logger.error("startTunnel called with nil token")
-            completionHandler(
-                NSError(
-                    domain: "\(Bundle.main.bundleIdentifier!).PTP",
-                    code: -1,
-                    userInfo: [NSLocalizedDescriptionKey: "Missing Token"]
-                )
-            )
+            completionHandler(makeNSError(suffix: "PTP", desc: "Missing Token"))
             return
         }
         logger.debug("retrieved token & access URL")
@@ -104,11 +85,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
             } catch {
                 logger.error("error starting manager: \(error.description, privacy: .public)")
                 completionHandler(
-                    NSError(
-                        domain: "\(Bundle.main.bundleIdentifier!).Manager",
-                        code: -1,
-                        userInfo: [NSLocalizedDescriptionKey: error.description]
-                    )
+                    makeNSError(suffix: "Manager", desc: error.description)
                 )
             }
         }
diff --git a/Coder Desktop/VPNLib/Util.swift b/Coder Desktop/VPNLib/Util.swift
index e471633..fd9bbc3 100644
--- a/Coder Desktop/VPNLib/Util.swift	
+++ b/Coder Desktop/VPNLib/Util.swift	
@@ -21,3 +21,11 @@ public struct CompletionWrapper<T>: @unchecked Sendable {
         block()
     }
 }
+
+public func makeNSError(suffix: String, code: Int = -1, desc: String) -> NSError {
+    NSError(
+        domain: "\(Bundle.main.bundleIdentifier!).\(suffix)",
+        code: code,
+        userInfo: [NSLocalizedDescriptionKey: desc]
+    )
+}

From ce1883e1c30dc5493a984d4f58d60806b76ea7a7 Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Mon, 10 Feb 2025 19:06:11 +1100
Subject: [PATCH 4/9] fix: display offline workspaces

---
 .../Preview Content/PreviewVPN.swift          |   4 +-
 .../Coder Desktop/VPNMenuState.swift          | 116 +++++++++++++
 Coder Desktop/Coder Desktop/VPNService.swift  |  64 +------
 Coder Desktop/Coder Desktop/Views/Agent.swift |  99 -----------
 .../Coder Desktop/Views/Agents.swift          |  12 +-
 .../Coder Desktop/Views/VPNMenu.swift         |   2 +-
 .../Coder Desktop/Views/VPNMenuItem.swift     | 105 ++++++++++++
 .../Coder DesktopTests/AgentsTests.swift      |  12 +-
 Coder Desktop/Coder DesktopTests/Util.swift   |   2 +-
 .../VPNMenuStateTests.swift                   | 159 ++++++++++++++++++
 .../Coder DesktopTests/VPNServiceTests.swift  | 116 -------------
 11 files changed, 404 insertions(+), 287 deletions(-)
 create mode 100644 Coder Desktop/Coder Desktop/VPNMenuState.swift
 delete mode 100644 Coder Desktop/Coder Desktop/Views/Agent.swift
 create mode 100644 Coder Desktop/Coder Desktop/Views/VPNMenuItem.swift
 create mode 100644 Coder Desktop/Coder DesktopTests/VPNMenuStateTests.swift
 delete mode 100644 Coder Desktop/Coder DesktopTests/VPNServiceTests.swift

diff --git a/Coder Desktop/Coder Desktop/Preview Content/PreviewVPN.swift b/Coder Desktop/Coder Desktop/Preview Content/PreviewVPN.swift
index 5e66eb7..7e85a86 100644
--- a/Coder Desktop/Coder Desktop/Preview Content/PreviewVPN.swift	
+++ b/Coder Desktop/Coder Desktop/Preview Content/PreviewVPN.swift	
@@ -4,7 +4,7 @@ import SwiftUI
 @MainActor
 final class PreviewVPN: Coder_Desktop.VPNService {
     @Published var state: Coder_Desktop.VPNServiceState = .disabled
-    @Published var agents: [UUID: Coder_Desktop.Agent] = [
+    @Published var menuState: VPNMenuState = .init(agents: [
         UUID(): Agent(id: UUID(), name: "dev", status: .error, copyableDNS: "asdf.coder", wsName: "dogfood2",
                       wsID: UUID()),
         UUID(): Agent(id: UUID(), name: "dev", status: .okay, copyableDNS: "asdf.coder",
@@ -25,7 +25,7 @@ final class PreviewVPN: Coder_Desktop.VPNService {
                       wsID: UUID()),
         UUID(): Agent(id: UUID(), name: "dev", status: .off, copyableDNS: "asdf.coder", wsName: "example",
                       wsID: UUID()),
-    ]
+    ], workspaces: [:])
     let shouldFail: Bool
     let longError = "This is a long error to test the UI with long error messages"
 
diff --git a/Coder Desktop/Coder Desktop/VPNMenuState.swift b/Coder Desktop/Coder Desktop/VPNMenuState.swift
new file mode 100644
index 0000000..866afc2
--- /dev/null
+++ b/Coder Desktop/Coder Desktop/VPNMenuState.swift	
@@ -0,0 +1,116 @@
+import Foundation
+import SwiftUI
+import VPNLib
+
+struct Agent: Identifiable, Equatable, Comparable {
+    let id: UUID
+    let name: String
+    let status: AgentStatus
+    let copyableDNS: String
+    let wsName: String
+    let wsID: UUID
+
+    // Agents are sorted by status, and then by name
+    static func < (lhs: Agent, rhs: Agent) -> Bool {
+        if lhs.status != rhs.status {
+            return lhs.status < rhs.status
+        }
+        return lhs.wsName.localizedCompare(rhs.wsName) == .orderedAscending
+    }
+}
+
+enum AgentStatus: Int, Equatable, Comparable {
+    case okay = 0
+    case warn = 1
+    case error = 2
+    case off = 3
+
+    public var color: Color {
+        switch self {
+        case .okay: .green
+        case .warn: .yellow
+        case .error: .red
+        case .off: .gray
+        }
+    }
+
+    static func < (lhs: AgentStatus, rhs: AgentStatus) -> Bool {
+        lhs.rawValue < rhs.rawValue
+    }
+}
+
+struct Workspace: Identifiable, Equatable, Comparable {
+    let id: UUID
+    let name: String
+    var agents: [UUID]
+
+    static func < (lhs: Workspace, rhs: Workspace) -> Bool {
+        lhs.name.localizedCompare(rhs.name) == .orderedAscending
+    }
+}
+
+struct VPNMenuState {
+    var agents: [UUID: Agent] = [:]
+    var workspaces: [UUID: Workspace] = [:]
+
+    mutating func upsertAgent(_ agent: Vpn_Agent) {
+        guard let id = UUID(uuidData: agent.id) else { return }
+        guard let wsID = UUID(uuidData: agent.workspaceID) else { return }
+        // An existing agent with the same name, belonging to the same workspace
+        // is from a previous workspace build, and should be removed.
+        agents.filter { $0.value.name == agent.name && $0.value.wsID == wsID }
+            .forEach { agents[$0.key] = nil }
+        workspaces[wsID]?.agents.append(id)
+        let wsName = workspaces[wsID]?.name ?? "Unknown Workspace"
+        agents[id] = Agent(
+            id: id,
+            name: agent.name,
+            // If last handshake was not within last five minutes, the agent is unhealthy
+            status: agent.lastHandshake.date > Date.now.addingTimeInterval(-300) ? .okay : .warn,
+            // Choose the shortest hostname, and remove trailing dot if present
+            copyableDNS: agent.fqdn.min(by: { $0.count < $1.count })
+                .map { $0.hasSuffix(".") ? String($0.dropLast()) : $0 } ?? "UNKNOWN",
+            wsName: wsName,
+            wsID: wsID
+        )
+    }
+
+    mutating func deleteAgent(withId id: Data) {
+        guard let id = UUID(uuidData: id) else { return }
+        // Update Workspaces
+        if let agent = agents[id], var ws = workspaces[agent.wsID] {
+            ws.agents.removeAll { $0 == id }
+            workspaces[agent.wsID] = ws
+        }
+        agents[id] = nil
+    }
+
+    mutating func upsertWorkspace(_ workspace: Vpn_Workspace) {
+        guard let id = UUID(uuidData: workspace.id) else { return }
+        workspaces[id] = Workspace(id: id, name: workspace.name, agents: [])
+    }
+
+    mutating func deleteWorkspace(withId id: Data) {
+        guard let wsID = UUID(uuidData: id) else { return }
+        agents.filter { _, value in
+            value.wsID == wsID
+        }.forEach { key, _ in
+            agents[key] = nil
+        }
+        workspaces[wsID] = nil
+    }
+
+    func sorted() -> [VPNMenuItem] {
+        var items = agents.values.map { VPNMenuItem.agent($0) }
+        // Workspaces with no agents are shown as offline
+        items += workspaces.filter { _, value in
+            value.agents.isEmpty
+        }.map { VPNMenuItem.offlineWorkspace(Workspace(id: $0.key, name: $0.value.name, agents: $0.value.agents)) }
+        return items.sorted()
+    }
+
+    mutating func clear() {
+        agents.removeAll()
+        workspaces.removeAll()
+    }
+}
diff --git a/Coder Desktop/Coder Desktop/VPNService.swift b/Coder Desktop/Coder Desktop/VPNService.swift
index 9d8abb8..95aff95 100644
--- a/Coder Desktop/Coder Desktop/VPNService.swift	
+++ b/Coder Desktop/Coder Desktop/VPNService.swift	
@@ -6,7 +6,7 @@ import VPNLib
 @MainActor
 protocol VPNService: ObservableObject {
     var state: VPNServiceState { get }
-    var agents: [UUID: Agent] { get }
+    var menuState: VPNMenuState { get }
     func start() async
     func stop() async
     func configureTunnelProviderProtocol(proto: NETunnelProviderProtocol?)
@@ -41,7 +41,6 @@ enum VPNServiceError: Error, Equatable {
 final class CoderVPNService: NSObject, VPNService {
     var logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "vpn")
     lazy var xpc: VPNXPCInterface = .init(vpn: self)
-    var workspaces: [UUID: String] = [:]
 
     @Published var tunnelState: VPNServiceState = .disabled
     @Published var sysExtnState: SystemExtensionState = .uninstalled
@@ -56,7 +55,7 @@ final class CoderVPNService: NSObject, VPNService {
         return tunnelState
     }
 
-    @Published var agents: [UUID: Agent] = [:]
+    @Published var menuState: VPNMenuState = .init()
 
     // systemExtnDelegate holds a reference to the SystemExtensionDelegate so that it doesn't get
     // garbage collected while the OSSystemExtensionRequest is in flight, since the OS framework
@@ -85,11 +84,6 @@ final class CoderVPNService: NSObject, VPNService {
         NotificationCenter.default.removeObserver(self)
     }
 
-    func clearPeers() {
-        agents = [:]
-        workspaces = [:]
-    }
-
     func start() async {
         switch tunnelState {
         case .disabled, .failed:
@@ -150,7 +144,7 @@ final class CoderVPNService: NSObject, VPNService {
         do {
             let msg = try Vpn_PeerUpdate(serializedBytes: data)
             debugPrint(msg)
-            clearPeers()
+            menuState.clear()
             applyPeerUpdate(with: msg)
         } catch {
             logger.error("failed to decode peer update \(error)")
@@ -159,53 +153,11 @@ final class CoderVPNService: NSObject, VPNService {
 
     func applyPeerUpdate(with update: Vpn_PeerUpdate) {
         // Delete agents
-        update.deletedAgents
-            .compactMap { UUID(uuidData: $0.id) }
-            .forEach { agentID in
-                agents[agentID] = nil
-            }
-        update.deletedWorkspaces
-            .compactMap { UUID(uuidData: $0.id) }
-            .forEach { workspaceID in
-                workspaces[workspaceID] = nil
-                for (id, agent) in agents where agent.wsID == workspaceID {
-                    agents[id] = nil
-                }
-            }
-
-        // Update workspaces
-        for workspaceProto in update.upsertedWorkspaces {
-            if let workspaceID = UUID(uuidData: workspaceProto.id) {
-                workspaces[workspaceID] = workspaceProto.name
-            }
-        }
-
-        for agentProto in update.upsertedAgents {
-            guard let agentID = UUID(uuidData: agentProto.id) else {
-                continue
-            }
-            guard let workspaceID = UUID(uuidData: agentProto.workspaceID) else {
-                continue
-            }
-            let workspaceName = workspaces[workspaceID] ?? "Unknown Workspace"
-            let newAgent = Agent(
-                id: agentID,
-                name: agentProto.name,
-                // If last handshake was not within last five minutes, the agent is unhealthy
-                status: agentProto.lastHandshake.date > Date.now.addingTimeInterval(-300) ? .okay : .off,
-                copyableDNS: agentProto.fqdn.first ?? "UNKNOWN",
-                wsName: workspaceName,
-                wsID: workspaceID
-            )
-
-            // An existing agent with the same name, belonging to the same workspace
-            // is from a previous workspace build, and should be removed.
-            agents
-                .filter { $0.value.name == agentProto.name && $0.value.wsID == workspaceID }
-                .forEach { agents[$0.key] = nil }
-
-            agents[agentID] = newAgent
-        }
+        update.deletedAgents.forEach { menuState.deleteAgent(withId: $0.id) }
+        update.deletedWorkspaces.forEach { menuState.deleteWorkspace(withId: $0.id) }
+        // Upsert workspaces before agents to populate agent workspace names
+        update.upsertedWorkspaces.forEach { menuState.upsertWorkspace($0) }
+        update.upsertedAgents.forEach { menuState.upsertAgent($0) }
     }
 }
 
diff --git a/Coder Desktop/Coder Desktop/Views/Agent.swift b/Coder Desktop/Coder Desktop/Views/Agent.swift
deleted file mode 100644
index a24a5f7..0000000
--- a/Coder Desktop/Coder Desktop/Views/Agent.swift	
+++ /dev/null
@@ -1,99 +0,0 @@
-import SwiftUI
-
-struct Agent: Identifiable, Equatable, Comparable {
-    let id: UUID
-    let name: String
-    let status: AgentStatus
-    let copyableDNS: String
-    let wsName: String
-    let wsID: UUID
-
-    // Agents are sorted by status, and then by name
-    static func < (lhs: Agent, rhs: Agent) -> Bool {
-        if lhs.status != rhs.status {
-            return lhs.status < rhs.status
-        }
-        return lhs.wsName.localizedCompare(rhs.wsName) == .orderedAscending
-    }
-}
-
-enum AgentStatus: Int, Equatable, Comparable {
-    case okay = 0
-    case warn = 1
-    case error = 2
-    case off = 3
-
-    public var color: Color {
-        switch self {
-        case .okay: .green
-        case .warn: .yellow
-        case .error: .red
-        case .off: .gray
-        }
-    }
-
-    static func < (lhs: AgentStatus, rhs: AgentStatus) -> Bool {
-        lhs.rawValue < rhs.rawValue
-    }
-}
-
-struct AgentRowView: View {
-    let agent: Agent
-    let baseAccessURL: URL
-    @State private var nameIsSelected: Bool = false
-    @State private var copyIsSelected: Bool = false
-
-    private var fmtWsName: AttributedString {
-        var formattedName = AttributedString(agent.wsName)
-        formattedName.foregroundColor = .primary
-        var coderPart = AttributedString(".coder")
-        coderPart.foregroundColor = .gray
-        formattedName.append(coderPart)
-        return formattedName
-    }
-
-    private var wsURL: URL {
-        // TODO: CoderVPN currently only supports owned workspaces
-        baseAccessURL.appending(path: "@me").appending(path: agent.wsName)
-    }
-
-    var body: some View {
-        HStack(spacing: 0) {
-            Link(destination: wsURL) {
-                HStack(spacing: Theme.Size.trayPadding) {
-                    ZStack {
-                        Circle()
-                            .fill(agent.status.color.opacity(0.4))
-                            .frame(width: 12, height: 12)
-                        Circle()
-                            .fill(agent.status.color.opacity(1.0))
-                            .frame(width: 7, height: 7)
-                    }
-                    Text(fmtWsName).lineLimit(1).truncationMode(.tail)
-                    Spacer()
-                }.padding(.horizontal, Theme.Size.trayPadding)
-                    .frame(minHeight: 22)
-                    .frame(maxWidth: .infinity, alignment: .leading)
-                    .foregroundStyle(nameIsSelected ? Color.white : .primary)
-                    .background(nameIsSelected ? Color.accentColor.opacity(0.8) : .clear)
-                    .clipShape(.rect(cornerRadius: Theme.Size.rectCornerRadius))
-                    .onHover { hovering in nameIsSelected = hovering }
-                Spacer()
-            }.buttonStyle(.plain)
-            Button {
-                // TODO: Proper clipboard abstraction
-                NSPasteboard.general.setString(agent.copyableDNS, forType: .string)
-            } label: {
-                Image(systemName: "doc.on.doc")
-                    .symbolVariant(.fill)
-                    .padding(3)
-            }.foregroundStyle(copyIsSelected ? Color.white : .primary)
-                .imageScale(.small)
-                .background(copyIsSelected ? Color.accentColor.opacity(0.8) : .clear)
-                .clipShape(.rect(cornerRadius: Theme.Size.rectCornerRadius))
-                .onHover { hovering in copyIsSelected = hovering }
-                .buttonStyle(.plain)
-                .padding(.trailing, Theme.Size.trayMargin)
-        }
-    }
-}
diff --git a/Coder Desktop/Coder Desktop/Views/Agents.swift b/Coder Desktop/Coder Desktop/Views/Agents.swift
index 949ab10..44a8f13 100644
--- a/Coder Desktop/Coder Desktop/Views/Agents.swift	
+++ b/Coder Desktop/Coder Desktop/Views/Agents.swift	
@@ -12,15 +12,15 @@ struct Agents<VPN: VPNService, S: Session>: View {
         Group {
             // Agents List
             if vpn.state == .connected {
-                let sortedAgents = vpn.agents.values.sorted()
-                let visibleData = viewAll ? sortedAgents[...] : sortedAgents.prefix(defaultVisibleRows)
-                ForEach(visibleData, id: \.id) { agent in
-                    AgentRowView(agent: agent, baseAccessURL: session.baseAccessURL!)
+                let items = vpn.menuState.sorted()
+                let visibleItems = viewAll ? items[...] : items.prefix(defaultVisibleRows)
+                ForEach(visibleItems, id: \.id) { agent in
+                    MenuItemView(item: agent, baseAccessURL: session.baseAccessURL!)
                         .padding(.horizontal, Theme.Size.trayMargin)
                 }
-                if vpn.agents.count > defaultVisibleRows {
+                if items.count > defaultVisibleRows {
                     Toggle(isOn: $viewAll) {
-                        Text(viewAll ? "Show Less" : "Show All")
+                        Text(viewAll ? "Show less" : "Show all")
                             .font(.headline)
                             .foregroundColor(.gray)
                             .padding(.horizontal, Theme.Size.trayInset)
diff --git a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift
index 3f253e1..ec63d6e 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
@@ -28,7 +28,7 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
                         .disabled(vpnDisabled)
                 }
                 Divider()
-                Text("Workspace Agents")
+                Text("Workspaces")
                     .font(.headline)
                     .foregroundColor(.gray)
                 VPNState<VPN, S>()
diff --git a/Coder Desktop/Coder Desktop/Views/VPNMenuItem.swift b/Coder Desktop/Coder Desktop/Views/VPNMenuItem.swift
new file mode 100644
index 0000000..6ccdcc0
--- /dev/null
+++ b/Coder Desktop/Coder Desktop/Views/VPNMenuItem.swift	
@@ -0,0 +1,105 @@
+import SwiftUI
+
+// Each row in the workspaces list is an agent or an offline workspace
+enum VPNMenuItem: Equatable, Comparable, Identifiable {
+    case agent(Agent)
+    case offlineWorkspace(Workspace)
+
+    var wsName: String {
+        switch self {
+        case let .agent(agent): agent.wsName
+        case let .offlineWorkspace(workspace): workspace.name
+        }
+    }
+
+    var status: AgentStatus {
+        switch self {
+        case let .agent(agent): agent.status
+        case .offlineWorkspace: .off
+        }
+    }
+
+    var id: UUID {
+        switch self {
+        case let .agent(agent): agent.id
+        case let .offlineWorkspace(workspace): workspace.id
+        }
+    }
+
+    static func < (lhs: VPNMenuItem, rhs: VPNMenuItem) -> Bool {
+        switch (lhs, rhs) {
+        case let (.agent(lhsAgent), .agent(rhsAgent)):
+            lhsAgent < rhsAgent
+        case let (.offlineWorkspace(lhsWorkspace), .offlineWorkspace(rhsWorkspace)):
+            lhsWorkspace < rhsWorkspace
+        // Agents always appear before offline workspaces
+        case (.offlineWorkspace, .agent):
+            false
+        case (.agent, .offlineWorkspace):
+            true
+        }
+    }
+}
+
+struct MenuItemView: View {
+    let item: VPNMenuItem
+    let baseAccessURL: URL
+    @State private var nameIsSelected: Bool = false
+    @State private var copyIsSelected: Bool = false
+
+    private var fmtWsName: AttributedString {
+        var formattedName = AttributedString(item.wsName)
+        formattedName.foregroundColor = .primary
+        var coderPart = AttributedString(".coder")
+        coderPart.foregroundColor = .gray
+        formattedName.append(coderPart)
+        return formattedName
+    }
+
+    private var wsURL: URL {
+        // TODO: CoderVPN currently only supports owned workspaces
+        baseAccessURL.appending(path: "@me").appending(path: item.wsName)
+    }
+
+    var body: some View {
+        HStack(spacing: 0) {
+            Link(destination: wsURL) {
+                HStack(spacing: Theme.Size.trayPadding) {
+                    ZStack {
+                        Circle()
+                            .fill(item.status.color.opacity(0.4))
+                            .frame(width: 12, height: 12)
+                        Circle()
+                            .fill(item.status.color.opacity(1.0))
+                            .frame(width: 7, height: 7)
+                    }
+                    Text(fmtWsName).lineLimit(1).truncationMode(.tail)
+                    Spacer()
+                }.padding(.horizontal, Theme.Size.trayPadding)
+                    .frame(minHeight: 22)
+                    .frame(maxWidth: .infinity, alignment: .leading)
+                    .foregroundStyle(nameIsSelected ? Color.white : .primary)
+                    .background(nameIsSelected ? Color.accentColor.opacity(0.8) : .clear)
+                    .clipShape(.rect(cornerRadius: Theme.Size.rectCornerRadius))
+                    .onHover { hovering in nameIsSelected = hovering }
+                Spacer()
+            }.buttonStyle(.plain)
+            if case let .agent(agent) = item {
+                Button {
+                    NSPasteboard.general.clearContents()
+                    NSPasteboard.general.setString(agent.copyableDNS, forType: .string)
+                } label: {
+                    Image(systemName: "doc.on.doc")
+                        .symbolVariant(.fill)
+                        .padding(3)
+                }.foregroundStyle(copyIsSelected ? Color.white : .primary)
+                    .imageScale(.small)
+                    .background(copyIsSelected ? Color.accentColor.opacity(0.8) : .clear)
+                    .clipShape(.rect(cornerRadius: Theme.Size.rectCornerRadius))
+                    .onHover { hovering in copyIsSelected = hovering }
+                    .buttonStyle(.plain)
+                    .padding(.trailing, Theme.Size.trayMargin)
+            }
+        }
+    }
+}
diff --git a/Coder Desktop/Coder DesktopTests/AgentsTests.swift b/Coder Desktop/Coder DesktopTests/AgentsTests.swift
index 8e06c8d..b93ca2b 100644
--- a/Coder Desktop/Coder DesktopTests/AgentsTests.swift	
+++ b/Coder Desktop/Coder DesktopTests/AgentsTests.swift	
@@ -44,7 +44,7 @@ struct AgentsTests {
     @Test
     func agentsWhenVPNOn() throws {
         vpn.state = .connected
-        vpn.agents = createMockAgents(count: Theme.defaultVisibleAgents + 2)
+        vpn.menuState = .init(agents: createMockAgents(count: Theme.defaultVisibleAgents + 2))
 
         let forEach = try view.inspect().find(ViewType.ForEach.self)
         #expect(forEach.count == Theme.defaultVisibleAgents)
@@ -55,24 +55,24 @@ struct AgentsTests {
     @Test
     func showAllToggle() async throws {
         vpn.state = .connected
-        vpn.agents = createMockAgents(count: 7)
+        vpn.menuState = .init(agents: createMockAgents(count: 7))
 
         try await ViewHosting.host(view) {
             try await sut.inspection.inspect { view in
                 var toggle = try view.find(ViewType.Toggle.self)
-                #expect(try toggle.labelView().text().string() == "Show All")
+                #expect(try toggle.labelView().text().string() == "Show all")
                 #expect(try !toggle.isOn())
 
                 try toggle.tap()
                 toggle = try view.find(ViewType.Toggle.self)
                 var forEach = try view.find(ViewType.ForEach.self)
                 #expect(forEach.count == Theme.defaultVisibleAgents + 2)
-                #expect(try toggle.labelView().text().string() == "Show Less")
+                #expect(try toggle.labelView().text().string() == "Show less")
 
                 try toggle.tap()
                 toggle = try view.find(ViewType.Toggle.self)
                 forEach = try view.find(ViewType.ForEach.self)
-                #expect(try toggle.labelView().text().string() == "Show All")
+                #expect(try toggle.labelView().text().string() == "Show all")
                 #expect(forEach.count == Theme.defaultVisibleAgents)
             }
         }
@@ -81,7 +81,7 @@ struct AgentsTests {
     @Test
     func noToggleFewAgents() throws {
         vpn.state = .connected
-        vpn.agents = createMockAgents(count: 3)
+        vpn.menuState = .init(agents: createMockAgents(count: 3))
 
         #expect(throws: (any Error).self) {
             _ = try view.inspect().find(ViewType.Toggle.self)
diff --git a/Coder Desktop/Coder DesktopTests/Util.swift b/Coder Desktop/Coder DesktopTests/Util.swift
index d224615..84f8821 100644
--- a/Coder Desktop/Coder DesktopTests/Util.swift	
+++ b/Coder Desktop/Coder DesktopTests/Util.swift	
@@ -8,7 +8,7 @@ import ViewInspector
 class MockVPNService: VPNService, ObservableObject {
     @Published var state: Coder_Desktop.VPNServiceState = .disabled
     @Published var baseAccessURL: URL = .init(string: "https://dev.coder.com")!
-    @Published var agents: [UUID: Coder_Desktop.Agent] = [:]
+    @Published var menuState: VPNMenuState = .init()
     var onStart: (() async -> Void)?
     var onStop: (() async -> Void)?
 
diff --git a/Coder Desktop/Coder DesktopTests/VPNMenuStateTests.swift b/Coder Desktop/Coder DesktopTests/VPNMenuStateTests.swift
new file mode 100644
index 0000000..439ebdb
--- /dev/null
+++ b/Coder Desktop/Coder DesktopTests/VPNMenuStateTests.swift	
@@ -0,0 +1,159 @@
+@testable import Coder_Desktop
+import Testing
+@testable import VPNLib
+
+@MainActor
+@Suite
+struct VPNMenuStateTests {
+    var state = VPNMenuState()
+
+    @Test
+    mutating func testUpsertAgent_addsAgent() async throws {
+        let agentID = UUID()
+        let workspaceID = UUID()
+        state.upsertWorkspace(Vpn_Workspace.with { $0.id = workspaceID.uuidData; $0.name = "foo" })
+
+        let agent = Vpn_Agent.with {
+            $0.id = agentID.uuidData
+            $0.workspaceID = workspaceID.uuidData
+            $0.name = "dev"
+            $0.lastHandshake = .init(date: Date.now)
+            $0.fqdn = ["foo.coder"]
+        }
+
+        state.upsertAgent(agent)
+
+        let storedAgent = try #require(state.agents[agentID])
+        #expect(storedAgent.name == "dev")
+        #expect(storedAgent.wsID == workspaceID)
+        #expect(storedAgent.wsName == "foo")
+        #expect(storedAgent.copyableDNS == "foo.coder")
+        #expect(storedAgent.status == .okay)
+    }
+
+    @Test
+    mutating func testDeleteAgent_removesAgent() async throws {
+        let agentID = UUID()
+        let workspaceID = UUID()
+        state.upsertWorkspace(Vpn_Workspace.with { $0.id = workspaceID.uuidData; $0.name = "foo" })
+
+        let agent = Vpn_Agent.with {
+            $0.id = agentID.uuidData
+            $0.workspaceID = workspaceID.uuidData
+            $0.name = "agent1"
+            $0.lastHandshake = .init(date: Date.now)
+            $0.fqdn = ["foo.coder"]
+        }
+
+        state.upsertAgent(agent)
+        state.deleteAgent(withId: agent.id)
+
+        #expect(state.agents[agentID] == nil)
+    }
+
+    @Test
+    mutating func testDeleteWorkspace_removesWorkspaceAndAgents() async throws {
+        let agentID = UUID()
+        let workspaceID = UUID()
+        state.upsertWorkspace(Vpn_Workspace.with { $0.id = workspaceID.uuidData; $0.name = "foo" })
+
+        let agent = Vpn_Agent.with {
+            $0.id = agentID.uuidData
+            $0.workspaceID = workspaceID.uuidData
+            $0.name = "agent1"
+            $0.lastHandshake = .init(date: Date.now)
+            $0.fqdn = ["foo.coder"]
+        }
+
+        state.upsertAgent(agent)
+        state.deleteWorkspace(withId: workspaceID.uuidData)
+
+        #expect(state.agents[agentID] == nil)
+        #expect(state.workspaces[workspaceID] == nil)
+    }
+
+    @Test
+    mutating func testUpsertAgent_unhealthyAgent() async throws {
+        let agentID = UUID()
+        let workspaceID = UUID()
+        state.upsertWorkspace(Vpn_Workspace.with { $0.id = workspaceID.uuidData; $0.name = "foo" })
+
+        let agent = Vpn_Agent.with {
+            $0.id = agentID.uuidData
+            $0.workspaceID = workspaceID.uuidData
+            $0.name = "agent1"
+            $0.lastHandshake = .init(date: Date.now.addingTimeInterval(-600))
+            $0.fqdn = ["foo.coder"]
+        }
+
+        state.upsertAgent(agent)
+
+        let storedAgent = try #require(state.agents[agentID])
+        #expect(storedAgent.status == .warn)
+    }
+
+    @Test
+    mutating func testUpsertAgent_replacesOldAgent() async throws {
+        let workspaceID = UUID()
+        let oldAgentID = UUID()
+        let newAgentID = UUID()
+        state.upsertWorkspace(Vpn_Workspace.with { $0.id = workspaceID.uuidData; $0.name = "foo" })
+
+        let oldAgent = Vpn_Agent.with {
+            $0.id = oldAgentID.uuidData
+            $0.workspaceID = workspaceID.uuidData
+            $0.name = "agent1"
+            $0.lastHandshake = .init(date: Date.now.addingTimeInterval(-600))
+            $0.fqdn = ["foo.coder"]
+        }
+
+        state.upsertAgent(oldAgent)
+
+        let newAgent = Vpn_Agent.with {
+            $0.id = newAgentID.uuidData
+            $0.workspaceID = workspaceID.uuidData
+            $0.name = "agent1" // Same name as old agent
+            $0.lastHandshake = .init(date: Date.now)
+            $0.fqdn = ["foo.coder"]
+        }
+
+        state.upsertAgent(newAgent)
+
+        #expect(state.agents[oldAgentID] == nil)
+        let storedAgent = try #require(state.agents[newAgentID])
+        #expect(storedAgent.name == "agent1")
+        #expect(storedAgent.wsID == workspaceID)
+        #expect(storedAgent.copyableDNS == "foo.coder")
+        #expect(storedAgent.status == .okay)
+    }
+
+    @Test
+    mutating func testUpsertWorkspace_addsOfflineWorkspace() async throws {
+        let workspaceID = UUID()
+        state.upsertWorkspace(Vpn_Workspace.with { $0.id = workspaceID.uuidData; $0.name = "foo" })
+
+        let storedWorkspace = try #require(state.workspaces[workspaceID])
+        #expect(storedWorkspace.name == "foo")
+
+        var output = state.sorted()
+        #expect(output.count == 1)
+        #expect(output[0].id == workspaceID)
+        #expect(output[0].wsName == "foo")
+
+        let agentID = UUID()
+        let agent = Vpn_Agent.with {
+            $0.id = agentID.uuidData
+            $0.workspaceID = workspaceID.uuidData
+            $0.name = "agent1"
+            $0.lastHandshake = .init(date: Date.now.addingTimeInterval(-200))
+            $0.fqdn = ["foo.coder"]
+        }
+        state.upsertAgent(agent)
+
+        output = state.sorted()
+        #expect(output.count == 1)
+        #expect(output[0].id == agentID)
+        #expect(output[0].wsName == "foo")
+        #expect(output[0].status == .okay)
+    }
+}
diff --git a/Coder Desktop/Coder DesktopTests/VPNServiceTests.swift b/Coder Desktop/Coder DesktopTests/VPNServiceTests.swift
deleted file mode 100644
index 9d1370a..0000000
--- a/Coder Desktop/Coder DesktopTests/VPNServiceTests.swift	
+++ /dev/null
@@ -1,116 +0,0 @@
-@testable import Coder_Desktop
-import Testing
-@testable import VPNLib
-
-@MainActor
-@Suite
-struct CoderVPNServiceTests {
-    let service = CoderVPNService()
-
-    init() {
-        service.workspaces = [:]
-        service.agents = [:]
-    }
-
-    @Test
-    func testApplyPeerUpdate_upsertsAgents() async throws {
-        let agentID = UUID()
-        let workspaceID = UUID()
-        service.workspaces[workspaceID] = "foo"
-
-        let update = Vpn_PeerUpdate.with {
-            $0.upsertedAgents = [Vpn_Agent.with {
-                $0.id = agentID.uuidData
-                $0.workspaceID = workspaceID.uuidData
-                $0.name = "dev"
-                $0.lastHandshake = .init(date: Date.now)
-                $0.fqdn = ["foo.coder"]
-            }]
-        }
-
-        service.applyPeerUpdate(with: update)
-
-        let agent = try #require(service.agents[agentID])
-        #expect(agent.name == "dev")
-        #expect(agent.wsID == workspaceID)
-        #expect(agent.wsName == "foo")
-        #expect(agent.copyableDNS == "foo.coder")
-        #expect(agent.status == .okay)
-    }
-
-    @Test
-    func testApplyPeerUpdate_deletesAgentsAndWorkspaces() async throws {
-        let agentID = UUID()
-        let workspaceID = UUID()
-
-        service.agents[agentID] = Agent(
-            id: agentID, name: "agent1", status: .okay,
-            copyableDNS: "foo.coder", wsName: "foo", wsID: workspaceID
-        )
-        service.workspaces[workspaceID] = "foo"
-
-        let update = Vpn_PeerUpdate.with {
-            $0.deletedAgents = [Vpn_Agent.with { $0.id = agentID.uuidData }]
-            $0.deletedWorkspaces = [Vpn_Workspace.with { $0.id = workspaceID.uuidData }]
-        }
-
-        service.applyPeerUpdate(with: update)
-
-        #expect(service.agents[agentID] == nil)
-        #expect(service.workspaces[workspaceID] == nil)
-    }
-
-    @Test
-    func testApplyPeerUpdate_unhealthyAgent() async throws {
-        let agentID = UUID()
-        let workspaceID = UUID()
-        service.workspaces[workspaceID] = "foo"
-
-        let update = Vpn_PeerUpdate.with {
-            $0.upsertedAgents = [Vpn_Agent.with {
-                $0.id = agentID.uuidData
-                $0.workspaceID = workspaceID.uuidData
-                $0.name = "agent1"
-                $0.lastHandshake = .init(date: Date.now.addingTimeInterval(-600))
-                $0.fqdn = ["foo.coder"]
-            }]
-        }
-
-        service.applyPeerUpdate(with: update)
-
-        let agent = try #require(service.agents[agentID])
-        #expect(agent.status == .off)
-    }
-
-    @Test
-    func testApplyPeerUpdate_replaceOldAgent() async throws {
-        let workspaceID = UUID()
-        let oldAgentID = UUID()
-        let newAgentID = UUID()
-        service.workspaces[workspaceID] = "foo"
-
-        service.agents[oldAgentID] = Agent(
-            id: oldAgentID, name: "agent1", status: .off,
-            copyableDNS: "foo.coder", wsName: "foo", wsID: workspaceID
-        )
-
-        let update = Vpn_PeerUpdate.with {
-            $0.upsertedAgents = [Vpn_Agent.with {
-                $0.id = newAgentID.uuidData
-                $0.workspaceID = workspaceID.uuidData
-                $0.name = "agent1" // Same name as old agent
-                $0.lastHandshake = .init(date: Date.now)
-                $0.fqdn = ["foo.coder"]
-            }]
-        }
-
-        service.applyPeerUpdate(with: update)
-
-        #expect(service.agents[oldAgentID] == nil)
-        let newAgent = try #require(service.agents[newAgentID])
-        #expect(newAgent.name == "agent1")
-        #expect(newAgent.wsID == workspaceID)
-        #expect(newAgent.copyableDNS == "foo.coder")
-        #expect(newAgent.status == .okay)
-    }
-}

From 972f269719387557571830c89d75e9226915e3ea Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Wed, 12 Feb 2025 18:08:07 +1100
Subject: [PATCH 5/9] review

---
 Coder Desktop/Coder Desktop/About.swift       |  3 +-
 .../Preview Content/PreviewVPN.swift          | 22 ++---
 .../Coder Desktop/VPNMenuState.swift          | 58 ++++++++----
 .../Coder Desktop/Views/Agents.swift          | 17 +++-
 .../Coder Desktop/Views/ButtonRow.swift       | 11 ++-
 .../Coder Desktop/Views/InvalidAgents.swift   | 56 ++++++++++++
 Coder Desktop/Coder Desktop/Views/Util.swift  |  8 ++
 .../Coder Desktop/Views/VPNMenu.swift         |  4 +-
 .../Coder Desktop/Views/VPNMenuItem.swift     | 25 +++---
 .../Coder Desktop/Views/VPNState.swift        |  2 +-
 .../Coder DesktopTests/AgentsTests.swift      | 89 +++++++++++++++++--
 .../VPNMenuStateTests.swift                   | 60 ++++++++++++-
 .../Coder DesktopTests/VPNStateTests.swift    |  2 +-
 13 files changed, 301 insertions(+), 56 deletions(-)
 create mode 100644 Coder Desktop/Coder Desktop/Views/InvalidAgents.swift

diff --git a/Coder Desktop/Coder Desktop/About.swift b/Coder Desktop/Coder Desktop/About.swift
index 3771175..8849c9b 100644
--- a/Coder Desktop/Coder Desktop/About.swift	
+++ b/Coder Desktop/Coder Desktop/About.swift	
@@ -1,6 +1,7 @@
 import SwiftUI
 
 enum About {
+    public static let repo: String = "https://github.com/coder/coder-desktop-macos"
     private static var credits: NSAttributedString {
         let coder = NSMutableAttributedString(
             string: "Coder.com",
@@ -21,7 +22,7 @@ enum About {
             string: "GitHub",
             attributes: [
                 .foregroundColor: NSColor.labelColor,
-                .link: NSURL(string: "https://github.com/coder/coder-desktop-macos")!,
+                .link: NSURL(string: About.repo)!,
                 .font: NSFont.systemFont(ofSize: NSFont.systemFontSize),
             ]
         )
diff --git a/Coder Desktop/Coder Desktop/Preview Content/PreviewVPN.swift b/Coder Desktop/Coder Desktop/Preview Content/PreviewVPN.swift
index 7e85a86..4faa10f 100644
--- a/Coder Desktop/Coder Desktop/Preview Content/PreviewVPN.swift	
+++ b/Coder Desktop/Coder Desktop/Preview Content/PreviewVPN.swift	
@@ -3,27 +3,27 @@ import SwiftUI
 
 @MainActor
 final class PreviewVPN: Coder_Desktop.VPNService {
-    @Published var state: Coder_Desktop.VPNServiceState = .disabled
+    @Published var state: Coder_Desktop.VPNServiceState = .connected
     @Published var menuState: VPNMenuState = .init(agents: [
-        UUID(): Agent(id: UUID(), name: "dev", status: .error, copyableDNS: "asdf.coder", wsName: "dogfood2",
+        UUID(): Agent(id: UUID(), name: "dev", status: .error, hosts: ["asdf.coder"], wsName: "dogfood2",
                       wsID: UUID()),
-        UUID(): Agent(id: UUID(), name: "dev", status: .okay, copyableDNS: "asdf.coder",
+        UUID(): Agent(id: UUID(), name: "dev", status: .okay, hosts: ["asdf.coder"],
                       wsName: "testing-a-very-long-name", wsID: UUID()),
-        UUID(): Agent(id: UUID(), name: "dev", status: .warn, copyableDNS: "asdf.coder", wsName: "opensrc",
+        UUID(): Agent(id: UUID(), name: "dev", status: .warn, hosts: ["asdf.coder"], wsName: "opensrc",
                       wsID: UUID()),
-        UUID(): Agent(id: UUID(), name: "dev", status: .off, copyableDNS: "asdf.coder", wsName: "gvisor",
+        UUID(): Agent(id: UUID(), name: "dev", status: .off, hosts: ["asdf.coder"], wsName: "gvisor",
                       wsID: UUID()),
-        UUID(): Agent(id: UUID(), name: "dev", status: .off, copyableDNS: "asdf.coder", wsName: "example",
+        UUID(): Agent(id: UUID(), name: "dev", status: .off, hosts: ["asdf.coder"], wsName: "example",
                       wsID: UUID()),
-        UUID(): Agent(id: UUID(), name: "dev", status: .error, copyableDNS: "asdf.coder", wsName: "dogfood2",
+        UUID(): Agent(id: UUID(), name: "dev", status: .error, hosts: ["asdf.coder"], wsName: "dogfood2",
                       wsID: UUID()),
-        UUID(): Agent(id: UUID(), name: "dev", status: .okay, copyableDNS: "asdf.coder",
+        UUID(): Agent(id: UUID(), name: "dev", status: .okay, hosts: ["asdf.coder"],
                       wsName: "testing-a-very-long-name", wsID: UUID()),
-        UUID(): Agent(id: UUID(), name: "dev", status: .warn, copyableDNS: "asdf.coder", wsName: "opensrc",
+        UUID(): Agent(id: UUID(), name: "dev", status: .warn, hosts: ["asdf.coder"], wsName: "opensrc",
                       wsID: UUID()),
-        UUID(): Agent(id: UUID(), name: "dev", status: .off, copyableDNS: "asdf.coder", wsName: "gvisor",
+        UUID(): Agent(id: UUID(), name: "dev", status: .off, hosts: ["asdf.coder"], wsName: "gvisor",
                       wsID: UUID()),
-        UUID(): Agent(id: UUID(), name: "dev", status: .off, copyableDNS: "asdf.coder", wsName: "example",
+        UUID(): Agent(id: UUID(), name: "dev", status: .off, hosts: ["asdf.coder"], wsName: "example",
                       wsID: UUID()),
     ], workspaces: [:])
     let shouldFail: Bool
diff --git a/Coder Desktop/Coder Desktop/VPNMenuState.swift b/Coder Desktop/Coder Desktop/VPNMenuState.swift
index 866afc2..e1a91a0 100644
--- a/Coder Desktop/Coder Desktop/VPNMenuState.swift	
+++ b/Coder Desktop/Coder Desktop/VPNMenuState.swift	
@@ -6,7 +6,7 @@ struct Agent: Identifiable, Equatable, Comparable {
     let id: UUID
     let name: String
     let status: AgentStatus
-    let copyableDNS: String
+    let hosts: [String]
     let wsName: String
     let wsID: UUID
 
@@ -17,6 +17,9 @@ struct Agent: Identifiable, Equatable, Comparable {
         }
         return lhs.wsName.localizedCompare(rhs.wsName) == .orderedAscending
     }
+
+    // Hosts arrive sorted by length, the shortest looks best in the UI.
+    var primaryHost: String? { hosts.first }
 }
 
 enum AgentStatus: Int, Equatable, Comparable {
@@ -42,7 +45,7 @@ enum AgentStatus: Int, Equatable, Comparable {
 struct Workspace: Identifiable, Equatable, Comparable {
     let id: UUID
     let name: String
-    var agents: [UUID]
+    var agents: Set<UUID>
 
     static func < (lhs: Workspace, rhs: Workspace) -> Bool {
         lhs.name.localizedCompare(rhs.name) == .orderedAscending
@@ -52,42 +55,63 @@ struct Workspace: Identifiable, Equatable, Comparable {
 struct VPNMenuState {
     var agents: [UUID: Agent] = [:]
     var workspaces: [UUID: Workspace] = [:]
+    // Upserted agents that don't belong to any known workspace, have no FQDNs,
+    // or have any invalid UUIDs.
+    var invalidAgents: [Vpn_Agent] = []
 
     mutating func upsertAgent(_ agent: Vpn_Agent) {
-        guard let id = UUID(uuidData: agent.id) else { return }
-        guard let wsID = UUID(uuidData: agent.workspaceID) else { return }
+        guard
+            let id = UUID(uuidData: agent.id),
+            let wsID = UUID(uuidData: agent.workspaceID),
+            var workspace = workspaces[wsID],
+            !agent.fqdn.isEmpty
+        else {
+            invalidAgents.append(agent)
+            return
+        }
         // An existing agent with the same name, belonging to the same workspace
         // is from a previous workspace build, and should be removed.
         agents.filter { $0.value.name == agent.name && $0.value.wsID == wsID }
             .forEach { agents[$0.key] = nil }
-        workspaces[wsID]?.agents.append(id)
-        let wsName = workspaces[wsID]?.name ?? "Unknown Workspace"
+        workspace.agents.insert(id)
+        workspaces[wsID] = workspace
+
         agents[id] = Agent(
             id: id,
             name: agent.name,
             // If last handshake was not within last five minutes, the agent is unhealthy
             status: agent.lastHandshake.date > Date.now.addingTimeInterval(-300) ? .okay : .warn,
-            // Choose the shortest hostname, and remove trailing dot if present
-            copyableDNS: agent.fqdn.min(by: { $0.count < $1.count })
-                .map { $0.hasSuffix(".") ? String($0.dropLast()) : $0 } ?? "UNKNOWN",
-            wsName: wsName,
+            // Remove trailing dot if present
+            hosts: agent.fqdn.map { $0.hasSuffix(".") ? String($0.dropLast()) : $0 },
+            wsName: workspace.name,
             wsID: wsID
         )
     }
 
     mutating func deleteAgent(withId id: Data) {
-        guard let id = UUID(uuidData: id) else { return }
+        guard let agentUUID = UUID(uuidData: id) else { return }
         // Update Workspaces
-        if let agent = agents[id], var ws = workspaces[agent.wsID] {
-            ws.agents.removeAll { $0 == id }
+        if let agent = agents[agentUUID], var ws = workspaces[agent.wsID] {
+            ws.agents.remove(agentUUID)
             workspaces[agent.wsID] = ws
         }
-        agents[id] = nil
+        agents[agentUUID] = nil
+        // Remove from invalid agents if present
+        invalidAgents.removeAll { invalidAgent in
+            invalidAgent.id == id
+        }
     }
 
     mutating func upsertWorkspace(_ workspace: Vpn_Workspace) {
-        guard let id = UUID(uuidData: workspace.id) else { return }
-        workspaces[id] = Workspace(id: id, name: workspace.name, agents: [])
+        guard let wsID = UUID(uuidData: workspace.id) else { return }
+        workspaces[wsID] = Workspace(id: wsID, name: workspace.name, agents: [])
+        // Check if we can associate any invalid agents with this workspace
+        invalidAgents.filter { agent in
+            agent.workspaceID == workspace.id
+        }.forEach { agent in
+            invalidAgents.removeAll { $0 == agent }
+            upsertAgent(agent)
+        }
     }
 
     mutating func deleteWorkspace(withId id: Data) {
@@ -100,7 +124,7 @@ struct VPNMenuState {
         workspaces[wsID] = nil
     }
 
-    func sorted() -> [VPNMenuItem] {
+    var sorted: [VPNMenuItem] {
         var items = agents.values.map { VPNMenuItem.agent($0) }
         // Workspaces with no agents are shown as offline
         items += workspaces.filter { _, value in
diff --git a/Coder Desktop/Coder Desktop/Views/Agents.swift b/Coder Desktop/Coder Desktop/Views/Agents.swift
index 44a8f13..933a999 100644
--- a/Coder Desktop/Coder Desktop/Views/Agents.swift	
+++ b/Coder Desktop/Coder Desktop/Views/Agents.swift	
@@ -12,13 +12,24 @@ struct Agents<VPN: VPNService, S: Session>: View {
         Group {
             // Agents List
             if vpn.state == .connected {
-                let items = vpn.menuState.sorted()
-                let visibleItems = viewAll ? items[...] : items.prefix(defaultVisibleRows)
+                let items = vpn.menuState.sorted
+                let visibleOnlineItems = items.prefix(defaultVisibleRows) {
+                    $0.status != .off
+                }
+                let visibleItems = viewAll ? items[...] : visibleOnlineItems
                 ForEach(visibleItems, id: \.id) { agent in
                     MenuItemView(item: agent, baseAccessURL: session.baseAccessURL!)
                         .padding(.horizontal, Theme.Size.trayMargin)
                 }
-                if items.count > defaultVisibleRows {
+                if visibleItems.count == 0 {
+                    Text("No \(items.count > 0 ? "running " : "")workspaces!")
+                        .font(.body)
+                        .foregroundColor(.gray)
+                        .padding(.horizontal, Theme.Size.trayInset)
+                        .padding(.top, 2)
+                }
+                // Only show the toggle if there are more items to show
+                if visibleOnlineItems.count < items.count {
                     Toggle(isOn: $viewAll) {
                         Text(viewAll ? "Show less" : "Show all")
                             .font(.headline)
diff --git a/Coder Desktop/Coder Desktop/Views/ButtonRow.swift b/Coder Desktop/Coder Desktop/Views/ButtonRow.swift
index 088eb13..9dbb916 100644
--- a/Coder Desktop/Coder Desktop/Views/ButtonRow.swift	
+++ b/Coder Desktop/Coder Desktop/Views/ButtonRow.swift	
@@ -1,6 +1,13 @@
 import SwiftUI
 
 struct ButtonRowView<Label: View>: View {
+    init(highlightColor: Color = .accentColor, isSelected: Bool = false, label: @escaping () -> Label) {
+        self.highlightColor = highlightColor
+        self.isSelected = isSelected
+        self.label = label
+    }
+
+    let highlightColor: Color
     @State private var isSelected: Bool = false
     @ViewBuilder var label: () -> Label
 
@@ -12,8 +19,8 @@ struct ButtonRowView<Label: View>: View {
         .padding(.horizontal, Theme.Size.trayPadding)
         .frame(minHeight: 22)
         .frame(maxWidth: .infinity, alignment: .leading)
-        .foregroundStyle(isSelected ? Color.white : .primary)
-        .background(isSelected ? Color.accentColor.opacity(0.8) : .clear)
+        .foregroundStyle(isSelected ? .white : .primary)
+        .background(isSelected ? highlightColor.opacity(0.8) : .clear)
         .clipShape(.rect(cornerRadius: Theme.Size.rectCornerRadius))
         .onHover { hovering in isSelected = hovering }
     }
diff --git a/Coder Desktop/Coder Desktop/Views/InvalidAgents.swift b/Coder Desktop/Coder Desktop/Views/InvalidAgents.swift
new file mode 100644
index 0000000..9e27fa5
--- /dev/null
+++ b/Coder Desktop/Coder Desktop/Views/InvalidAgents.swift	
@@ -0,0 +1,56 @@
+import SwiftUI
+import VPNLib
+
+struct InvalidAgentsButton<VPN: VPNService>: View {
+    @Environment(\.dismiss) var dismiss
+    @EnvironmentObject var vpn: VPN
+    var msg: String {
+        "\(vpn.menuState.invalidAgents.count) invalid \(vpn.menuState.invalidAgents.count > 1 ? "agents" : "agent").."
+    }
+
+    var body: some View {
+        Button {
+            showAlert()
+        } label: {
+            ButtonRowView(highlightColor: .red) { Text(msg) }
+        }.buttonStyle(.plain)
+    }
+
+    // `.alert` from SwiftUI doesn't play nice when the calling view is in the
+    // menu bar.
+    private func showAlert() {
+        let formattedAgents = vpn.menuState.invalidAgents.map { agent in
+            let agent_id = if let agent_id = UUID(uuidData: agent.id) {
+                agent_id.uuidString
+            } else {
+                "Invalid ID: \(agent.id.base64EncodedString())"
+            }
+            let wsID = if let wsID = UUID(uuidData: agent.workspaceID) {
+                wsID.uuidString
+            } else {
+                "Invalid ID: \(agent.workspaceID.base64EncodedString())"
+            }
+            let lastHandshake = agent.hasLastHandshake ? "\(agent.lastHandshake)" : "Never"
+            return """
+            Agent Name: \(agent.name)
+            ID: \(agent_id)
+            Workspace ID: \(wsID)
+            Last Handshake: \(lastHandshake)
+            FQDNs: \(agent.fqdn)
+            Addresses: \(agent.ipAddrs)
+            """
+        }.joined(separator: "\n\n")
+
+        let alert = NSAlert()
+        alert.messageText = "Invalid Agents"
+        alert.informativeText = """
+        Coder Desktop received invalid agents from the VPN. This should
+        never happen. Please open an issue on \(About.repo).
+
+        \(formattedAgents)
+        """
+        alert.alertStyle = .warning
+        dismiss()
+        alert.runModal()
+    }
+}
diff --git a/Coder Desktop/Coder Desktop/Views/Util.swift b/Coder Desktop/Coder Desktop/Views/Util.swift
index 693dc93..8f9ef31 100644
--- a/Coder Desktop/Coder Desktop/Views/Util.swift	
+++ b/Coder Desktop/Coder Desktop/Views/Util.swift	
@@ -31,3 +31,11 @@ extension UUID {
         self.init(uuid: uuid)
     }
 }
+
+extension Array {
+    func prefix(_ maxCount: Int, while predicate: (Element) -> Bool) -> ArraySlice<Element> {
+        let failureIndex = enumerated().first(where: { !predicate($0.element) })?.offset ?? count
+        let endIndex = Swift.min(failureIndex, maxCount)
+        return self[..<endIndex]
+    }
+}
diff --git a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift
index ec63d6e..99a4802 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
@@ -37,11 +37,13 @@ struct VPNMenu<VPN: VPNService, S: Session>: View {
             // Trailing stack
             VStack(alignment: .leading, spacing: 3) {
                 TrayDivider()
+                if vpn.state == .connected, !vpn.menuState.invalidAgents.isEmpty {
+                    InvalidAgentsButton<VPN>()
+                }
                 if session.hasSession {
                     Link(destination: session.baseAccessURL!.appending(path: "templates")) {
                         ButtonRowView {
                             Text("Create workspace")
-                            EmptyView()
                         }
                     }.buttonStyle(.plain)
                     TrayDivider()
diff --git a/Coder Desktop/Coder Desktop/Views/VPNMenuItem.swift b/Coder Desktop/Coder Desktop/Views/VPNMenuItem.swift
index 6ccdcc0..43aac47 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNMenuItem.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNMenuItem.swift	
@@ -47,12 +47,17 @@ struct MenuItemView: View {
     @State private var nameIsSelected: Bool = false
     @State private var copyIsSelected: Bool = false
 
-    private var fmtWsName: AttributedString {
-        var formattedName = AttributedString(item.wsName)
+    private var itemName: AttributedString {
+        let name = switch item {
+        case let .agent(agent): agent.primaryHost ?? "\(item.wsName).coder"
+        case .offlineWorkspace: "\(item.wsName).coder"
+        }
+
+        var formattedName = AttributedString(name)
         formattedName.foregroundColor = .primary
-        var coderPart = AttributedString(".coder")
-        coderPart.foregroundColor = .gray
-        formattedName.append(coderPart)
+        if let range = formattedName.range(of: ".coder") {
+            formattedName[range].foregroundColor = .gray
+        }
         return formattedName
     }
 
@@ -73,26 +78,26 @@ struct MenuItemView: View {
                             .fill(item.status.color.opacity(1.0))
                             .frame(width: 7, height: 7)
                     }
-                    Text(fmtWsName).lineLimit(1).truncationMode(.tail)
+                    Text(itemName).lineLimit(1).truncationMode(.tail)
                     Spacer()
                 }.padding(.horizontal, Theme.Size.trayPadding)
                     .frame(minHeight: 22)
                     .frame(maxWidth: .infinity, alignment: .leading)
-                    .foregroundStyle(nameIsSelected ? Color.white : .primary)
+                    .foregroundStyle(nameIsSelected ? .white : .primary)
                     .background(nameIsSelected ? Color.accentColor.opacity(0.8) : .clear)
                     .clipShape(.rect(cornerRadius: Theme.Size.rectCornerRadius))
                     .onHover { hovering in nameIsSelected = hovering }
                 Spacer()
             }.buttonStyle(.plain)
-            if case let .agent(agent) = item {
+            if case let .agent(agent) = item, let copyableDNS = agent.primaryHost {
                 Button {
                     NSPasteboard.general.clearContents()
-                    NSPasteboard.general.setString(agent.copyableDNS, forType: .string)
+                    NSPasteboard.general.setString(copyableDNS, forType: .string)
                 } label: {
                     Image(systemName: "doc.on.doc")
                         .symbolVariant(.fill)
                         .padding(3)
-                }.foregroundStyle(copyIsSelected ? Color.white : .primary)
+                }.foregroundStyle(copyIsSelected ? .white : .primary)
                     .imageScale(.small)
                     .background(copyIsSelected ? Color.accentColor.opacity(0.8) : .clear)
                     .clipShape(.rect(cornerRadius: Theme.Size.rectCornerRadius))
diff --git a/Coder Desktop/Coder Desktop/Views/VPNState.swift b/Coder Desktop/Coder Desktop/Views/VPNState.swift
index 4afc6c2..b7a090b 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNState.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNState.swift	
@@ -18,7 +18,7 @@ struct VPNState<VPN: VPNService, S: Session>: View {
                     .font(.body)
                     .foregroundColor(.gray)
             case (.disabled, _):
-                Text("Enable CoderVPN to see agents")
+                Text("Enable CoderVPN to see workspaces")
                     .font(.body)
                     .foregroundStyle(.gray)
             case (.connecting, _), (.disconnecting, _):
diff --git a/Coder Desktop/Coder DesktopTests/AgentsTests.swift b/Coder Desktop/Coder DesktopTests/AgentsTests.swift
index b93ca2b..1fd2022 100644
--- a/Coder Desktop/Coder DesktopTests/AgentsTests.swift	
+++ b/Coder Desktop/Coder DesktopTests/AgentsTests.swift	
@@ -18,14 +18,14 @@ struct AgentsTests {
         view = sut.environmentObject(vpn).environmentObject(session)
     }
 
-    private func createMockAgents(count: Int) -> [UUID: Agent] {
+    private func createMockAgents(count: Int, status: AgentStatus = .okay) -> [UUID: Agent] {
         Dictionary(uniqueKeysWithValues: (1 ... count).map {
             let agent = Agent(
                 id: UUID(),
                 name: "dev",
-                status: .okay,
-                copyableDNS: "a\($0).example.com",
-                wsName: "a\($0)",
+                status: status,
+                hosts: ["a\($0).coder"],
+                wsName: "ws\($0)",
                 wsID: UUID()
             )
             return (agent.id, agent)
@@ -41,6 +41,17 @@ struct AgentsTests {
         }
     }
 
+    @Test func noAgents() async throws {
+        vpn.state = .connected
+        vpn.menuState = .init(agents: [:])
+
+        try await ViewHosting.host(view) {
+            try await sut.inspection.inspect { view in
+                #expect(throws: Never.self) { try view.find(text: "No workspaces!") }
+            }
+        }
+    }
+
     @Test
     func agentsWhenVPNOn() throws {
         vpn.state = .connected
@@ -60,12 +71,14 @@ struct AgentsTests {
         try await ViewHosting.host(view) {
             try await sut.inspection.inspect { view in
                 var toggle = try view.find(ViewType.Toggle.self)
+                var forEach = try view.find(ViewType.ForEach.self)
+                #expect(forEach.count == Theme.defaultVisibleAgents)
                 #expect(try toggle.labelView().text().string() == "Show all")
                 #expect(try !toggle.isOn())
 
                 try toggle.tap()
                 toggle = try view.find(ViewType.Toggle.self)
-                var forEach = try view.find(ViewType.ForEach.self)
+                forEach = try view.find(ViewType.ForEach.self)
                 #expect(forEach.count == Theme.defaultVisibleAgents + 2)
                 #expect(try toggle.labelView().text().string() == "Show less")
 
@@ -87,4 +100,70 @@ struct AgentsTests {
             _ = try view.inspect().find(ViewType.Toggle.self)
         }
     }
+
+    @Test func showAllToggle_noOnlineWorkspaces() async throws {
+        vpn.state = .connected
+        let tmpAgents = createMockAgents(count: Theme.defaultVisibleAgents + 1, status: .off)
+        vpn.menuState = .init(agents: tmpAgents)
+
+        try await ViewHosting.host(view) {
+            try await sut.inspection.inspect { view in
+                var toggle = try view.find(ViewType.Toggle.self)
+                var forEach = try view.find(ViewType.ForEach.self)
+                #expect(throws: Never.self) { try view.find(text: "No running workspaces!") }
+                #expect(forEach.count == 0)
+                #expect(try toggle.labelView().text().string() == "Show all")
+                #expect(try !toggle.isOn())
+
+                try toggle.tap()
+                toggle = try view.find(ViewType.Toggle.self)
+                forEach = try view.find(ViewType.ForEach.self)
+                #expect(forEach.count == Theme.defaultVisibleAgents + 1)
+                #expect(try toggle.labelView().text().string() == "Show less")
+
+                try toggle.tap()
+                toggle = try view.find(ViewType.Toggle.self)
+                forEach = try view.find(ViewType.ForEach.self)
+                #expect(try toggle.labelView().text().string() == "Show all")
+                #expect(forEach.count == 0)
+            }
+        }
+    }
+
+    @Test
+    func showAllToggle_oneOfflineWorkspace() async throws {
+        vpn.state = .connected
+        vpn.menuState = .init(agents: createMockAgents(count: Theme.defaultVisibleAgents - 2))
+        let offlineAgent = Agent(
+            id: UUID(),
+            name: "dev",
+            status: .off,
+            hosts: ["offline.coder"],
+            wsName: "offlinews",
+            wsID: UUID()
+        )
+        vpn.menuState.agents[offlineAgent.id] = offlineAgent
+
+        try await ViewHosting.host(view) {
+            try await sut.inspection.inspect { view in
+                var toggle = try view.find(ViewType.Toggle.self)
+                var forEach = try view.find(ViewType.ForEach.self)
+                #expect(forEach.count == Theme.defaultVisibleAgents - 2)
+                #expect(try toggle.labelView().text().string() == "Show all")
+                #expect(try !toggle.isOn())
+
+                try toggle.tap()
+                toggle = try view.find(ViewType.Toggle.self)
+                forEach = try view.find(ViewType.ForEach.self)
+                #expect(forEach.count == Theme.defaultVisibleAgents - 1)
+                #expect(try toggle.labelView().text().string() == "Show less")
+
+                try toggle.tap()
+                toggle = try view.find(ViewType.Toggle.self)
+                forEach = try view.find(ViewType.ForEach.self)
+                #expect(try toggle.labelView().text().string() == "Show all")
+                #expect(forEach.count == Theme.defaultVisibleAgents - 2)
+            }
+        }
+    }
 }
diff --git a/Coder Desktop/Coder DesktopTests/VPNMenuStateTests.swift b/Coder Desktop/Coder DesktopTests/VPNMenuStateTests.swift
index 439ebdb..d82aff8 100644
--- a/Coder Desktop/Coder DesktopTests/VPNMenuStateTests.swift	
+++ b/Coder Desktop/Coder DesktopTests/VPNMenuStateTests.swift	
@@ -27,7 +27,7 @@ struct VPNMenuStateTests {
         #expect(storedAgent.name == "dev")
         #expect(storedAgent.wsID == workspaceID)
         #expect(storedAgent.wsName == "foo")
-        #expect(storedAgent.copyableDNS == "foo.coder")
+        #expect(storedAgent.primaryHost == "foo.coder")
         #expect(storedAgent.status == .okay)
     }
 
@@ -123,7 +123,7 @@ struct VPNMenuStateTests {
         let storedAgent = try #require(state.agents[newAgentID])
         #expect(storedAgent.name == "agent1")
         #expect(storedAgent.wsID == workspaceID)
-        #expect(storedAgent.copyableDNS == "foo.coder")
+        #expect(storedAgent.primaryHost == "foo.coder")
         #expect(storedAgent.status == .okay)
     }
 
@@ -135,7 +135,7 @@ struct VPNMenuStateTests {
         let storedWorkspace = try #require(state.workspaces[workspaceID])
         #expect(storedWorkspace.name == "foo")
 
-        var output = state.sorted()
+        var output = state.sorted
         #expect(output.count == 1)
         #expect(output[0].id == workspaceID)
         #expect(output[0].wsName == "foo")
@@ -150,10 +150,62 @@ struct VPNMenuStateTests {
         }
         state.upsertAgent(agent)
 
-        output = state.sorted()
+        output = state.sorted
         #expect(output.count == 1)
         #expect(output[0].id == agentID)
         #expect(output[0].wsName == "foo")
         #expect(output[0].status == .okay)
     }
+
+    @Test
+    mutating func testUpsertAgent_invalidAgent_noUUID() async throws {
+        let agent = Vpn_Agent.with {
+            $0.name = "invalidAgent"
+            $0.fqdn = ["invalid.coder"]
+        }
+
+        state.upsertAgent(agent)
+
+        #expect(state.agents.isEmpty)
+        #expect(state.invalidAgents.count == 1)
+    }
+
+    @Test
+    mutating func testUpsertAgent_outOfOrder() async throws {
+        let agentID = UUID()
+        let workspaceID = UUID()
+
+        let agent = Vpn_Agent.with {
+            $0.id = agentID.uuidData
+            $0.workspaceID = workspaceID.uuidData
+            $0.name = "orphanAgent"
+            $0.lastHandshake = .init(date: Date.now)
+            $0.fqdn = ["orphan.coder"]
+        }
+
+        state.upsertAgent(agent)
+        #expect(state.agents.isEmpty)
+        state.upsertWorkspace(Vpn_Workspace.with { $0.id = workspaceID.uuidData; $0.name = "validWorkspace" })
+        #expect(state.agents.count == 1)
+    }
+
+    @Test
+    mutating func testDeleteInvalidAgent_removesInvalid() async throws {
+        let agentID = UUID()
+        let workspaceID = UUID()
+
+        let agent = Vpn_Agent.with {
+            $0.id = agentID.uuidData
+            $0.workspaceID = workspaceID.uuidData
+            $0.name = "invalidAgent"
+            $0.lastHandshake = .init(date: Date.now)
+            $0.fqdn = ["invalid.coder"]
+        }
+
+        state.upsertAgent(agent)
+        #expect(state.agents.isEmpty)
+        state.deleteAgent(withId: agentID.uuidData)
+        #expect(state.agents.isEmpty)
+        #expect(state.invalidAgents.isEmpty)
+    }
 }
diff --git a/Coder Desktop/Coder DesktopTests/VPNStateTests.swift b/Coder Desktop/Coder DesktopTests/VPNStateTests.swift
index 298bacd..1330f06 100644
--- a/Coder Desktop/Coder DesktopTests/VPNStateTests.swift	
+++ b/Coder Desktop/Coder DesktopTests/VPNStateTests.swift	
@@ -26,7 +26,7 @@ struct VPNStateTests {
         try await ViewHosting.host(view) {
             try await sut.inspection.inspect { view in
                 #expect(throws: Never.self) {
-                    try view.find(text: "Enable CoderVPN to see agents")
+                    try view.find(text: "Enable CoderVPN to see workspaces")
                 }
             }
         }

From 63442fe5f5a5bcae80b3206e2fc450485a95d511 Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Wed, 12 Feb 2025 18:46:00 +1100
Subject: [PATCH 6/9] undo dumb idea

---
 .../Coder Desktop/Views/Agents.swift          | 11 ++--
 Coder Desktop/Coder Desktop/Views/Util.swift  |  8 ---
 .../Coder DesktopTests/AgentsTests.swift      | 63 +++----------------
 3 files changed, 11 insertions(+), 71 deletions(-)

diff --git a/Coder Desktop/Coder Desktop/Views/Agents.swift b/Coder Desktop/Coder Desktop/Views/Agents.swift
index 933a999..53c0441 100644
--- a/Coder Desktop/Coder Desktop/Views/Agents.swift	
+++ b/Coder Desktop/Coder Desktop/Views/Agents.swift	
@@ -13,23 +13,20 @@ struct Agents<VPN: VPNService, S: Session>: View {
             // Agents List
             if vpn.state == .connected {
                 let items = vpn.menuState.sorted
-                let visibleOnlineItems = items.prefix(defaultVisibleRows) {
-                    $0.status != .off
-                }
-                let visibleItems = viewAll ? items[...] : visibleOnlineItems
+                let visibleItems = viewAll ? items[...] : items.prefix(defaultVisibleRows)
                 ForEach(visibleItems, id: \.id) { agent in
                     MenuItemView(item: agent, baseAccessURL: session.baseAccessURL!)
                         .padding(.horizontal, Theme.Size.trayMargin)
                 }
-                if visibleItems.count == 0 {
-                    Text("No \(items.count > 0 ? "running " : "")workspaces!")
+                if items.count == 0 {
+                    Text("No workspaces!")
                         .font(.body)
                         .foregroundColor(.gray)
                         .padding(.horizontal, Theme.Size.trayInset)
                         .padding(.top, 2)
                 }
                 // Only show the toggle if there are more items to show
-                if visibleOnlineItems.count < items.count {
+                if items.count > defaultVisibleRows {
                     Toggle(isOn: $viewAll) {
                         Text(viewAll ? "Show less" : "Show all")
                             .font(.headline)
diff --git a/Coder Desktop/Coder Desktop/Views/Util.swift b/Coder Desktop/Coder Desktop/Views/Util.swift
index 8f9ef31..693dc93 100644
--- a/Coder Desktop/Coder Desktop/Views/Util.swift	
+++ b/Coder Desktop/Coder Desktop/Views/Util.swift	
@@ -31,11 +31,3 @@ extension UUID {
         self.init(uuid: uuid)
     }
 }
-
-extension Array {
-    func prefix(_ maxCount: Int, while predicate: (Element) -> Bool) -> ArraySlice<Element> {
-        let failureIndex = enumerated().first(where: { !predicate($0.element) })?.offset ?? count
-        let endIndex = Swift.min(failureIndex, maxCount)
-        return self[..<endIndex]
-    }
-}
diff --git a/Coder Desktop/Coder DesktopTests/AgentsTests.swift b/Coder Desktop/Coder DesktopTests/AgentsTests.swift
index 1fd2022..b460b1f 100644
--- a/Coder Desktop/Coder DesktopTests/AgentsTests.swift	
+++ b/Coder Desktop/Coder DesktopTests/AgentsTests.swift	
@@ -101,68 +101,19 @@ struct AgentsTests {
         }
     }
 
-    @Test func showAllToggle_noOnlineWorkspaces() async throws {
-        vpn.state = .connected
-        let tmpAgents = createMockAgents(count: Theme.defaultVisibleAgents + 1, status: .off)
-        vpn.menuState = .init(agents: tmpAgents)
-
-        try await ViewHosting.host(view) {
-            try await sut.inspection.inspect { view in
-                var toggle = try view.find(ViewType.Toggle.self)
-                var forEach = try view.find(ViewType.ForEach.self)
-                #expect(throws: Never.self) { try view.find(text: "No running workspaces!") }
-                #expect(forEach.count == 0)
-                #expect(try toggle.labelView().text().string() == "Show all")
-                #expect(try !toggle.isOn())
-
-                try toggle.tap()
-                toggle = try view.find(ViewType.Toggle.self)
-                forEach = try view.find(ViewType.ForEach.self)
-                #expect(forEach.count == Theme.defaultVisibleAgents + 1)
-                #expect(try toggle.labelView().text().string() == "Show less")
-
-                try toggle.tap()
-                toggle = try view.find(ViewType.Toggle.self)
-                forEach = try view.find(ViewType.ForEach.self)
-                #expect(try toggle.labelView().text().string() == "Show all")
-                #expect(forEach.count == 0)
-            }
-        }
-    }
-
     @Test
-    func showAllToggle_oneOfflineWorkspace() async throws {
+    func showOfflineWorkspace() async throws {
         vpn.state = .connected
-        vpn.menuState = .init(agents: createMockAgents(count: Theme.defaultVisibleAgents - 2))
-        let offlineAgent = Agent(
-            id: UUID(),
-            name: "dev",
-            status: .off,
-            hosts: ["offline.coder"],
-            wsName: "offlinews",
-            wsID: UUID()
+        vpn.menuState = .init(
+            agents: createMockAgents(count: Theme.defaultVisibleAgents - 1),
+            workspaces: [UUID(): Workspace(id: UUID(), name: "offline", agents: .init())]
         )
-        vpn.menuState.agents[offlineAgent.id] = offlineAgent
 
         try await ViewHosting.host(view) {
             try await sut.inspection.inspect { view in
-                var toggle = try view.find(ViewType.Toggle.self)
-                var forEach = try view.find(ViewType.ForEach.self)
-                #expect(forEach.count == Theme.defaultVisibleAgents - 2)
-                #expect(try toggle.labelView().text().string() == "Show all")
-                #expect(try !toggle.isOn())
-
-                try toggle.tap()
-                toggle = try view.find(ViewType.Toggle.self)
-                forEach = try view.find(ViewType.ForEach.self)
-                #expect(forEach.count == Theme.defaultVisibleAgents - 1)
-                #expect(try toggle.labelView().text().string() == "Show less")
-
-                try toggle.tap()
-                toggle = try view.find(ViewType.Toggle.self)
-                forEach = try view.find(ViewType.ForEach.self)
-                #expect(try toggle.labelView().text().string() == "Show all")
-                #expect(forEach.count == Theme.defaultVisibleAgents - 2)
+                let forEach = try view.find(ViewType.ForEach.self)
+                #expect(forEach.count == Theme.defaultVisibleAgents)
+                #expect(throws: Never.self) { try view.find(link: "offline.coder") }
             }
         }
     }

From 05582ab68a65a49c01271f81e08410451eeb520a Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Wed, 5 Feb 2025 12:15:45 +1100
Subject: [PATCH 7/9] chore(ci): build for distribution

Change-Id: Idd722d6fe9c1d69076dbd85bc0371f8ae9a3354a
Signed-off-by: Thomas Kosiewski <tk@coder.com>

Author: Ethan Dickson <ethan@coder.com>
Co-Authored-By: Thomas Kosiewski <tk@coder.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
---
 .env                                          |    9 +
 .github/actions/nix-devshell/action.yaml      |    3 -
 .github/dependabot.yaml                       |   15 +
 .github/workflows/ci.yml                      |   18 +-
 .github/workflows/release.yml                 |   45 +
 .gitignore                                    |    7 +
 .../Coder Desktop/Coder_Desktop.entitlements  |   16 -
 .../Coder Desktop/Views/LoginForm.swift       |   10 +-
 .../Views/Settings/NetworkTab.swift           |    8 +-
 .../Coder Desktop/Views/VPNMenu.swift         |   12 +-
 Coder Desktop/VPN/Manager.swift               |    3 +-
 Coder Desktop/VPN/VPN.entitlements            |   20 -
 Coder Desktop/project.yml                     |   21 +-
 Makefile                                      |   74 +-
 flake.nix                                     |   32 +-
 nix/create-dmg/package-lock.json              | 9595 +++++++++++++++++
 scripts/build.sh                              |  139 +
 17 files changed, 9946 insertions(+), 81 deletions(-)
 create mode 100644 .env
 create mode 100644 .github/dependabot.yaml
 create mode 100644 .github/workflows/release.yml
 delete mode 100644 Coder Desktop/Coder Desktop/Coder_Desktop.entitlements
 delete mode 100644 Coder Desktop/VPN/VPN.entitlements
 create mode 100644 nix/create-dmg/package-lock.json
 create mode 100755 scripts/build.sh

diff --git a/.env b/.env
new file mode 100644
index 0000000..449b9ed
--- /dev/null
+++ b/.env
@@ -0,0 +1,9 @@
+# Build a release locally using: op run --env-file="./.env" -- make release
+APPLE_CERT="op://Apple/Apple DeveloperID PKCS12 base64/notesPlain"
+CERT_PASSWORD="op://Apple/DeveloperID p12 password/password"
+
+APPLE_ID="op://Apple/3apcadvvcojjbpxnd7m5fgh5wm/username"
+APPLE_ID_PASSWORD="op://Apple/3apcadvvcojjbpxnd7m5fgh5wm/password"
+
+APP_PROF="op://Apple/Provisioning Profiles/profiles/application_base64"
+EXT_PROF="op://Apple/Provisioning Profiles/profiles/extension_base64"
diff --git a/.github/actions/nix-devshell/action.yaml b/.github/actions/nix-devshell/action.yaml
index 6cea0a0..1a7590f 100644
--- a/.github/actions/nix-devshell/action.yaml
+++ b/.github/actions/nix-devshell/action.yaml
@@ -6,8 +6,5 @@ runs:
     - name: Setup Nix
       uses: DeterminateSystems/nix-installer-action@e50d5f73bfe71c2dd0aa4218de8f4afa59f8f81d # v16
 
-    - name: Setup GHA Nix cache
-      uses: DeterminateSystems/magic-nix-cache-action@6221693898146dc97e38ad0e013488a16477a4c4 # v9
-
     - name: Enter devshell
       uses: nicknovitski/nix-develop@9be7cfb4b10451d3390a75dc18ad0465bed4932a # v1.2.1
diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml
new file mode 100644
index 0000000..7bfd018
--- /dev/null
+++ b/.github/dependabot.yaml
@@ -0,0 +1,15 @@
+version: 2
+updates:
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "weekly"
+      time: "06:00"
+      timezone: "America/Chicago"
+    labels: []
+    commit-message:
+      prefix: "ci"
+    groups:
+      github-actions:
+        patterns:
+          - "*"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 145b67a..70d81e9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -18,15 +18,11 @@ jobs:
     name: test
     runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
     steps:
-      - name: Harden Runner
-        uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
-        with:
-          egress-policy: audit
-
       - name: Checkout
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
         with:
           fetch-depth: 1
+          persist-credentials: false
 
       - name: Switch XCode Version
         uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
@@ -44,15 +40,11 @@ jobs:
     name: fmt
     runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
     steps:
-      - name: Harden Runner
-        uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
-        with:
-          egress-policy: audit
-
       - name: Checkout
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
         with:
           fetch-depth: 1
+          persist-credentials: false
 
       - name: Switch XCode Version
         uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
@@ -70,15 +62,11 @@ jobs:
     name: lint
     runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
     steps:
-      - name: Harden Runner
-        uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
-        with:
-          egress-policy: audit
-
       - name: Checkout
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
         with:
           fetch-depth: 1
+          persist-credentials: false
 
       - name: Setup Nix
         uses: ./.github/actions/nix-devshell
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..6a546bf
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,45 @@
+name: release
+
+on:
+  release:
+    types: [published]
+
+permissions: {}
+
+jobs:
+  build:
+    runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest'}}
+    if: ${{ github.repository_owner == 'coder' }}
+    permissions:
+      # To upload assets to the release
+      contents: write
+    steps:
+      - name: Checkout
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        with:
+          fetch-depth: 1
+          persist-credentials: false
+
+      - name: Switch XCode Version
+        uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
+        with:
+          xcode-version: "16.0.0"
+
+      - name: Setup Nix
+        uses: ./.github/actions/nix-devshell
+
+      - name: Build
+        env:
+          APPLE_CERT: ${{ secrets.APPLE_DEVELOPER_ID_PKCS12_B64 }}
+          APPLE_ID: ${{ secrets.APPLE_NOTARYTOOL_USERNAME  }}
+          APPLE_ID_PASSWORD: ${{ secrets.APPLE_NOTARYTOOL_PASSWORD }}
+          APP_PROF: ${{ secrets.CODER_DESKTOP_APP_PROVISIONPROFILE_B64 }}
+          CERT_PASSWORD: ${{ secrets.APPLE_DEVELOPER_ID_PKCS12_PASSWORD }}
+          EXT_PROF: ${{ secrets.CODER_DESKTOP_EXTENSION_PROVISIONPROFILE_B64 }}
+        run: make release
+
+      - name: Upload Release Assets
+        run: gh release upload "$RELEASE_TAG" "$out"
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          RELEASE_TAG: ${{ github.event.release.tag_name }}
diff --git a/.gitignore b/.gitignore
index 51965fb..e6983d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -295,3 +295,10 @@ xcuserdata
 buildServer.json
 
 # End of https://www.toptal.com/developers/gitignore/api/xcode,jetbrains,macos,direnv,swift,swiftpm,objective-c
+
+*.entitlements
+app-signing.keychain-db
+release/
+
+# marker files
+.fl5C1A396C
diff --git a/Coder Desktop/Coder Desktop/Coder_Desktop.entitlements b/Coder Desktop/Coder Desktop/Coder_Desktop.entitlements
deleted file mode 100644
index 0d80c22..0000000
--- a/Coder Desktop/Coder Desktop/Coder_Desktop.entitlements	
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>com.apple.developer.networking.networkextension</key>
-	<array>
-		<string>packet-tunnel-provider</string>
-	</array>
-	<key>com.apple.developer.system-extension.install</key>
-	<true/>
-	<key>com.apple.security.application-groups</key>
-	<array>
-		<string>$(TeamIdentifierPrefix)com.coder.Coder-Desktop</string>
-	</array>
-</dict>
-</plist>
diff --git a/Coder Desktop/Coder Desktop/Views/LoginForm.swift b/Coder Desktop/Coder Desktop/Views/LoginForm.swift
index 653e493..8943b50 100644
--- a/Coder Desktop/Coder Desktop/Views/LoginForm.swift	
+++ b/Coder Desktop/Coder Desktop/Views/LoginForm.swift	
@@ -194,7 +194,9 @@ enum LoginField: Hashable {
     case sessionToken
 }
 
-#Preview {
-    LoginForm<PreviewSession>()
-        .environmentObject(PreviewSession())
-}
+#if DEBUG
+    #Preview {
+        LoginForm<PreviewSession>()
+            .environmentObject(PreviewSession())
+    }
+#endif
diff --git a/Coder Desktop/Coder Desktop/Views/Settings/NetworkTab.swift b/Coder Desktop/Coder Desktop/Views/Settings/NetworkTab.swift
index 5e1d7ef..d830e74 100644
--- a/Coder Desktop/Coder Desktop/Views/Settings/NetworkTab.swift	
+++ b/Coder Desktop/Coder Desktop/Views/Settings/NetworkTab.swift	
@@ -9,6 +9,8 @@ struct NetworkTab<VPN: VPNService>: View {
     }
 }
 
-#Preview {
-    NetworkTab<PreviewVPN>()
-}
+#if DEBUG
+    #Preview {
+        NetworkTab<PreviewVPN>()
+    }
+#endif
diff --git a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift
index 99a4802..0c70c1a 100644
--- a/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
+++ b/Coder Desktop/Coder Desktop/Views/VPNMenu.swift	
@@ -101,8 +101,10 @@ func openSystemExtensionSettings() {
     NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.ExtensionsPreferences?extensionPointIdentifier=com.apple.system_extension.network_extension.extension-point")!)
 }
 
-#Preview {
-    VPNMenu<PreviewVPN, PreviewSession>().frame(width: 256)
-        .environmentObject(PreviewVPN())
-        .environmentObject(PreviewSession())
-}
+#if DEBUG
+    #Preview {
+        VPNMenu<PreviewVPN, PreviewSession>().frame(width: 256)
+            .environmentObject(PreviewVPN())
+            .environmentObject(PreviewSession())
+    }
+#endif
diff --git a/Coder Desktop/VPN/Manager.swift b/Coder Desktop/VPN/Manager.swift
index 58a65b5..4506dfa 100644
--- a/Coder Desktop/VPN/Manager.swift	
+++ b/Coder Desktop/VPN/Manager.swift	
@@ -48,12 +48,13 @@ actor Manager {
         }
 
         // HACK: The downloaded dylib may be quarantined, but we've validated it's signature
-        // so it's safe to execute. However, this SE must be sandboxed, so we defer to the app.
+        // so it's safe to execute. However, the SE must be sandboxed, so we defer to the app.
         try await removeQuarantine(dest)
 
         do {
             try tunnelHandle = TunnelHandle(dylibPath: dest)
         } catch {
+            logger.error("couldn't open dylib \(error, privacy: .public)")
             throw .tunnelSetup(error)
         }
         speaker = await Speaker<Vpn_ManagerMessage, Vpn_TunnelMessage>(
diff --git a/Coder Desktop/VPN/VPN.entitlements b/Coder Desktop/VPN/VPN.entitlements
deleted file mode 100644
index a5c12f4..0000000
--- a/Coder Desktop/VPN/VPN.entitlements	
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>com.apple.developer.networking.networkextension</key>
-	<array>
-		<string>packet-tunnel-provider</string>
-	</array>
-	<key>com.apple.security.app-sandbox</key>
-	<true/>
-	<key>com.apple.security.application-groups</key>
-	<array>
-		<string>$(TeamIdentifierPrefix)com.coder.Coder-Desktop</string>
-	</array>
-	<key>com.apple.security.network.client</key>
-	<true/>
-	<key>com.apple.security.network.server</key>
-	<true/>
-</dict>
-</plist>
diff --git a/Coder Desktop/project.yml b/Coder Desktop/project.yml
index 54ce06a..8b9b18f 100644
--- a/Coder Desktop/project.yml	
+++ b/Coder Desktop/project.yml	
@@ -8,8 +8,8 @@ options:
 
 settings:
   base:
-    MARKETING_VERSION: "1.0" # Sets the version number.
-    CURRENT_PROJECT_VERSION: "1" # Sets the build number.
+    MARKETING_VERSION: ${MARKETING_VERSION} # Sets the version number.
+    CURRENT_PROJECT_VERSION: ${CURRENT_PROJECT_VERSION} # Sets the build number.
 
     ALWAYS_SEARCH_USER_PATHS: NO
     ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS: YES
@@ -114,7 +114,7 @@ targets:
       path: Coder Desktop/Coder_Desktop.entitlements
       properties:
         com.apple.developer.networking.networkextension:
-          - packet-tunnel-provider
+          - packet-tunnel-provider${PTP_SUFFIX}
         com.apple.developer.system-extension.install: true
         com.apple.security.application-groups:
           - $(TeamIdentifierPrefix)com.coder.Coder-Desktop
@@ -122,6 +122,7 @@ targets:
       base:
         ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon # Sets the app icon to "AppIcon".
         ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor
+        # `CODE_SIGN_*` options are overriden during a release build
         CODE_SIGN_IDENTITY: "Apple Development"
         CODE_SIGN_STYLE: Automatic
         COMBINE_HIDPI_IMAGES: YES
@@ -132,6 +133,8 @@ targets:
         INFOPLIST_KEY_NSHumanReadableCopyright: ""
         SWIFT_EMIT_LOC_STRINGS: YES
         PRODUCT_BUNDLE_IDENTIFIER: "com.coder.Coder-Desktop"
+        # Empty outside of release builds
+        PROVISIONING_PROFILE_SPECIFIER: ${APP_PROVISIONING_PROFILE_ID}
 
         # (ThomasK33): Install the application into the /Applications folder
         # so that macOS stops complaining about the app being run from an
@@ -197,7 +200,8 @@ targets:
       path: VPN/VPN.entitlements
       properties:
         com.apple.developer.networking.networkextension:
-          - packet-tunnel-provider
+          # PTP_SUFFIX is populated at `xcodegen` time.
+          - packet-tunnel-provider${PTP_SUFFIX}
         com.apple.security.app-sandbox: true
         com.apple.security.application-groups:
           - $(TeamIdentifierPrefix)com.coder.Coder-Desktop
@@ -212,6 +216,11 @@ targets:
         PRODUCT_NAME: "$(PRODUCT_BUNDLE_IDENTIFIER)"
         SWIFT_EMIT_LOC_STRINGS: YES
         SWIFT_OBJC_BRIDGING_HEADER: "VPN/com_coder_Coder_Desktop_VPN-Bridging-Header.h"
+        # `CODE_SIGN_*` are overriden during a release build
+        CODE_SIGN_IDENTITY: "Apple Development"
+        CODE_SIGN_STYLE: Automatic
+        # Empty outside of release builds
+        PROVISIONING_PROFILE_SPECIFIER: ${EXT_PROVISIONING_PROFILE_ID}
     dependencies:
       - target: VPNLib
         embed: true
@@ -232,8 +241,6 @@ targets:
         DYLIB_COMPATIBILITY_VERSION: 1
         DYLIB_CURRENT_VERSION: 1
         DYLIB_INSTALL_NAME_BASE: "@rpath"
-        CODE_SIGN_IDENTITY: "Apple Development"
-        CODE_SIGN_STYLE: Automatic
         LD_RUNPATH_SEARCH_PATHS:
           - "@executable_path/../Frameworks"
           - "@loader_path/Frameworks"
@@ -294,4 +301,4 @@ targets:
     settings:
       base:
         TEST_HOST: "$(BUILT_PRODUCTS_DIR)/Coder Desktop.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Coder Desktop"
-        PRODUCT_BUNDLE_IDENTIFIER: com.coder.Coder-Desktop.CoderSDKTests
\ No newline at end of file
+        PRODUCT_BUNDLE_IDENTIFIER: com.coder.Coder-Desktop.CoderSDKTests
diff --git a/Makefile b/Makefile
index 7e078de..23ad5a8 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,14 @@ XCPROJECT := Coder\ Desktop/Coder\ Desktop.xcodeproj
 SCHEME := Coder\ Desktop
 SWIFT_VERSION := 6.0
 
+MARKETING_VERSION=$(shell git describe --tags --abbrev=0 | sed 's/^v//')
+CURRENT_PROJECT_VERSION=$(shell git describe --tags)
+
+# Define the keychain file name first
+KEYCHAIN_FILE := app-signing.keychain-db
+# Use shell to get the absolute path only if the file exists
+APP_SIGNING_KEYCHAIN := $(if $(wildcard $(KEYCHAIN_FILE)),$(shell realpath $(KEYCHAIN_FILE)),$(abspath $(KEYCHAIN_FILE)))
+
 .PHONY: setup
 setup: \
 	$(XCPROJECT) \
@@ -18,11 +26,39 @@ setup: \
 
 $(XCPROJECT): $(PROJECT)/project.yml
 	cd $(PROJECT); \
-		SWIFT_VERSION=$(SWIFT_VERSION) xcodegen
+		SWIFT_VERSION=$(SWIFT_VERSION) \
+		PTP_SUFFIX=${PTP_SUFFIX} \
+		APP_PROVISIONING_PROFILE_ID=${APP_PROVISIONING_PROFILE_ID} \
+		EXT_PROVISIONING_PROFILE_ID=${EXT_PROVISIONING_PROFILE_ID} \
+		CURRENT_PROJECT_VERSION=$(CURRENT_PROJECT_VERSION) \
+		MARKETING_VERSION=$(MARKETING_VERSION) \
+		xcodegen
 
 $(PROJECT)/VPNLib/vpn.pb.swift: $(PROJECT)/VPNLib/vpn.proto
 	protoc --swift_opt=Visibility=public --swift_out=. 'Coder Desktop/VPNLib/vpn.proto'
 
+$(KEYCHAIN_FILE):
+	security create-keychain -p "" "$(APP_SIGNING_KEYCHAIN)"
+	security set-keychain-settings -lut 21600 "$(APP_SIGNING_KEYCHAIN)"
+	security unlock-keychain -p "" "$(APP_SIGNING_KEYCHAIN)"
+	@tempfile=$$(mktemp); \
+	echo "$$APPLE_CERT" | base64 -d > $$tempfile; \
+	security import $$tempfile -P '$(CERT_PASSWORD)' -A -t cert -f pkcs12 -k "$(APP_SIGNING_KEYCHAIN)"; \
+	rm $$tempfile
+	security list-keychains -d user -s $$(security list-keychains -d user | tr -d '\"') "$(APP_SIGNING_KEYCHAIN)"
+
+.PHONY: release
+release: $(KEYCHAIN_FILE) ## Create a release build of Coder Desktop
+	@APP_PROF_PATH="$$(mktemp)"; \
+	EXT_PROF_PATH="$$(mktemp)"; \
+	echo -n "$$APP_PROF" | base64 -d > "$$APP_PROF_PATH"; \
+	echo -n "$$EXT_PROF" | base64 -d > "$$EXT_PROF_PATH"; \
+	./scripts/build.sh \
+		--app-prof-path "$$APP_PROF_PATH" \
+		--ext-prof-path "$$EXT_PROF_PATH" \
+		--keychain "$(APP_SIGNING_KEYCHAIN)"; \
+	rm "$$APP_PROF_PATH" "$$EXT_PROF_PATH"
+
 .PHONY: fmt
 fmt: ## Run Swift file formatter
 	swiftformat \
@@ -40,16 +76,42 @@ test: $(XCPROJECT) ## Run all tests
 		CODE_SIGNING_ALLOWED=NO | xcbeautify
 
 .PHONY: lint
-lint: ## Lint swift files
+lint: lint/swift lint/actions ## Lint all files in the repo
+
+.PHONY: lint/swift
+lint/swift: ## Lint Swift files
 	swiftlint \
 		--strict \
 		--quiet $(LINTFLAGS)
 
+.PHONY: lint/actions
+lint/actions: ## Lint GitHub Actions
+	actionlint
+	zizmor .
+
 .PHONY: clean
-clean: ## Clean Xcode project
-	xcodebuild clean \
-		-project $(XCPROJECT)
-	rm -rf $(XCPROJECT)
+clean: clean/project clean/keychain clean/build ## Clean project and artifacts
+
+.PHONY: clean/project
+clean/project:
+	@if [ -d $(XCPROJECT) ]; then \
+		echo "Cleaning project: '$(XCPROJECT)'"; \
+		xcodebuild clean -project $(XCPROJECT); \
+		rm -rf $(XCPROJECT); \
+	fi
+	find . -name "*.entitlements" -type f -delete
+
+.PHONY: clean/keychain
+clean/keychain:
+	@if [ -e "$(APP_SIGNING_KEYCHAIN)" ]; then \
+		echo "Cleaning keychain: '$(APP_SIGNING_KEYCHAIN)'"; \
+		security delete-keychain "$(APP_SIGNING_KEYCHAIN)"; \
+		rm -f "$(APP_SIGNING_KEYCHAIN)"; \
+	fi
+
+.PHONY: clean/build
+clean/build:
+	rm -rf build/ release/ $$out
 
 .PHONY: proto
 proto: $(PROJECT)/VPNLib/vpn.pb.swift ## Generate Swift files from protobufs
diff --git a/flake.nix b/flake.nix
index a83e4b3..5e1e9d8 100644
--- a/flake.nix
+++ b/flake.nix
@@ -25,23 +25,53 @@
           };
 
           formatter = pkgs.nixfmt-rfc-style;
+
+          create-dmg = pkgs.buildNpmPackage rec {
+            pname = "create-dmg";
+            version = "7.0.0";
+
+            src = pkgs.fetchFromGitHub {
+              owner = "sindresorhus";
+              repo = pname;
+              rev = "v${version}";
+              hash = "sha256-+GxKfhVDmtgEh9NOAzGexgfj1qAb0raC8AmrrnJ2vNA=";
+            };
+
+            npmDepsHash = "sha256-48r9v0sTlHbyH4RjynClfC/QsFAlgMTtXCbleuMSM80=";
+
+            # create-dmg author does not want to include a lockfile in their releases,
+            # thus we need to vendor it in ourselves.
+            postPatch = ''
+              cp ${./nix/create-dmg/package-lock.json} package-lock.json
+            '';
+
+            # Plain JS, so nothing to build
+            dontNpmBuild = true;
+            dontNpmPrune = true;
+          };
         in
         {
           inherit formatter;
 
           devShells.default = pkgs.mkShellNoCC {
             buildInputs = with pkgs; [
+              actionlint
               apple-sdk_15
               clang
+              coreutils
+              create-dmg
               formatter
+              gh
               gnumake
               protobuf_28
               protoc-gen-swift
               swiftformat
               swiftlint
               watchexec
-              xcodegen
               xcbeautify
+              xcodegen
+              xcpretty
+              zizmor
             ];
           };
         }
diff --git a/nix/create-dmg/package-lock.json b/nix/create-dmg/package-lock.json
new file mode 100644
index 0000000..4360e1f
--- /dev/null
+++ b/nix/create-dmg/package-lock.json
@@ -0,0 +1,9595 @@
+{
+	"name": "create-dmg",
+	"version": "7.0.0",
+	"lockfileVersion": 3,
+	"requires": true,
+	"packages": {
+		"": {
+			"name": "create-dmg",
+			"version": "7.0.0",
+			"license": "MIT",
+			"dependencies": {
+				"appdmg": "^0.6.6",
+				"execa": "^8.0.1",
+				"gm": "^1.25.0",
+				"icns-lib": "^1.0.1",
+				"meow": "^13.1.0",
+				"ora": "^8.0.1",
+				"plist": "^3.1.0",
+				"tempy": "^3.1.0"
+			},
+			"bin": {
+				"create-dmg": "cli.js"
+			},
+			"devDependencies": {
+				"ava": "^6.1.1",
+				"xo": "^0.56.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/@babel/code-frame": {
+			"version": "7.26.2",
+			"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+			"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@babel/helper-validator-identifier": "^7.25.9",
+				"js-tokens": "^4.0.0",
+				"picocolors": "^1.0.0"
+			},
+			"engines": {
+				"node": ">=6.9.0"
+			}
+		},
+		"node_modules/@babel/helper-validator-identifier": {
+			"version": "7.25.9",
+			"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+			"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6.9.0"
+			}
+		},
+		"node_modules/@eslint-community/eslint-utils": {
+			"version": "4.4.1",
+			"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
+			"integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"eslint-visitor-keys": "^3.4.3"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+			}
+		},
+		"node_modules/@eslint-community/regexpp": {
+			"version": "4.12.1",
+			"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+			"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+			}
+		},
+		"node_modules/@eslint/eslintrc": {
+			"version": "2.1.4",
+			"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+			"integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ajv": "^6.12.4",
+				"debug": "^4.3.2",
+				"espree": "^9.6.0",
+				"globals": "^13.19.0",
+				"ignore": "^5.2.0",
+				"import-fresh": "^3.2.1",
+				"js-yaml": "^4.1.0",
+				"minimatch": "^3.1.2",
+				"strip-json-comments": "^3.1.1"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			}
+		},
+		"node_modules/@eslint/eslintrc/node_modules/argparse": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+			"dev": true,
+			"license": "Python-2.0"
+		},
+		"node_modules/@eslint/eslintrc/node_modules/ignore": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+			"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 4"
+			}
+		},
+		"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"argparse": "^2.0.1"
+			},
+			"bin": {
+				"js-yaml": "bin/js-yaml.js"
+			}
+		},
+		"node_modules/@eslint/js": {
+			"version": "8.57.1",
+			"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
+			"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			}
+		},
+		"node_modules/@humanwhocodes/config-array": {
+			"version": "0.13.0",
+			"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+			"integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
+			"deprecated": "Use @eslint/config-array instead",
+			"dev": true,
+			"license": "Apache-2.0",
+			"dependencies": {
+				"@humanwhocodes/object-schema": "^2.0.3",
+				"debug": "^4.3.1",
+				"minimatch": "^3.0.5"
+			},
+			"engines": {
+				"node": ">=10.10.0"
+			}
+		},
+		"node_modules/@humanwhocodes/module-importer": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+			"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"engines": {
+				"node": ">=12.22"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/nzakas"
+			}
+		},
+		"node_modules/@humanwhocodes/object-schema": {
+			"version": "2.0.3",
+			"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+			"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+			"deprecated": "Use @eslint/object-schema instead",
+			"dev": true,
+			"license": "BSD-3-Clause"
+		},
+		"node_modules/@isaacs/cliui": {
+			"version": "8.0.2",
+			"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+			"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"string-width": "^5.1.2",
+				"string-width-cjs": "npm:string-width@^4.2.0",
+				"strip-ansi": "^7.0.1",
+				"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+				"wrap-ansi": "^8.1.0",
+				"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+			},
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@isaacs/cliui/node_modules/emoji-regex": {
+			"version": "9.2.2",
+			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+			"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@isaacs/cliui/node_modules/string-width": {
+			"version": "5.1.2",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+			"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"eastasianwidth": "^0.2.0",
+				"emoji-regex": "^9.2.2",
+				"strip-ansi": "^7.0.1"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
+			"version": "8.1.0",
+			"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+			"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-styles": "^6.1.0",
+				"string-width": "^5.0.1",
+				"strip-ansi": "^7.0.1"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+			}
+		},
+		"node_modules/@isaacs/fs-minipass": {
+			"version": "4.0.1",
+			"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+			"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"minipass": "^7.0.4"
+			},
+			"engines": {
+				"node": ">=18.0.0"
+			}
+		},
+		"node_modules/@jridgewell/gen-mapping": {
+			"version": "0.3.8",
+			"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+			"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@jridgewell/set-array": "^1.2.1",
+				"@jridgewell/sourcemap-codec": "^1.4.10",
+				"@jridgewell/trace-mapping": "^0.3.24"
+			},
+			"engines": {
+				"node": ">=6.0.0"
+			}
+		},
+		"node_modules/@jridgewell/resolve-uri": {
+			"version": "3.1.2",
+			"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+			"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"engines": {
+				"node": ">=6.0.0"
+			}
+		},
+		"node_modules/@jridgewell/set-array": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+			"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"engines": {
+				"node": ">=6.0.0"
+			}
+		},
+		"node_modules/@jridgewell/source-map": {
+			"version": "0.3.6",
+			"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
+			"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@jridgewell/gen-mapping": "^0.3.5",
+				"@jridgewell/trace-mapping": "^0.3.25"
+			}
+		},
+		"node_modules/@jridgewell/sourcemap-codec": {
+			"version": "1.5.0",
+			"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+			"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/@jridgewell/trace-mapping": {
+			"version": "0.3.25",
+			"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+			"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@jridgewell/resolve-uri": "^3.1.0",
+				"@jridgewell/sourcemap-codec": "^1.4.14"
+			}
+		},
+		"node_modules/@mapbox/node-pre-gyp": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.0.tgz",
+			"integrity": "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==",
+			"dev": true,
+			"license": "BSD-3-Clause",
+			"dependencies": {
+				"consola": "^3.2.3",
+				"detect-libc": "^2.0.0",
+				"https-proxy-agent": "^7.0.5",
+				"node-fetch": "^2.6.7",
+				"nopt": "^8.0.0",
+				"semver": "^7.5.3",
+				"tar": "^7.4.0"
+			},
+			"bin": {
+				"node-pre-gyp": "bin/node-pre-gyp"
+			},
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/@nodelib/fs.scandir": {
+			"version": "2.1.5",
+			"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+			"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@nodelib/fs.stat": "2.0.5",
+				"run-parallel": "^1.1.9"
+			},
+			"engines": {
+				"node": ">= 8"
+			}
+		},
+		"node_modules/@nodelib/fs.stat": {
+			"version": "2.0.5",
+			"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+			"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 8"
+			}
+		},
+		"node_modules/@nodelib/fs.walk": {
+			"version": "1.2.8",
+			"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+			"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@nodelib/fs.scandir": "2.1.5",
+				"fastq": "^1.6.0"
+			},
+			"engines": {
+				"node": ">= 8"
+			}
+		},
+		"node_modules/@pkgjs/parseargs": {
+			"version": "0.11.0",
+			"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+			"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+			"dev": true,
+			"license": "MIT",
+			"optional": true,
+			"engines": {
+				"node": ">=14"
+			}
+		},
+		"node_modules/@pkgr/core": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
+			"integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/unts"
+			}
+		},
+		"node_modules/@rollup/pluginutils": {
+			"version": "5.1.4",
+			"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
+			"integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@types/estree": "^1.0.0",
+				"estree-walker": "^2.0.2",
+				"picomatch": "^4.0.2"
+			},
+			"engines": {
+				"node": ">=14.0.0"
+			},
+			"peerDependencies": {
+				"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+			},
+			"peerDependenciesMeta": {
+				"rollup": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@sindresorhus/merge-streams": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz",
+			"integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/@types/eslint": {
+			"version": "8.56.12",
+			"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz",
+			"integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@types/estree": "*",
+				"@types/json-schema": "*"
+			}
+		},
+		"node_modules/@types/eslint-scope": {
+			"version": "3.7.7",
+			"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+			"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@types/eslint": "*",
+				"@types/estree": "*"
+			}
+		},
+		"node_modules/@types/estree": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+			"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@types/json-schema": {
+			"version": "7.0.15",
+			"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+			"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@types/json5": {
+			"version": "0.0.29",
+			"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+			"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@types/node": {
+			"version": "22.13.1",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz",
+			"integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"undici-types": "~6.20.0"
+			}
+		},
+		"node_modules/@types/normalize-package-data": {
+			"version": "2.4.4",
+			"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
+			"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@types/semver": {
+			"version": "7.5.8",
+			"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
+			"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/@typescript-eslint/eslint-plugin": {
+			"version": "6.21.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz",
+			"integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@eslint-community/regexpp": "^4.5.1",
+				"@typescript-eslint/scope-manager": "6.21.0",
+				"@typescript-eslint/type-utils": "6.21.0",
+				"@typescript-eslint/utils": "6.21.0",
+				"@typescript-eslint/visitor-keys": "6.21.0",
+				"debug": "^4.3.4",
+				"graphemer": "^1.4.0",
+				"ignore": "^5.2.4",
+				"natural-compare": "^1.4.0",
+				"semver": "^7.5.4",
+				"ts-api-utils": "^1.0.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
+				"eslint": "^7.0.0 || ^8.0.0"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+			"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 4"
+			}
+		},
+		"node_modules/@typescript-eslint/parser": {
+			"version": "6.21.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
+			"integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"dependencies": {
+				"@typescript-eslint/scope-manager": "6.21.0",
+				"@typescript-eslint/types": "6.21.0",
+				"@typescript-eslint/typescript-estree": "6.21.0",
+				"@typescript-eslint/visitor-keys": "6.21.0",
+				"debug": "^4.3.4"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^7.0.0 || ^8.0.0"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/scope-manager": {
+			"version": "6.21.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
+			"integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@typescript-eslint/types": "6.21.0",
+				"@typescript-eslint/visitor-keys": "6.21.0"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/type-utils": {
+			"version": "6.21.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz",
+			"integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@typescript-eslint/typescript-estree": "6.21.0",
+				"@typescript-eslint/utils": "6.21.0",
+				"debug": "^4.3.4",
+				"ts-api-utils": "^1.0.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^7.0.0 || ^8.0.0"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/types": {
+			"version": "6.21.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
+			"integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/typescript-estree": {
+			"version": "6.21.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
+			"integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"dependencies": {
+				"@typescript-eslint/types": "6.21.0",
+				"@typescript-eslint/visitor-keys": "6.21.0",
+				"debug": "^4.3.4",
+				"globby": "^11.1.0",
+				"is-glob": "^4.0.3",
+				"minimatch": "9.0.3",
+				"semver": "^7.5.4",
+				"ts-api-utils": "^1.0.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+			"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"balanced-match": "^1.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/typescript-estree/node_modules/globby": {
+			"version": "11.1.0",
+			"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+			"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"array-union": "^2.1.0",
+				"dir-glob": "^3.0.1",
+				"fast-glob": "^3.2.9",
+				"ignore": "^5.2.0",
+				"merge2": "^1.4.1",
+				"slash": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/@typescript-eslint/typescript-estree/node_modules/ignore": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+			"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 4"
+			}
+		},
+		"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+			"version": "9.0.3",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+			"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"brace-expansion": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=16 || 14 >=14.17"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/@typescript-eslint/typescript-estree/node_modules/slash": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+			"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/@typescript-eslint/utils": {
+			"version": "6.21.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz",
+			"integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@eslint-community/eslint-utils": "^4.4.0",
+				"@types/json-schema": "^7.0.12",
+				"@types/semver": "^7.5.0",
+				"@typescript-eslint/scope-manager": "6.21.0",
+				"@typescript-eslint/types": "6.21.0",
+				"@typescript-eslint/typescript-estree": "6.21.0",
+				"semver": "^7.5.4"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^7.0.0 || ^8.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/visitor-keys": {
+			"version": "6.21.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
+			"integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@typescript-eslint/types": "6.21.0",
+				"eslint-visitor-keys": "^3.4.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@ungap/structured-clone": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
+			"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/@vercel/nft": {
+			"version": "0.27.10",
+			"resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.27.10.tgz",
+			"integrity": "sha512-zbaF9Wp/NsZtKLE4uVmL3FyfFwlpDyuymQM1kPbeT0mVOHKDQQNjnnfslB3REg3oZprmNFJuh3pkHBk2qAaizg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@mapbox/node-pre-gyp": "^2.0.0-rc.0",
+				"@rollup/pluginutils": "^5.1.3",
+				"acorn": "^8.6.0",
+				"acorn-import-attributes": "^1.9.5",
+				"async-sema": "^3.1.1",
+				"bindings": "^1.4.0",
+				"estree-walker": "2.0.2",
+				"glob": "^7.1.3",
+				"graceful-fs": "^4.2.9",
+				"node-gyp-build": "^4.2.2",
+				"picomatch": "^4.0.2",
+				"resolve-from": "^5.0.0"
+			},
+			"bin": {
+				"nft": "out/cli.js"
+			},
+			"engines": {
+				"node": ">=16"
+			}
+		},
+		"node_modules/@webassemblyjs/ast": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
+			"integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@webassemblyjs/helper-numbers": "1.13.2",
+				"@webassemblyjs/helper-wasm-bytecode": "1.13.2"
+			}
+		},
+		"node_modules/@webassemblyjs/floating-point-hex-parser": {
+			"version": "1.13.2",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
+			"integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/@webassemblyjs/helper-api-error": {
+			"version": "1.13.2",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
+			"integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/@webassemblyjs/helper-buffer": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
+			"integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/@webassemblyjs/helper-numbers": {
+			"version": "1.13.2",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
+			"integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@webassemblyjs/floating-point-hex-parser": "1.13.2",
+				"@webassemblyjs/helper-api-error": "1.13.2",
+				"@xtuc/long": "4.2.2"
+			}
+		},
+		"node_modules/@webassemblyjs/helper-wasm-bytecode": {
+			"version": "1.13.2",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
+			"integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/@webassemblyjs/helper-wasm-section": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
+			"integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@webassemblyjs/ast": "1.14.1",
+				"@webassemblyjs/helper-buffer": "1.14.1",
+				"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+				"@webassemblyjs/wasm-gen": "1.14.1"
+			}
+		},
+		"node_modules/@webassemblyjs/ieee754": {
+			"version": "1.13.2",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
+			"integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@xtuc/ieee754": "^1.2.0"
+			}
+		},
+		"node_modules/@webassemblyjs/leb128": {
+			"version": "1.13.2",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
+			"integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"peer": true,
+			"dependencies": {
+				"@xtuc/long": "4.2.2"
+			}
+		},
+		"node_modules/@webassemblyjs/utf8": {
+			"version": "1.13.2",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
+			"integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/@webassemblyjs/wasm-edit": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
+			"integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@webassemblyjs/ast": "1.14.1",
+				"@webassemblyjs/helper-buffer": "1.14.1",
+				"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+				"@webassemblyjs/helper-wasm-section": "1.14.1",
+				"@webassemblyjs/wasm-gen": "1.14.1",
+				"@webassemblyjs/wasm-opt": "1.14.1",
+				"@webassemblyjs/wasm-parser": "1.14.1",
+				"@webassemblyjs/wast-printer": "1.14.1"
+			}
+		},
+		"node_modules/@webassemblyjs/wasm-gen": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
+			"integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@webassemblyjs/ast": "1.14.1",
+				"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+				"@webassemblyjs/ieee754": "1.13.2",
+				"@webassemblyjs/leb128": "1.13.2",
+				"@webassemblyjs/utf8": "1.13.2"
+			}
+		},
+		"node_modules/@webassemblyjs/wasm-opt": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
+			"integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@webassemblyjs/ast": "1.14.1",
+				"@webassemblyjs/helper-buffer": "1.14.1",
+				"@webassemblyjs/wasm-gen": "1.14.1",
+				"@webassemblyjs/wasm-parser": "1.14.1"
+			}
+		},
+		"node_modules/@webassemblyjs/wasm-parser": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
+			"integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@webassemblyjs/ast": "1.14.1",
+				"@webassemblyjs/helper-api-error": "1.13.2",
+				"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+				"@webassemblyjs/ieee754": "1.13.2",
+				"@webassemblyjs/leb128": "1.13.2",
+				"@webassemblyjs/utf8": "1.13.2"
+			}
+		},
+		"node_modules/@webassemblyjs/wast-printer": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
+			"integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@webassemblyjs/ast": "1.14.1",
+				"@xtuc/long": "4.2.2"
+			}
+		},
+		"node_modules/@xmldom/xmldom": {
+			"version": "0.8.10",
+			"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+			"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=10.0.0"
+			}
+		},
+		"node_modules/@xtuc/ieee754": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+			"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+			"dev": true,
+			"license": "BSD-3-Clause",
+			"peer": true
+		},
+		"node_modules/@xtuc/long": {
+			"version": "4.2.2",
+			"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+			"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"peer": true
+		},
+		"node_modules/abbrev": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.0.tgz",
+			"integrity": "sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==",
+			"dev": true,
+			"license": "ISC",
+			"engines": {
+				"node": "^18.17.0 || >=20.5.0"
+			}
+		},
+		"node_modules/acorn": {
+			"version": "8.14.0",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+			"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"acorn": "bin/acorn"
+			},
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/acorn-import-attributes": {
+			"version": "1.9.5",
+			"resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
+			"integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
+			"dev": true,
+			"license": "MIT",
+			"peerDependencies": {
+				"acorn": "^8"
+			}
+		},
+		"node_modules/acorn-jsx": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+			"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+			"dev": true,
+			"license": "MIT",
+			"peerDependencies": {
+				"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+			}
+		},
+		"node_modules/acorn-walk": {
+			"version": "8.3.4",
+			"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
+			"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"acorn": "^8.11.0"
+			},
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/agent-base": {
+			"version": "7.1.3",
+			"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+			"integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 14"
+			}
+		},
+		"node_modules/ajv": {
+			"version": "6.12.6",
+			"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+			"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"fast-deep-equal": "^3.1.1",
+				"fast-json-stable-stringify": "^2.0.0",
+				"json-schema-traverse": "^0.4.1",
+				"uri-js": "^4.2.2"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/epoberezkin"
+			}
+		},
+		"node_modules/ajv-formats": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+			"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"ajv": "^8.0.0"
+			},
+			"peerDependencies": {
+				"ajv": "^8.0.0"
+			},
+			"peerDependenciesMeta": {
+				"ajv": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/ajv-formats/node_modules/ajv": {
+			"version": "8.17.1",
+			"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+			"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"fast-deep-equal": "^3.1.3",
+				"fast-uri": "^3.0.1",
+				"json-schema-traverse": "^1.0.0",
+				"require-from-string": "^2.0.2"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/epoberezkin"
+			}
+		},
+		"node_modules/ajv-formats/node_modules/json-schema-traverse": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+			"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/ajv-keywords": {
+			"version": "3.5.2",
+			"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+			"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"peerDependencies": {
+				"ajv": "^6.9.1"
+			}
+		},
+		"node_modules/ansi-escapes": {
+			"version": "4.3.2",
+			"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+			"integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"type-fest": "^0.21.3"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/ansi-escapes/node_modules/type-fest": {
+			"version": "0.21.3",
+			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+			"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+			"dev": true,
+			"license": "(MIT OR CC0-1.0)",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/ansi-regex": {
+			"version": "6.1.0",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+			"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/ansi-regex?sponsor=1"
+			}
+		},
+		"node_modules/ansi-styles": {
+			"version": "6.2.1",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+			"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
+			}
+		},
+		"node_modules/appdmg": {
+			"version": "0.6.6",
+			"resolved": "https://registry.npmjs.org/appdmg/-/appdmg-0.6.6.tgz",
+			"integrity": "sha512-GRmFKlCG+PWbcYF4LUNonTYmy0GjguDy6Jh9WP8mpd0T6j80XIJyXBiWlD0U+MLNhqV9Nhx49Gl9GpVToulpLg==",
+			"license": "MIT",
+			"os": [
+				"darwin"
+			],
+			"dependencies": {
+				"async": "^1.4.2",
+				"ds-store": "^0.1.5",
+				"execa": "^1.0.0",
+				"fs-temp": "^1.0.0",
+				"fs-xattr": "^0.3.0",
+				"image-size": "^0.7.4",
+				"is-my-json-valid": "^2.20.0",
+				"minimist": "^1.1.3",
+				"parse-color": "^1.0.0",
+				"path-exists": "^4.0.0",
+				"repeat-string": "^1.5.4"
+			},
+			"bin": {
+				"appdmg": "bin/appdmg.js"
+			},
+			"engines": {
+				"node": ">=8.5"
+			}
+		},
+		"node_modules/appdmg/node_modules/cross-spawn": {
+			"version": "6.0.6",
+			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz",
+			"integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==",
+			"license": "MIT",
+			"dependencies": {
+				"nice-try": "^1.0.4",
+				"path-key": "^2.0.1",
+				"semver": "^5.5.0",
+				"shebang-command": "^1.2.0",
+				"which": "^1.2.9"
+			},
+			"engines": {
+				"node": ">=4.8"
+			}
+		},
+		"node_modules/appdmg/node_modules/execa": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+			"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+			"license": "MIT",
+			"dependencies": {
+				"cross-spawn": "^6.0.0",
+				"get-stream": "^4.0.0",
+				"is-stream": "^1.1.0",
+				"npm-run-path": "^2.0.0",
+				"p-finally": "^1.0.0",
+				"signal-exit": "^3.0.0",
+				"strip-eof": "^1.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/appdmg/node_modules/get-stream": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+			"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+			"license": "MIT",
+			"dependencies": {
+				"pump": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/appdmg/node_modules/is-stream": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+			"integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/appdmg/node_modules/npm-run-path": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+			"integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
+			"license": "MIT",
+			"dependencies": {
+				"path-key": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/appdmg/node_modules/path-key": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+			"integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/appdmg/node_modules/semver": {
+			"version": "5.7.2",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+			"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+			"license": "ISC",
+			"bin": {
+				"semver": "bin/semver"
+			}
+		},
+		"node_modules/appdmg/node_modules/shebang-command": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+			"integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+			"license": "MIT",
+			"dependencies": {
+				"shebang-regex": "^1.0.0"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/appdmg/node_modules/shebang-regex": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+			"integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/appdmg/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==",
+			"license": "ISC"
+		},
+		"node_modules/appdmg/node_modules/which": {
+			"version": "1.3.1",
+			"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+			"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+			"license": "ISC",
+			"dependencies": {
+				"isexe": "^2.0.0"
+			},
+			"bin": {
+				"which": "bin/which"
+			}
+		},
+		"node_modules/argparse": {
+			"version": "1.0.10",
+			"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+			"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"sprintf-js": "~1.0.2"
+			}
+		},
+		"node_modules/array-buffer-byte-length": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+			"integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"is-array-buffer": "^3.0.5"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/array-find-index": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+			"integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/array-includes": {
+			"version": "3.1.8",
+			"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
+			"integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.7",
+				"define-properties": "^1.2.1",
+				"es-abstract": "^1.23.2",
+				"es-object-atoms": "^1.0.0",
+				"get-intrinsic": "^1.2.4",
+				"is-string": "^1.0.7"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/array-parallel": {
+			"version": "0.1.3",
+			"resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz",
+			"integrity": "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w==",
+			"license": "MIT"
+		},
+		"node_modules/array-series": {
+			"version": "0.1.5",
+			"resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz",
+			"integrity": "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg==",
+			"license": "MIT"
+		},
+		"node_modules/array-union": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+			"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/array.prototype.flat": {
+			"version": "1.3.3",
+			"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
+			"integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"define-properties": "^1.2.1",
+				"es-abstract": "^1.23.5",
+				"es-shim-unscopables": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/array.prototype.flatmap": {
+			"version": "1.3.3",
+			"resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
+			"integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"define-properties": "^1.2.1",
+				"es-abstract": "^1.23.5",
+				"es-shim-unscopables": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/arraybuffer.prototype.slice": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+			"integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"array-buffer-byte-length": "^1.0.1",
+				"call-bind": "^1.0.8",
+				"define-properties": "^1.2.1",
+				"es-abstract": "^1.23.5",
+				"es-errors": "^1.3.0",
+				"get-intrinsic": "^1.2.6",
+				"is-array-buffer": "^3.0.4"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/arrgv": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz",
+			"integrity": "sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8.0.0"
+			}
+		},
+		"node_modules/arrify": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz",
+			"integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/async": {
+			"version": "1.5.2",
+			"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+			"integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==",
+			"license": "MIT"
+		},
+		"node_modules/async-function": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
+			"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/async-sema": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz",
+			"integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/ava": {
+			"version": "6.2.0",
+			"resolved": "https://registry.npmjs.org/ava/-/ava-6.2.0.tgz",
+			"integrity": "sha512-+GZk5PbyepjiO/68hzCZCUepQOQauKfNnI7sA4JukBTg97jD7E+tDKEA7OhGOGr6EorNNMM9+jqvgHVOTOzG4w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@vercel/nft": "^0.27.5",
+				"acorn": "^8.13.0",
+				"acorn-walk": "^8.3.4",
+				"ansi-styles": "^6.2.1",
+				"arrgv": "^1.0.2",
+				"arrify": "^3.0.0",
+				"callsites": "^4.2.0",
+				"cbor": "^9.0.2",
+				"chalk": "^5.3.0",
+				"chunkd": "^2.0.1",
+				"ci-info": "^4.0.0",
+				"ci-parallel-vars": "^1.0.1",
+				"cli-truncate": "^4.0.0",
+				"code-excerpt": "^4.0.0",
+				"common-path-prefix": "^3.0.0",
+				"concordance": "^5.0.4",
+				"currently-unhandled": "^0.4.1",
+				"debug": "^4.3.7",
+				"emittery": "^1.0.3",
+				"figures": "^6.1.0",
+				"globby": "^14.0.2",
+				"ignore-by-default": "^2.1.0",
+				"indent-string": "^5.0.0",
+				"is-plain-object": "^5.0.0",
+				"is-promise": "^4.0.0",
+				"matcher": "^5.0.0",
+				"memoize": "^10.0.0",
+				"ms": "^2.1.3",
+				"p-map": "^7.0.2",
+				"package-config": "^5.0.0",
+				"picomatch": "^4.0.2",
+				"plur": "^5.1.0",
+				"pretty-ms": "^9.1.0",
+				"resolve-cwd": "^3.0.0",
+				"stack-utils": "^2.0.6",
+				"strip-ansi": "^7.1.0",
+				"supertap": "^3.0.1",
+				"temp-dir": "^3.0.0",
+				"write-file-atomic": "^6.0.0",
+				"yargs": "^17.7.2"
+			},
+			"bin": {
+				"ava": "entrypoints/cli.mjs"
+			},
+			"engines": {
+				"node": "^18.18 || ^20.8 || ^22 || >=23"
+			},
+			"peerDependencies": {
+				"@ava/typescript": "*"
+			},
+			"peerDependenciesMeta": {
+				"@ava/typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/available-typed-arrays": {
+			"version": "1.0.7",
+			"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+			"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"possible-typed-array-names": "^1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/balanced-match": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+			"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/base32-encode": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/base32-encode/-/base32-encode-1.2.0.tgz",
+			"integrity": "sha512-cHFU8XeRyx0GgmoWi5qHMCVRiqU6J3MHWxVgun7jggCBUpVzm1Ir7M9dYr2whjSNc3tFeXfQ/oZjQu/4u55h9A==",
+			"license": "MIT",
+			"dependencies": {
+				"to-data-view": "^1.1.0"
+			}
+		},
+		"node_modules/base64-js": {
+			"version": "1.5.1",
+			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+			"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			],
+			"license": "MIT"
+		},
+		"node_modules/bindings": {
+			"version": "1.5.0",
+			"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+			"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"file-uri-to-path": "1.0.0"
+			}
+		},
+		"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==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/bplist-creator": {
+			"version": "0.0.8",
+			"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz",
+			"integrity": "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==",
+			"license": "MIT",
+			"dependencies": {
+				"stream-buffers": "~2.2.0"
+			}
+		},
+		"node_modules/brace-expansion": {
+			"version": "1.1.11",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+			"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"balanced-match": "^1.0.0",
+				"concat-map": "0.0.1"
+			}
+		},
+		"node_modules/braces": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+			"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"fill-range": "^7.1.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/browserslist": {
+			"version": "4.24.4",
+			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
+			"integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/browserslist"
+				},
+				{
+					"type": "tidelift",
+					"url": "https://tidelift.com/funding/github/npm/browserslist"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"caniuse-lite": "^1.0.30001688",
+				"electron-to-chromium": "^1.5.73",
+				"node-releases": "^2.0.19",
+				"update-browserslist-db": "^1.1.1"
+			},
+			"bin": {
+				"browserslist": "cli.js"
+			},
+			"engines": {
+				"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+			}
+		},
+		"node_modules/buffer-from": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+			"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/builtin-modules": {
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+			"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/builtins": {
+			"version": "5.1.0",
+			"resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz",
+			"integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"semver": "^7.0.0"
+			}
+		},
+		"node_modules/call-bind": {
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
+			"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind-apply-helpers": "^1.0.0",
+				"es-define-property": "^1.0.0",
+				"get-intrinsic": "^1.2.4",
+				"set-function-length": "^1.2.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/call-bind-apply-helpers": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
+			"integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"es-errors": "^1.3.0",
+				"function-bind": "^1.1.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/call-bound": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
+			"integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind-apply-helpers": "^1.0.1",
+				"get-intrinsic": "^1.2.6"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/callsites": {
+			"version": "4.2.0",
+			"resolved": "https://registry.npmjs.org/callsites/-/callsites-4.2.0.tgz",
+			"integrity": "sha512-kfzR4zzQtAE9PC7CzZsjl3aBNbXWuXiSeOCdLcPpBfGW8YuCqQHcRPFDbr/BPVmd3EEPVpuFzLyuT/cUhPr4OQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12.20"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/caniuse-lite": {
+			"version": "1.0.30001699",
+			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz",
+			"integrity": "sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/browserslist"
+				},
+				{
+					"type": "tidelift",
+					"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
+			"license": "CC-BY-4.0",
+			"peer": true
+		},
+		"node_modules/cbor": {
+			"version": "9.0.2",
+			"resolved": "https://registry.npmjs.org/cbor/-/cbor-9.0.2.tgz",
+			"integrity": "sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"nofilter": "^3.1.0"
+			},
+			"engines": {
+				"node": ">=16"
+			}
+		},
+		"node_modules/chalk": {
+			"version": "5.4.1",
+			"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
+			"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
+			"license": "MIT",
+			"engines": {
+				"node": "^12.17.0 || ^14.13 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/chalk?sponsor=1"
+			}
+		},
+		"node_modules/chownr": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+			"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+			"dev": true,
+			"license": "BlueOak-1.0.0",
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/chrome-trace-event": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
+			"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"engines": {
+				"node": ">=6.0"
+			}
+		},
+		"node_modules/chunkd": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/chunkd/-/chunkd-2.0.1.tgz",
+			"integrity": "sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/ci-info": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.1.0.tgz",
+			"integrity": "sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/sibiraj-s"
+				}
+			],
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/ci-parallel-vars": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/ci-parallel-vars/-/ci-parallel-vars-1.0.1.tgz",
+			"integrity": "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/clean-regexp": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz",
+			"integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"escape-string-regexp": "^1.0.5"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/clean-regexp/node_modules/escape-string-regexp": {
+			"version": "1.0.5",
+			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+			"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.8.0"
+			}
+		},
+		"node_modules/cli-cursor": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+			"integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
+			"license": "MIT",
+			"dependencies": {
+				"restore-cursor": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/cli-spinners": {
+			"version": "2.9.2",
+			"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+			"integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/cli-truncate": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
+			"integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"slice-ansi": "^5.0.0",
+				"string-width": "^7.0.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/cliui": {
+			"version": "8.0.1",
+			"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+			"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"string-width": "^4.2.0",
+				"strip-ansi": "^6.0.1",
+				"wrap-ansi": "^7.0.0"
+			},
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/cliui/node_modules/ansi-regex": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/cliui/node_modules/emoji-regex": {
+			"version": "8.0.0",
+			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/cliui/node_modules/is-fullwidth-code-point": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/cliui/node_modules/string-width": {
+			"version": "4.2.3",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+			"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"emoji-regex": "^8.0.0",
+				"is-fullwidth-code-point": "^3.0.0",
+				"strip-ansi": "^6.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/cliui/node_modules/strip-ansi": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-regex": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/code-excerpt": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz",
+			"integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"convert-to-spaces": "^2.0.1"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			}
+		},
+		"node_modules/color-convert": {
+			"version": "0.5.3",
+			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
+			"integrity": "sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling=="
+		},
+		"node_modules/color-name": {
+			"version": "1.1.4",
+			"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+			"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/commander": {
+			"version": "2.20.3",
+			"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+			"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/common-path-prefix": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz",
+			"integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/concat-map": {
+			"version": "0.0.1",
+			"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+			"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/concordance": {
+			"version": "5.0.4",
+			"resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz",
+			"integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==",
+			"dev": true,
+			"license": "ISC",
+			"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/confusing-browser-globals": {
+			"version": "1.0.11",
+			"resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
+			"integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/consola": {
+			"version": "3.4.0",
+			"resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz",
+			"integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^14.18.0 || >=16.10.0"
+			}
+		},
+		"node_modules/convert-to-spaces": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz",
+			"integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			}
+		},
+		"node_modules/cosmiconfig": {
+			"version": "8.3.6",
+			"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz",
+			"integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"import-fresh": "^3.3.0",
+				"js-yaml": "^4.1.0",
+				"parse-json": "^5.2.0",
+				"path-type": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=14"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/d-fischer"
+			},
+			"peerDependencies": {
+				"typescript": ">=4.9.5"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/cosmiconfig/node_modules/argparse": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+			"dev": true,
+			"license": "Python-2.0"
+		},
+		"node_modules/cosmiconfig/node_modules/js-yaml": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"argparse": "^2.0.1"
+			},
+			"bin": {
+				"js-yaml": "bin/js-yaml.js"
+			}
+		},
+		"node_modules/cosmiconfig/node_modules/path-type": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+			"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/cross-spawn": {
+			"version": "7.0.6",
+			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+			"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+			"license": "MIT",
+			"dependencies": {
+				"path-key": "^3.1.0",
+				"shebang-command": "^2.0.0",
+				"which": "^2.0.1"
+			},
+			"engines": {
+				"node": ">= 8"
+			}
+		},
+		"node_modules/crypto-random-string": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz",
+			"integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==",
+			"license": "MIT",
+			"dependencies": {
+				"type-fest": "^1.0.1"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/crypto-random-string/node_modules/type-fest": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
+			"integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
+			"license": "(MIT OR CC0-1.0)",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/currently-unhandled": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+			"integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"array-find-index": "^1.0.1"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/data-view-buffer": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+			"integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"es-errors": "^1.3.0",
+				"is-data-view": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/data-view-byte-length": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+			"integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"es-errors": "^1.3.0",
+				"is-data-view": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/inspect-js"
+			}
+		},
+		"node_modules/data-view-byte-offset": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+			"integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.2",
+				"es-errors": "^1.3.0",
+				"is-data-view": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"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==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"time-zone": "^1.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/debug": {
+			"version": "4.4.0",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+			"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ms": "^2.1.3"
+			},
+			"engines": {
+				"node": ">=6.0"
+			},
+			"peerDependenciesMeta": {
+				"supports-color": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/deep-is": {
+			"version": "0.1.4",
+			"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+			"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/define-data-property": {
+			"version": "1.1.4",
+			"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+			"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"es-define-property": "^1.0.0",
+				"es-errors": "^1.3.0",
+				"gopd": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"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==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/define-properties": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+			"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"define-data-property": "^1.0.1",
+				"has-property-descriptors": "^1.0.0",
+				"object-keys": "^1.1.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/detect-libc": {
+			"version": "2.0.3",
+			"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+			"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/dir-glob": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+			"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"path-type": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/dir-glob/node_modules/path-type": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+			"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/doctrine": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+			"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"dependencies": {
+				"esutils": "^2.0.2"
+			},
+			"engines": {
+				"node": ">=6.0.0"
+			}
+		},
+		"node_modules/ds-store": {
+			"version": "0.1.6",
+			"resolved": "https://registry.npmjs.org/ds-store/-/ds-store-0.1.6.tgz",
+			"integrity": "sha512-kY21M6Lz+76OS3bnCzjdsJSF7LBpLYGCVfavW8TgQD2XkcqIZ86W0y9qUDZu6fp7SIZzqosMDW2zi7zVFfv4hw==",
+			"license": "MIT",
+			"dependencies": {
+				"bplist-creator": "~0.0.3",
+				"macos-alias": "~0.2.5",
+				"tn1150": "^0.1.0"
+			}
+		},
+		"node_modules/dunder-proto": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+			"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind-apply-helpers": "^1.0.1",
+				"es-errors": "^1.3.0",
+				"gopd": "^1.2.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/eastasianwidth": {
+			"version": "0.2.0",
+			"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+			"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/electron-to-chromium": {
+			"version": "1.5.97",
+			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.97.tgz",
+			"integrity": "sha512-HKLtaH02augM7ZOdYRuO19rWDeY+QSJ1VxnXFa/XDFLf07HvM90pALIJFgrO+UVaajI3+aJMMpojoUTLZyQ7JQ==",
+			"dev": true,
+			"license": "ISC",
+			"peer": true
+		},
+		"node_modules/emittery": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/emittery/-/emittery-1.1.0.tgz",
+			"integrity": "sha512-rsX7ktqARv/6UQDgMaLfIqUWAEzzbCQiVh7V9rhDXp6c37yoJcks12NVD+XPkgl4AEavmNhVfrhGoqYwIsMYYA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=14.16"
+			},
+			"funding": {
+				"url": "https://github.com/sindresorhus/emittery?sponsor=1"
+			}
+		},
+		"node_modules/emoji-regex": {
+			"version": "10.4.0",
+			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
+			"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
+			"license": "MIT"
+		},
+		"node_modules/encode-utf8": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz",
+			"integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==",
+			"license": "MIT"
+		},
+		"node_modules/end-of-stream": {
+			"version": "1.4.4",
+			"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+			"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+			"license": "MIT",
+			"dependencies": {
+				"once": "^1.4.0"
+			}
+		},
+		"node_modules/enhance-visitors": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/enhance-visitors/-/enhance-visitors-1.0.0.tgz",
+			"integrity": "sha512-+29eJLiUixTEDRaZ35Vu8jP3gPLNcQQkQkOQjLp2X+6cZGGPDD/uasbFzvLsJKnGZnvmyZ0srxudwOtskHeIDA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"lodash": "^4.13.1"
+			},
+			"engines": {
+				"node": ">=4.0.0"
+			}
+		},
+		"node_modules/enhanced-resolve": {
+			"version": "0.9.1",
+			"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz",
+			"integrity": "sha512-kxpoMgrdtkXZ5h0SeraBS1iRntpTpQ3R8ussdb38+UAFnMGX5DDyJXePm+OCHOcoXvHDw7mc2erbJBpDnl7TPw==",
+			"dev": true,
+			"dependencies": {
+				"graceful-fs": "^4.1.2",
+				"memory-fs": "^0.2.0",
+				"tapable": "^0.1.8"
+			},
+			"engines": {
+				"node": ">=0.6"
+			}
+		},
+		"node_modules/env-editor": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/env-editor/-/env-editor-1.1.0.tgz",
+			"integrity": "sha512-7AXskzN6T7Q9TFcKAGJprUbpQa4i1VsAetO9rdBqbGMGlragTziBgWt4pVYJMBWHQlLoX0buy6WFikzPH4Qjpw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/error-ex": {
+			"version": "1.3.2",
+			"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+			"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-arrayish": "^0.2.1"
+			}
+		},
+		"node_modules/es-abstract": {
+			"version": "1.23.9",
+			"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz",
+			"integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"array-buffer-byte-length": "^1.0.2",
+				"arraybuffer.prototype.slice": "^1.0.4",
+				"available-typed-arrays": "^1.0.7",
+				"call-bind": "^1.0.8",
+				"call-bound": "^1.0.3",
+				"data-view-buffer": "^1.0.2",
+				"data-view-byte-length": "^1.0.2",
+				"data-view-byte-offset": "^1.0.1",
+				"es-define-property": "^1.0.1",
+				"es-errors": "^1.3.0",
+				"es-object-atoms": "^1.0.0",
+				"es-set-tostringtag": "^2.1.0",
+				"es-to-primitive": "^1.3.0",
+				"function.prototype.name": "^1.1.8",
+				"get-intrinsic": "^1.2.7",
+				"get-proto": "^1.0.0",
+				"get-symbol-description": "^1.1.0",
+				"globalthis": "^1.0.4",
+				"gopd": "^1.2.0",
+				"has-property-descriptors": "^1.0.2",
+				"has-proto": "^1.2.0",
+				"has-symbols": "^1.1.0",
+				"hasown": "^2.0.2",
+				"internal-slot": "^1.1.0",
+				"is-array-buffer": "^3.0.5",
+				"is-callable": "^1.2.7",
+				"is-data-view": "^1.0.2",
+				"is-regex": "^1.2.1",
+				"is-shared-array-buffer": "^1.0.4",
+				"is-string": "^1.1.1",
+				"is-typed-array": "^1.1.15",
+				"is-weakref": "^1.1.0",
+				"math-intrinsics": "^1.1.0",
+				"object-inspect": "^1.13.3",
+				"object-keys": "^1.1.1",
+				"object.assign": "^4.1.7",
+				"own-keys": "^1.0.1",
+				"regexp.prototype.flags": "^1.5.3",
+				"safe-array-concat": "^1.1.3",
+				"safe-push-apply": "^1.0.0",
+				"safe-regex-test": "^1.1.0",
+				"set-proto": "^1.0.0",
+				"string.prototype.trim": "^1.2.10",
+				"string.prototype.trimend": "^1.0.9",
+				"string.prototype.trimstart": "^1.0.8",
+				"typed-array-buffer": "^1.0.3",
+				"typed-array-byte-length": "^1.0.3",
+				"typed-array-byte-offset": "^1.0.4",
+				"typed-array-length": "^1.0.7",
+				"unbox-primitive": "^1.1.0",
+				"which-typed-array": "^1.1.18"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/es-define-property": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+			"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/es-errors": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+			"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/es-module-lexer": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
+			"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/es-object-atoms": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+			"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"es-errors": "^1.3.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/es-set-tostringtag": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+			"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"es-errors": "^1.3.0",
+				"get-intrinsic": "^1.2.6",
+				"has-tostringtag": "^1.0.2",
+				"hasown": "^2.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/es-shim-unscopables": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
+			"integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"hasown": "^2.0.0"
+			}
+		},
+		"node_modules/es-to-primitive": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
+			"integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-callable": "^1.2.7",
+				"is-date-object": "^1.0.5",
+				"is-symbol": "^1.0.4"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/escalade": {
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+			"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/escape-string-regexp": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+			"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint": {
+			"version": "8.57.1",
+			"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
+			"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
+			"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@eslint-community/eslint-utils": "^4.2.0",
+				"@eslint-community/regexpp": "^4.6.1",
+				"@eslint/eslintrc": "^2.1.4",
+				"@eslint/js": "8.57.1",
+				"@humanwhocodes/config-array": "^0.13.0",
+				"@humanwhocodes/module-importer": "^1.0.1",
+				"@nodelib/fs.walk": "^1.2.8",
+				"@ungap/structured-clone": "^1.2.0",
+				"ajv": "^6.12.4",
+				"chalk": "^4.0.0",
+				"cross-spawn": "^7.0.2",
+				"debug": "^4.3.2",
+				"doctrine": "^3.0.0",
+				"escape-string-regexp": "^4.0.0",
+				"eslint-scope": "^7.2.2",
+				"eslint-visitor-keys": "^3.4.3",
+				"espree": "^9.6.1",
+				"esquery": "^1.4.2",
+				"esutils": "^2.0.2",
+				"fast-deep-equal": "^3.1.3",
+				"file-entry-cache": "^6.0.1",
+				"find-up": "^5.0.0",
+				"glob-parent": "^6.0.2",
+				"globals": "^13.19.0",
+				"graphemer": "^1.4.0",
+				"ignore": "^5.2.0",
+				"imurmurhash": "^0.1.4",
+				"is-glob": "^4.0.0",
+				"is-path-inside": "^3.0.3",
+				"js-yaml": "^4.1.0",
+				"json-stable-stringify-without-jsonify": "^1.0.1",
+				"levn": "^0.4.1",
+				"lodash.merge": "^4.6.2",
+				"minimatch": "^3.1.2",
+				"natural-compare": "^1.4.0",
+				"optionator": "^0.9.3",
+				"strip-ansi": "^6.0.1",
+				"text-table": "^0.2.0"
+			},
+			"bin": {
+				"eslint": "bin/eslint.js"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			}
+		},
+		"node_modules/eslint-compat-utils": {
+			"version": "0.5.1",
+			"resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz",
+			"integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"semver": "^7.5.4"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"peerDependencies": {
+				"eslint": ">=6.0.0"
+			}
+		},
+		"node_modules/eslint-config-prettier": {
+			"version": "8.10.0",
+			"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz",
+			"integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"eslint-config-prettier": "bin/cli.js"
+			},
+			"peerDependencies": {
+				"eslint": ">=7.0.0"
+			}
+		},
+		"node_modules/eslint-config-xo": {
+			"version": "0.43.1",
+			"resolved": "https://registry.npmjs.org/eslint-config-xo/-/eslint-config-xo-0.43.1.tgz",
+			"integrity": "sha512-azv1L2PysRA0NkZOgbndUpN+581L7wPqkgJOgxxw3hxwXAbJgD6Hqb/SjHRiACifXt/AvxCzE/jIKFAlI7XjvQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"confusing-browser-globals": "1.0.11"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			},
+			"peerDependencies": {
+				"eslint": ">=8.27.0"
+			}
+		},
+		"node_modules/eslint-config-xo-typescript": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/eslint-config-xo-typescript/-/eslint-config-xo-typescript-1.0.1.tgz",
+			"integrity": "sha512-vPQssnRSUgBFOEfB/KY12CXwltwFSn4RSCfa+w7gjBC2PFQ7Yfgmyei+1XUZ3K+8LRGef2NMJUcxts7PldhDjg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=16"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			},
+			"peerDependencies": {
+				"@typescript-eslint/eslint-plugin": ">=6.0.0",
+				"@typescript-eslint/parser": ">=6.0.0",
+				"eslint": ">=8.0.0",
+				"typescript": ">=4.7"
+			}
+		},
+		"node_modules/eslint-formatter-pretty": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/eslint-formatter-pretty/-/eslint-formatter-pretty-5.0.0.tgz",
+			"integrity": "sha512-Uick451FoL22/wXqyScX3inW8ZlD/GQO7eFXj3bqb6N/ZtuuF00/CwSNIKLbFCJPrX5V4EdQBSgJ/UVnmLRnug==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@types/eslint": "^8.0.0",
+				"ansi-escapes": "^4.2.1",
+				"chalk": "^4.1.0",
+				"eslint-rule-docs": "^1.1.235",
+				"log-symbols": "^4.0.0",
+				"plur": "^4.0.0",
+				"string-width": "^4.2.0",
+				"supports-hyperlinks": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=14.16"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/ansi-regex": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/ansi-styles": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+			"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-convert": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/chalk": {
+			"version": "4.1.2",
+			"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+			"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-styles": "^4.1.0",
+				"supports-color": "^7.1.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/chalk?sponsor=1"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/color-convert": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+			"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-name": "~1.1.4"
+			},
+			"engines": {
+				"node": ">=7.0.0"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/emoji-regex": {
+			"version": "8.0.0",
+			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/is-fullwidth-code-point": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/is-unicode-supported": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+			"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/log-symbols": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+			"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"chalk": "^4.1.0",
+				"is-unicode-supported": "^0.1.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/plur": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz",
+			"integrity": "sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"irregular-plurals": "^3.2.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/string-width": {
+			"version": "4.2.3",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+			"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"emoji-regex": "^8.0.0",
+				"is-fullwidth-code-point": "^3.0.0",
+				"strip-ansi": "^6.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/eslint-formatter-pretty/node_modules/strip-ansi": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-regex": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/eslint-import-resolver-node": {
+			"version": "0.3.9",
+			"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
+			"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"debug": "^3.2.7",
+				"is-core-module": "^2.13.0",
+				"resolve": "^1.22.4"
+			}
+		},
+		"node_modules/eslint-import-resolver-node/node_modules/debug": {
+			"version": "3.2.7",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+			"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ms": "^2.1.1"
+			}
+		},
+		"node_modules/eslint-import-resolver-node/node_modules/resolve": {
+			"version": "1.22.10",
+			"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+			"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-core-module": "^2.16.0",
+				"path-parse": "^1.0.7",
+				"supports-preserve-symlinks-flag": "^1.0.0"
+			},
+			"bin": {
+				"resolve": "bin/resolve"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/eslint-import-resolver-webpack": {
+			"version": "0.13.10",
+			"resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.10.tgz",
+			"integrity": "sha512-ciVTEg7sA56wRMR772PyjcBRmyBMLS46xgzQZqt6cWBEKc7cK65ZSSLCTLVRu2gGtKyXUb5stwf4xxLBfERLFA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"debug": "^3.2.7",
+				"enhanced-resolve": "^0.9.1",
+				"find-root": "^1.1.0",
+				"hasown": "^2.0.2",
+				"interpret": "^1.4.0",
+				"is-core-module": "^2.15.1",
+				"is-regex": "^1.2.0",
+				"lodash": "^4.17.21",
+				"resolve": "^2.0.0-next.5",
+				"semver": "^5.7.2"
+			},
+			"engines": {
+				"node": ">= 6"
+			},
+			"peerDependencies": {
+				"eslint-plugin-import": ">=1.4.0",
+				"webpack": ">=1.11.0"
+			}
+		},
+		"node_modules/eslint-import-resolver-webpack/node_modules/debug": {
+			"version": "3.2.7",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+			"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ms": "^2.1.1"
+			}
+		},
+		"node_modules/eslint-import-resolver-webpack/node_modules/semver": {
+			"version": "5.7.2",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+			"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+			"dev": true,
+			"license": "ISC",
+			"bin": {
+				"semver": "bin/semver"
+			}
+		},
+		"node_modules/eslint-module-utils": {
+			"version": "2.12.0",
+			"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz",
+			"integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"debug": "^3.2.7"
+			},
+			"engines": {
+				"node": ">=4"
+			},
+			"peerDependenciesMeta": {
+				"eslint": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/eslint-module-utils/node_modules/debug": {
+			"version": "3.2.7",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+			"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ms": "^2.1.1"
+			}
+		},
+		"node_modules/eslint-plugin-ava": {
+			"version": "14.0.0",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-ava/-/eslint-plugin-ava-14.0.0.tgz",
+			"integrity": "sha512-XmKT6hppaipwwnLVwwvQliSU6AF1QMHiNoLD5JQfzhUhf0jY7CO0O624fQrE+Y/fTb9vbW8r77nKf7M/oHulxw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"enhance-visitors": "^1.0.0",
+				"eslint-utils": "^3.0.0",
+				"espree": "^9.0.0",
+				"espurify": "^2.1.1",
+				"import-modules": "^2.1.0",
+				"micro-spelling-correcter": "^1.1.1",
+				"pkg-dir": "^5.0.0",
+				"resolve-from": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=14.17 <15 || >=16.4"
+			},
+			"peerDependencies": {
+				"eslint": ">=8.26.0"
+			}
+		},
+		"node_modules/eslint-plugin-es-x": {
+			"version": "7.8.0",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz",
+			"integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==",
+			"dev": true,
+			"funding": [
+				"https://github.com/sponsors/ota-meshi",
+				"https://opencollective.com/eslint"
+			],
+			"license": "MIT",
+			"dependencies": {
+				"@eslint-community/eslint-utils": "^4.1.2",
+				"@eslint-community/regexpp": "^4.11.0",
+				"eslint-compat-utils": "^0.5.1"
+			},
+			"engines": {
+				"node": "^14.18.0 || >=16.0.0"
+			},
+			"peerDependencies": {
+				"eslint": ">=8"
+			}
+		},
+		"node_modules/eslint-plugin-eslint-comments": {
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz",
+			"integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"escape-string-regexp": "^1.0.5",
+				"ignore": "^5.0.5"
+			},
+			"engines": {
+				"node": ">=6.5.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/mysticatea"
+			},
+			"peerDependencies": {
+				"eslint": ">=4.19.1"
+			}
+		},
+		"node_modules/eslint-plugin-eslint-comments/node_modules/escape-string-regexp": {
+			"version": "1.0.5",
+			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+			"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.8.0"
+			}
+		},
+		"node_modules/eslint-plugin-eslint-comments/node_modules/ignore": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+			"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 4"
+			}
+		},
+		"node_modules/eslint-plugin-import": {
+			"version": "2.27.5",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz",
+			"integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"array-includes": "^3.1.6",
+				"array.prototype.flat": "^1.3.1",
+				"array.prototype.flatmap": "^1.3.1",
+				"debug": "^3.2.7",
+				"doctrine": "^2.1.0",
+				"eslint-import-resolver-node": "^0.3.7",
+				"eslint-module-utils": "^2.7.4",
+				"has": "^1.0.3",
+				"is-core-module": "^2.11.0",
+				"is-glob": "^4.0.3",
+				"minimatch": "^3.1.2",
+				"object.values": "^1.1.6",
+				"resolve": "^1.22.1",
+				"semver": "^6.3.0",
+				"tsconfig-paths": "^3.14.1"
+			},
+			"engines": {
+				"node": ">=4"
+			},
+			"peerDependencies": {
+				"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
+			}
+		},
+		"node_modules/eslint-plugin-import/node_modules/debug": {
+			"version": "3.2.7",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+			"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ms": "^2.1.1"
+			}
+		},
+		"node_modules/eslint-plugin-import/node_modules/doctrine": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+			"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"dependencies": {
+				"esutils": "^2.0.2"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/eslint-plugin-import/node_modules/resolve": {
+			"version": "1.22.10",
+			"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+			"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-core-module": "^2.16.0",
+				"path-parse": "^1.0.7",
+				"supports-preserve-symlinks-flag": "^1.0.0"
+			},
+			"bin": {
+				"resolve": "bin/resolve"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/eslint-plugin-import/node_modules/semver": {
+			"version": "6.3.1",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+			"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+			"dev": true,
+			"license": "ISC",
+			"bin": {
+				"semver": "bin/semver.js"
+			}
+		},
+		"node_modules/eslint-plugin-n": {
+			"version": "16.6.2",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz",
+			"integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@eslint-community/eslint-utils": "^4.4.0",
+				"builtins": "^5.0.1",
+				"eslint-plugin-es-x": "^7.5.0",
+				"get-tsconfig": "^4.7.0",
+				"globals": "^13.24.0",
+				"ignore": "^5.2.4",
+				"is-builtin-module": "^3.2.1",
+				"is-core-module": "^2.12.1",
+				"minimatch": "^3.1.2",
+				"resolve": "^1.22.2",
+				"semver": "^7.5.3"
+			},
+			"engines": {
+				"node": ">=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/mysticatea"
+			},
+			"peerDependencies": {
+				"eslint": ">=7.0.0"
+			}
+		},
+		"node_modules/eslint-plugin-n/node_modules/ignore": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+			"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 4"
+			}
+		},
+		"node_modules/eslint-plugin-n/node_modules/resolve": {
+			"version": "1.22.10",
+			"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+			"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-core-module": "^2.16.0",
+				"path-parse": "^1.0.7",
+				"supports-preserve-symlinks-flag": "^1.0.0"
+			},
+			"bin": {
+				"resolve": "bin/resolve"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/eslint-plugin-no-use-extend-native": {
+			"version": "0.5.0",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-no-use-extend-native/-/eslint-plugin-no-use-extend-native-0.5.0.tgz",
+			"integrity": "sha512-dBNjs8hor8rJgeXLH4HTut5eD3RGWf9JUsadIfuL7UosVQ/dnvOKwxEcRrXrFxrMZ8llUVWT+hOimxJABsAUzQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-get-set-prop": "^1.0.0",
+				"is-js-type": "^2.0.0",
+				"is-obj-prop": "^1.0.0",
+				"is-proto-prop": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=6.0.0"
+			}
+		},
+		"node_modules/eslint-plugin-prettier": {
+			"version": "5.2.3",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz",
+			"integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"prettier-linter-helpers": "^1.0.0",
+				"synckit": "^0.9.1"
+			},
+			"engines": {
+				"node": "^14.18.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint-plugin-prettier"
+			},
+			"peerDependencies": {
+				"@types/eslint": ">=8.0.0",
+				"eslint": ">=8.0.0",
+				"eslint-config-prettier": "*",
+				"prettier": ">=3.0.0"
+			},
+			"peerDependenciesMeta": {
+				"@types/eslint": {
+					"optional": true
+				},
+				"eslint-config-prettier": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/eslint-plugin-unicorn": {
+			"version": "48.0.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-48.0.1.tgz",
+			"integrity": "sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@babel/helper-validator-identifier": "^7.22.5",
+				"@eslint-community/eslint-utils": "^4.4.0",
+				"ci-info": "^3.8.0",
+				"clean-regexp": "^1.0.0",
+				"esquery": "^1.5.0",
+				"indent-string": "^4.0.0",
+				"is-builtin-module": "^3.2.1",
+				"jsesc": "^3.0.2",
+				"lodash": "^4.17.21",
+				"pluralize": "^8.0.0",
+				"read-pkg-up": "^7.0.1",
+				"regexp-tree": "^0.1.27",
+				"regjsparser": "^0.10.0",
+				"semver": "^7.5.4",
+				"strip-indent": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=16"
+			},
+			"funding": {
+				"url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1"
+			},
+			"peerDependencies": {
+				"eslint": ">=8.44.0"
+			}
+		},
+		"node_modules/eslint-plugin-unicorn/node_modules/ci-info": {
+			"version": "3.9.0",
+			"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
+			"integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/sibiraj-s"
+				}
+			],
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/eslint-plugin-unicorn/node_modules/indent-string": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+			"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/eslint-rule-docs": {
+			"version": "1.1.235",
+			"resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.235.tgz",
+			"integrity": "sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/eslint-scope": {
+			"version": "7.2.2",
+			"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+			"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"dependencies": {
+				"esrecurse": "^4.3.0",
+				"estraverse": "^5.2.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			}
+		},
+		"node_modules/eslint-utils": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+			"integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"eslint-visitor-keys": "^2.0.0"
+			},
+			"engines": {
+				"node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/mysticatea"
+			},
+			"peerDependencies": {
+				"eslint": ">=5"
+			}
+		},
+		"node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+			"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/eslint-visitor-keys": {
+			"version": "3.4.3",
+			"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+			"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			}
+		},
+		"node_modules/eslint/node_modules/ansi-regex": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/eslint/node_modules/ansi-styles": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+			"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-convert": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
+			}
+		},
+		"node_modules/eslint/node_modules/argparse": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+			"dev": true,
+			"license": "Python-2.0"
+		},
+		"node_modules/eslint/node_modules/chalk": {
+			"version": "4.1.2",
+			"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+			"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-styles": "^4.1.0",
+				"supports-color": "^7.1.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/chalk?sponsor=1"
+			}
+		},
+		"node_modules/eslint/node_modules/color-convert": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+			"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-name": "~1.1.4"
+			},
+			"engines": {
+				"node": ">=7.0.0"
+			}
+		},
+		"node_modules/eslint/node_modules/escape-string-regexp": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+			"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint/node_modules/find-up": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+			"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"locate-path": "^6.0.0",
+				"path-exists": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint/node_modules/glob-parent": {
+			"version": "6.0.2",
+			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+			"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"is-glob": "^4.0.3"
+			},
+			"engines": {
+				"node": ">=10.13.0"
+			}
+		},
+		"node_modules/eslint/node_modules/ignore": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+			"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 4"
+			}
+		},
+		"node_modules/eslint/node_modules/js-yaml": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"argparse": "^2.0.1"
+			},
+			"bin": {
+				"js-yaml": "bin/js-yaml.js"
+			}
+		},
+		"node_modules/eslint/node_modules/locate-path": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+			"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"p-locate": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint/node_modules/p-limit": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+			"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"yocto-queue": "^0.1.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint/node_modules/p-locate": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+			"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"p-limit": "^3.0.2"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/eslint/node_modules/strip-ansi": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-regex": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/eslint/node_modules/yocto-queue": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+			"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/esm-utils": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/esm-utils/-/esm-utils-4.3.0.tgz",
+			"integrity": "sha512-KupZztbWAnuksy1TYPjTkePxVlMWzmXdmB72z1WvUadtUiFv6x+0PKjYfyy1io9gdvU1A6QIcu055NRrJu1TEA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"import-meta-resolve": "^4.1.0",
+				"url-or-path": "^2.3.0"
+			},
+			"funding": {
+				"url": "https://github.com/fisker/esm-utils?sponsor=1"
+			}
+		},
+		"node_modules/espree": {
+			"version": "9.6.1",
+			"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+			"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"dependencies": {
+				"acorn": "^8.9.0",
+				"acorn-jsx": "^5.3.2",
+				"eslint-visitor-keys": "^3.4.1"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			}
+		},
+		"node_modules/esprima": {
+			"version": "4.0.1",
+			"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+			"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"bin": {
+				"esparse": "bin/esparse.js",
+				"esvalidate": "bin/esvalidate.js"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/espurify": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/espurify/-/espurify-2.1.1.tgz",
+			"integrity": "sha512-zttWvnkhcDyGOhSH4vO2qCBILpdCMv/MX8lp4cqgRkQoDRGK2oZxi2GfWhlP2dIXmk7BaKeOTuzbHhyC68o8XQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/esquery": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+			"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+			"dev": true,
+			"license": "BSD-3-Clause",
+			"dependencies": {
+				"estraverse": "^5.1.0"
+			},
+			"engines": {
+				"node": ">=0.10"
+			}
+		},
+		"node_modules/esrecurse": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+			"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"dependencies": {
+				"estraverse": "^5.2.0"
+			},
+			"engines": {
+				"node": ">=4.0"
+			}
+		},
+		"node_modules/estraverse": {
+			"version": "5.3.0",
+			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+			"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"engines": {
+				"node": ">=4.0"
+			}
+		},
+		"node_modules/estree-walker": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+			"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/esutils": {
+			"version": "2.0.3",
+			"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+			"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/events": {
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+			"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"engines": {
+				"node": ">=0.8.x"
+			}
+		},
+		"node_modules/execa": {
+			"version": "8.0.1",
+			"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
+			"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
+			"license": "MIT",
+			"dependencies": {
+				"cross-spawn": "^7.0.3",
+				"get-stream": "^8.0.1",
+				"human-signals": "^5.0.0",
+				"is-stream": "^3.0.0",
+				"merge-stream": "^2.0.0",
+				"npm-run-path": "^5.1.0",
+				"onetime": "^6.0.0",
+				"signal-exit": "^4.1.0",
+				"strip-final-newline": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=16.17"
+			},
+			"funding": {
+				"url": "https://github.com/sindresorhus/execa?sponsor=1"
+			}
+		},
+		"node_modules/fast-deep-equal": {
+			"version": "3.1.3",
+			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+			"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/fast-diff": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
+			"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
+			"dev": true,
+			"license": "Apache-2.0"
+		},
+		"node_modules/fast-glob": {
+			"version": "3.3.3",
+			"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+			"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@nodelib/fs.stat": "^2.0.2",
+				"@nodelib/fs.walk": "^1.2.3",
+				"glob-parent": "^5.1.2",
+				"merge2": "^1.3.0",
+				"micromatch": "^4.0.8"
+			},
+			"engines": {
+				"node": ">=8.6.0"
+			}
+		},
+		"node_modules/fast-json-stable-stringify": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+			"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/fast-levenshtein": {
+			"version": "2.0.6",
+			"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+			"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/fast-uri": {
+			"version": "3.0.6",
+			"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
+			"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/fastify"
+				},
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/fastify"
+				}
+			],
+			"license": "BSD-3-Clause",
+			"peer": true
+		},
+		"node_modules/fastq": {
+			"version": "1.19.0",
+			"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
+			"integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"reusify": "^1.0.4"
+			}
+		},
+		"node_modules/figures": {
+			"version": "6.1.0",
+			"resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
+			"integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-unicode-supported": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/file-entry-cache": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+			"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"flat-cache": "^3.0.4"
+			},
+			"engines": {
+				"node": "^10.12.0 || >=12.0.0"
+			}
+		},
+		"node_modules/file-uri-to-path": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+			"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/fill-range": {
+			"version": "7.1.1",
+			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+			"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"to-regex-range": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/find-cache-dir": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz",
+			"integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"common-path-prefix": "^3.0.0",
+				"pkg-dir": "^7.0.0"
+			},
+			"engines": {
+				"node": ">=14.16"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/find-cache-dir/node_modules/pkg-dir": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz",
+			"integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"find-up": "^6.3.0"
+			},
+			"engines": {
+				"node": ">=14.16"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/find-root": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+			"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/find-up": {
+			"version": "6.3.0",
+			"resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
+			"integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"locate-path": "^7.1.0",
+				"path-exists": "^5.0.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/find-up-simple": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz",
+			"integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/find-up/node_modules/path-exists": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
+			"integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			}
+		},
+		"node_modules/flat-cache": {
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+			"integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"flatted": "^3.2.9",
+				"keyv": "^4.5.3",
+				"rimraf": "^3.0.2"
+			},
+			"engines": {
+				"node": "^10.12.0 || >=12.0.0"
+			}
+		},
+		"node_modules/flat-cache/node_modules/rimraf": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+			"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+			"deprecated": "Rimraf versions prior to v4 are no longer supported",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"glob": "^7.1.3"
+			},
+			"bin": {
+				"rimraf": "bin.js"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/flatted": {
+			"version": "3.3.2",
+			"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
+			"integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/fmix": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/fmix/-/fmix-0.1.0.tgz",
+			"integrity": "sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==",
+			"license": "MIT",
+			"dependencies": {
+				"imul": "^1.0.0"
+			}
+		},
+		"node_modules/for-each": {
+			"version": "0.3.4",
+			"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz",
+			"integrity": "sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-callable": "^1.2.7"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/foreground-child": {
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
+			"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"cross-spawn": "^7.0.0",
+				"signal-exit": "^4.0.1"
+			},
+			"engines": {
+				"node": ">=14"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/fs-temp": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/fs-temp/-/fs-temp-1.2.1.tgz",
+			"integrity": "sha512-okTwLB7/Qsq82G6iN5zZJFsOfZtx2/pqrA7Hk/9fvy+c+eJS9CvgGXT2uNxwnI14BDY9L/jQPkaBgSvlKfSW9w==",
+			"license": "MIT",
+			"dependencies": {
+				"random-path": "^0.1.0"
+			}
+		},
+		"node_modules/fs-xattr": {
+			"version": "0.3.1",
+			"resolved": "https://registry.npmjs.org/fs-xattr/-/fs-xattr-0.3.1.tgz",
+			"integrity": "sha512-UVqkrEW0GfDabw4C3HOrFlxKfx0eeigfRne69FxSBdHIP8Qt5Sq6Pu3RM9KmMlkygtC4pPKkj5CiPO5USnj2GA==",
+			"hasInstallScript": true,
+			"license": "MIT",
+			"os": [
+				"!win32"
+			],
+			"engines": {
+				"node": ">=8.6.0"
+			}
+		},
+		"node_modules/fs.realpath": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+			"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/function-bind": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+			"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+			"dev": true,
+			"license": "MIT",
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/function.prototype.name": {
+			"version": "1.1.8",
+			"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
+			"integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"call-bound": "^1.0.3",
+				"define-properties": "^1.2.1",
+				"functions-have-names": "^1.2.3",
+				"hasown": "^2.0.2",
+				"is-callable": "^1.2.7"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/functions-have-names": {
+			"version": "1.2.3",
+			"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+			"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+			"dev": true,
+			"license": "MIT",
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/generate-function": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
+			"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
+			"license": "MIT",
+			"dependencies": {
+				"is-property": "^1.0.2"
+			}
+		},
+		"node_modules/generate-object-property": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+			"integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==",
+			"license": "MIT",
+			"dependencies": {
+				"is-property": "^1.0.0"
+			}
+		},
+		"node_modules/get-caller-file": {
+			"version": "2.0.5",
+			"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+			"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+			"dev": true,
+			"license": "ISC",
+			"engines": {
+				"node": "6.* || 8.* || >= 10.*"
+			}
+		},
+		"node_modules/get-east-asian-width": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
+			"integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/get-intrinsic": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
+			"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind-apply-helpers": "^1.0.1",
+				"es-define-property": "^1.0.1",
+				"es-errors": "^1.3.0",
+				"es-object-atoms": "^1.0.0",
+				"function-bind": "^1.1.2",
+				"get-proto": "^1.0.0",
+				"gopd": "^1.2.0",
+				"has-symbols": "^1.1.0",
+				"hasown": "^2.0.2",
+				"math-intrinsics": "^1.1.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/get-proto": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+			"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"dunder-proto": "^1.0.1",
+				"es-object-atoms": "^1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/get-set-props": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/get-set-props/-/get-set-props-0.1.0.tgz",
+			"integrity": "sha512-7oKuKzAGKj0ag+eWZwcGw2fjiZ78tXnXQoBgY0aU7ZOxTu4bB7hSuQSDgtKy978EDH062P5FmD2EWiDpQS9K9Q==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/get-stdin": {
+			"version": "9.0.0",
+			"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz",
+			"integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/get-stream": {
+			"version": "8.0.1",
+			"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
+			"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=16"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/get-symbol-description": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+			"integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"es-errors": "^1.3.0",
+				"get-intrinsic": "^1.2.6"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/get-tsconfig": {
+			"version": "4.10.0",
+			"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz",
+			"integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"resolve-pkg-maps": "^1.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+			}
+		},
+		"node_modules/glob": {
+			"version": "7.2.3",
+			"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+			"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+			"deprecated": "Glob versions prior to v9 are no longer supported",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"fs.realpath": "^1.0.0",
+				"inflight": "^1.0.4",
+				"inherits": "2",
+				"minimatch": "^3.1.1",
+				"once": "^1.3.0",
+				"path-is-absolute": "^1.0.0"
+			},
+			"engines": {
+				"node": "*"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/glob-parent": {
+			"version": "5.1.2",
+			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+			"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"is-glob": "^4.0.1"
+			},
+			"engines": {
+				"node": ">= 6"
+			}
+		},
+		"node_modules/glob-to-regexp": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+			"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"peer": true
+		},
+		"node_modules/globals": {
+			"version": "13.24.0",
+			"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+			"integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"type-fest": "^0.20.2"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/globals/node_modules/type-fest": {
+			"version": "0.20.2",
+			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+			"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+			"dev": true,
+			"license": "(MIT OR CC0-1.0)",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/globalthis": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+			"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"define-properties": "^1.2.1",
+				"gopd": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/globby": {
+			"version": "14.1.0",
+			"resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz",
+			"integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@sindresorhus/merge-streams": "^2.1.0",
+				"fast-glob": "^3.3.3",
+				"ignore": "^7.0.3",
+				"path-type": "^6.0.0",
+				"slash": "^5.1.0",
+				"unicorn-magic": "^0.3.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/gm": {
+			"version": "1.25.0",
+			"resolved": "https://registry.npmjs.org/gm/-/gm-1.25.0.tgz",
+			"integrity": "sha512-4kKdWXTtgQ4biIo7hZA396HT062nDVVHPjQcurNZ3o/voYN+o5FUC5kOwuORbpExp3XbTJ3SU7iRipiIhQtovw==",
+			"license": "MIT",
+			"dependencies": {
+				"array-parallel": "~0.1.3",
+				"array-series": "~0.1.5",
+				"cross-spawn": "^4.0.0",
+				"debug": "^3.1.0"
+			},
+			"engines": {
+				"node": ">=14"
+			}
+		},
+		"node_modules/gm/node_modules/cross-spawn": {
+			"version": "4.0.2",
+			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
+			"integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==",
+			"license": "MIT",
+			"dependencies": {
+				"lru-cache": "^4.0.1",
+				"which": "^1.2.9"
+			}
+		},
+		"node_modules/gm/node_modules/debug": {
+			"version": "3.2.7",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+			"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+			"license": "MIT",
+			"dependencies": {
+				"ms": "^2.1.1"
+			}
+		},
+		"node_modules/gm/node_modules/which": {
+			"version": "1.3.1",
+			"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+			"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+			"license": "ISC",
+			"dependencies": {
+				"isexe": "^2.0.0"
+			},
+			"bin": {
+				"which": "bin/which"
+			}
+		},
+		"node_modules/gopd": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+			"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/graceful-fs": {
+			"version": "4.2.11",
+			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+			"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/graphemer": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+			"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/has": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
+			"integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4.0"
+			}
+		},
+		"node_modules/has-bigints": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
+			"integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/has-flag": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+			"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/has-property-descriptors": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+			"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"es-define-property": "^1.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/has-proto": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
+			"integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"dunder-proto": "^1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/has-symbols": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+			"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/has-tostringtag": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+			"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"has-symbols": "^1.0.3"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/hasown": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+			"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"function-bind": "^1.1.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/hosted-git-info": {
+			"version": "2.8.9",
+			"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+			"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/https-proxy-agent": {
+			"version": "7.0.6",
+			"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+			"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"agent-base": "^7.1.2",
+				"debug": "4"
+			},
+			"engines": {
+				"node": ">= 14"
+			}
+		},
+		"node_modules/human-signals": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
+			"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
+			"license": "Apache-2.0",
+			"engines": {
+				"node": ">=16.17.0"
+			}
+		},
+		"node_modules/icns-lib": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/icns-lib/-/icns-lib-1.0.1.tgz",
+			"integrity": "sha512-J7+RDRQApG/vChY5TP043NitBcNC7QMn1kOgGvlAkyrK65hozAaSwTNsTZ2HJh+br9e1NlzpBreAOpk4YuhOJA==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/ignore": {
+			"version": "7.0.3",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz",
+			"integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 4"
+			}
+		},
+		"node_modules/ignore-by-default": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.1.0.tgz",
+			"integrity": "sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==",
+			"dev": true,
+			"license": "ISC",
+			"engines": {
+				"node": ">=10 <11 || >=12 <13 || >=14"
+			}
+		},
+		"node_modules/image-size": {
+			"version": "0.7.5",
+			"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz",
+			"integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==",
+			"license": "MIT",
+			"bin": {
+				"image-size": "bin/image-size.js"
+			},
+			"engines": {
+				"node": ">=6.9.0"
+			}
+		},
+		"node_modules/import-fresh": {
+			"version": "3.3.1",
+			"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+			"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"parent-module": "^1.0.0",
+				"resolve-from": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/import-fresh/node_modules/resolve-from": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+			"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/import-meta-resolve": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
+			"integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==",
+			"dev": true,
+			"license": "MIT",
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/wooorm"
+			}
+		},
+		"node_modules/import-modules": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/import-modules/-/import-modules-2.1.0.tgz",
+			"integrity": "sha512-8HEWcnkbGpovH9yInoisxaSoIg9Brbul+Ju3Kqe2UsYDUBJD/iQjSgEj0zPcTDPKfPp2fs5xlv1i+JSye/m1/A==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/imul": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/imul/-/imul-1.0.1.tgz",
+			"integrity": "sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/imurmurhash": {
+			"version": "0.1.4",
+			"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+			"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.8.19"
+			}
+		},
+		"node_modules/indent-string": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz",
+			"integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/inflight": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+			"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+			"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"once": "^1.3.0",
+				"wrappy": "1"
+			}
+		},
+		"node_modules/inherits": {
+			"version": "2.0.4",
+			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/internal-slot": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
+			"integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"es-errors": "^1.3.0",
+				"hasown": "^2.0.2",
+				"side-channel": "^1.1.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/interpret": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+			"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.10"
+			}
+		},
+		"node_modules/irregular-plurals": {
+			"version": "3.5.0",
+			"resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz",
+			"integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/is-absolute": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+			"integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-relative": "^1.0.0",
+				"is-windows": "^1.0.1"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/is-array-buffer": {
+			"version": "3.0.5",
+			"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+			"integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"call-bound": "^1.0.3",
+				"get-intrinsic": "^1.2.6"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-arrayish": {
+			"version": "0.2.1",
+			"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+			"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/is-async-function": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
+			"integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"async-function": "^1.0.0",
+				"call-bound": "^1.0.3",
+				"get-proto": "^1.0.1",
+				"has-tostringtag": "^1.0.2",
+				"safe-regex-test": "^1.1.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-bigint": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
+			"integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"has-bigints": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-boolean-object": {
+			"version": "1.2.2",
+			"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
+			"integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"has-tostringtag": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-builtin-module": {
+			"version": "3.2.1",
+			"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+			"integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"builtin-modules": "^3.3.0"
+			},
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/is-callable": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+			"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-core-module": {
+			"version": "2.16.1",
+			"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+			"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"hasown": "^2.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-data-view": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
+			"integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.2",
+				"get-intrinsic": "^1.2.6",
+				"is-typed-array": "^1.1.13"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-date-object": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
+			"integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.2",
+				"has-tostringtag": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-docker": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+			"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"is-docker": "cli.js"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/is-extglob": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+			"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/is-finalizationregistry": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+			"integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-fullwidth-code-point": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
+			"integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/is-generator-function": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz",
+			"integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"get-proto": "^1.0.0",
+				"has-tostringtag": "^1.0.2",
+				"safe-regex-test": "^1.1.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-get-set-prop": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-get-set-prop/-/is-get-set-prop-1.0.0.tgz",
+			"integrity": "sha512-DvAYZ1ZgGUz4lzxKMPYlt08qAUqyG9ckSg2pIjfvcQ7+pkVNUHk8yVLXOnCLe5WKXhLop8oorWFBJHpwWQpszQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"get-set-props": "^0.1.0",
+				"lowercase-keys": "^1.0.0"
+			}
+		},
+		"node_modules/is-glob": {
+			"version": "4.0.3",
+			"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+			"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-extglob": "^2.1.1"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/is-interactive": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
+			"integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/is-js-type": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/is-js-type/-/is-js-type-2.0.0.tgz",
+			"integrity": "sha512-Aj13l47+uyTjlQNHtXBV8Cji3jb037vxwMWCgopRR8h6xocgBGW3qG8qGlIOEmbXQtkKShKuBM9e8AA1OeQ+xw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"js-types": "^1.0.0"
+			}
+		},
+		"node_modules/is-map": {
+			"version": "2.0.3",
+			"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+			"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-my-ip-valid": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz",
+			"integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==",
+			"license": "MIT"
+		},
+		"node_modules/is-my-json-valid": {
+			"version": "2.20.6",
+			"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz",
+			"integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==",
+			"license": "MIT",
+			"dependencies": {
+				"generate-function": "^2.0.0",
+				"generate-object-property": "^1.1.0",
+				"is-my-ip-valid": "^1.0.0",
+				"jsonpointer": "^5.0.0",
+				"xtend": "^4.0.0"
+			}
+		},
+		"node_modules/is-negated-glob": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
+			"integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/is-number": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+			"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.12.0"
+			}
+		},
+		"node_modules/is-number-object": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
+			"integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"has-tostringtag": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-obj-prop": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-obj-prop/-/is-obj-prop-1.0.0.tgz",
+			"integrity": "sha512-5Idb61slRlJlsAzi0Wsfwbp+zZY+9LXKUAZpvT/1ySw+NxKLRWfa0Bzj+wXI3fX5O9hiddm5c3DAaRSNP/yl2w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"lowercase-keys": "^1.0.0",
+				"obj-props": "^1.0.0"
+			}
+		},
+		"node_modules/is-path-inside": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+			"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/is-plain-object": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+			"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/is-promise": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+			"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/is-property": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+			"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
+			"license": "MIT"
+		},
+		"node_modules/is-proto-prop": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/is-proto-prop/-/is-proto-prop-2.0.0.tgz",
+			"integrity": "sha512-jl3NbQ/fGLv5Jhan4uX+Ge9ohnemqyblWVVCpAvtTQzNFvV2xhJq+esnkIbYQ9F1nITXoLfDDQLp7LBw/zzncg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"lowercase-keys": "^1.0.0",
+				"proto-props": "^2.0.0"
+			}
+		},
+		"node_modules/is-regex": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+			"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.2",
+				"gopd": "^1.2.0",
+				"has-tostringtag": "^1.0.2",
+				"hasown": "^2.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-relative": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+			"integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-unc-path": "^1.0.0"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/is-set": {
+			"version": "2.0.3",
+			"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+			"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-shared-array-buffer": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+			"integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"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==",
+			"license": "MIT",
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/is-string": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+			"integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"has-tostringtag": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-symbol": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
+			"integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.2",
+				"has-symbols": "^1.1.0",
+				"safe-regex-test": "^1.1.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-typed-array": {
+			"version": "1.1.15",
+			"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+			"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"which-typed-array": "^1.1.16"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-unc-path": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+			"integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"unc-path-regex": "^0.1.2"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/is-unicode-supported": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+			"integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/is-weakmap": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+			"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-weakref": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
+			"integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-weakset": {
+			"version": "2.0.4",
+			"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
+			"integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"get-intrinsic": "^1.2.6"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/is-windows": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+			"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/is-wsl": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+			"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-docker": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/isarray": {
+			"version": "2.0.5",
+			"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+			"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/isexe": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+			"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+			"license": "ISC"
+		},
+		"node_modules/jackspeak": {
+			"version": "3.4.3",
+			"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+			"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+			"dev": true,
+			"license": "BlueOak-1.0.0",
+			"dependencies": {
+				"@isaacs/cliui": "^8.0.2"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			},
+			"optionalDependencies": {
+				"@pkgjs/parseargs": "^0.11.0"
+			}
+		},
+		"node_modules/jest-worker": {
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+			"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@types/node": "*",
+				"merge-stream": "^2.0.0",
+				"supports-color": "^8.0.0"
+			},
+			"engines": {
+				"node": ">= 10.13.0"
+			}
+		},
+		"node_modules/jest-worker/node_modules/supports-color": {
+			"version": "8.1.1",
+			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+			"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"has-flag": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/supports-color?sponsor=1"
+			}
+		},
+		"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==",
+			"dev": true,
+			"license": "MIT",
+			"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",
+			"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/js-types": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/js-types/-/js-types-1.0.0.tgz",
+			"integrity": "sha512-bfwqBW9cC/Lp7xcRpug7YrXm0IVw+T9e3g4mCYnv0Pjr3zIzU9PCQElYU9oSGAWzXlbdl9X5SAMPejO9sxkeUw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/js-yaml": {
+			"version": "3.14.1",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+			"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"argparse": "^1.0.7",
+				"esprima": "^4.0.0"
+			},
+			"bin": {
+				"js-yaml": "bin/js-yaml.js"
+			}
+		},
+		"node_modules/jsesc": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+			"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"jsesc": "bin/jsesc"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/json-buffer": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+			"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/json-parse-even-better-errors": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+			"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/json-schema-traverse": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+			"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/json-stable-stringify-without-jsonify": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+			"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/json5": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+			"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"minimist": "^1.2.0"
+			},
+			"bin": {
+				"json5": "lib/cli.js"
+			}
+		},
+		"node_modules/jsonpointer": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
+			"integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/keyv": {
+			"version": "4.5.4",
+			"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+			"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"json-buffer": "3.0.1"
+			}
+		},
+		"node_modules/levn": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+			"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"prelude-ls": "^1.2.1",
+				"type-check": "~0.4.0"
+			},
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
+		"node_modules/line-column-path": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/line-column-path/-/line-column-path-3.0.0.tgz",
+			"integrity": "sha512-Atocnm7Wr9nuvAn97yEPQa3pcQI5eLQGBz+m6iTb+CVw+IOzYB9MrYK7jI7BfC9ISnT4Fu0eiwhAScV//rp4Hw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"type-fest": "^2.0.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/line-column-path/node_modules/type-fest": {
+			"version": "2.19.0",
+			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+			"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+			"dev": true,
+			"license": "(MIT OR CC0-1.0)",
+			"engines": {
+				"node": ">=12.20"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/lines-and-columns": {
+			"version": "1.2.4",
+			"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+			"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/load-json-file": {
+			"version": "7.0.1",
+			"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz",
+			"integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/loader-runner": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
+			"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"engines": {
+				"node": ">=6.11.5"
+			}
+		},
+		"node_modules/locate-path": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
+			"integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"p-locate": "^6.0.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/lodash": {
+			"version": "4.17.21",
+			"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+			"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/lodash-es": {
+			"version": "4.17.21",
+			"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+			"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/lodash.merge": {
+			"version": "4.6.2",
+			"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+			"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/log-symbols": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
+			"integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
+			"license": "MIT",
+			"dependencies": {
+				"chalk": "^5.3.0",
+				"is-unicode-supported": "^1.3.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/log-symbols/node_modules/is-unicode-supported": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+			"integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/lowercase-keys": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+			"integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/lru-cache": {
+			"version": "4.1.5",
+			"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+			"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+			"license": "ISC",
+			"dependencies": {
+				"pseudomap": "^1.0.2",
+				"yallist": "^2.1.2"
+			}
+		},
+		"node_modules/lru-cache/node_modules/yallist": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+			"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
+			"license": "ISC"
+		},
+		"node_modules/macos-alias": {
+			"version": "0.2.12",
+			"resolved": "https://registry.npmjs.org/macos-alias/-/macos-alias-0.2.12.tgz",
+			"integrity": "sha512-yiLHa7cfJcGRFq4FrR4tMlpNHb4Vy4mWnpajlSSIFM5k4Lv8/7BbbDLzCAVogWNl0LlLhizRp1drXv0hK9h0Yw==",
+			"hasInstallScript": true,
+			"license": "MIT",
+			"os": [
+				"darwin"
+			],
+			"dependencies": {
+				"nan": "^2.4.0"
+			}
+		},
+		"node_modules/matcher": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/matcher/-/matcher-5.0.0.tgz",
+			"integrity": "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"escape-string-regexp": "^5.0.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/math-intrinsics": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+			"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 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==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"blueimp-md5": "^2.10.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/memoize": {
+			"version": "10.0.0",
+			"resolved": "https://registry.npmjs.org/memoize/-/memoize-10.0.0.tgz",
+			"integrity": "sha512-H6cBLgsi6vMWOcCpvVCdFFnl3kerEXbrYh9q+lY6VXvQSmM6CkmV08VOwT+WE2tzIEqRPFfAq3fm4v/UIW6mSA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"mimic-function": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sindresorhus/memoize?sponsor=1"
+			}
+		},
+		"node_modules/memory-fs": {
+			"version": "0.2.0",
+			"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz",
+			"integrity": "sha512-+y4mDxU4rvXXu5UDSGCGNiesFmwCHuefGMoPCO1WYucNYj7DsLqrFaa2fXVI0H+NNiPTwwzKwspn9yTZqUGqng==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/meow": {
+			"version": "13.2.0",
+			"resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
+			"integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"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==",
+			"license": "MIT"
+		},
+		"node_modules/merge2": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+			"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 8"
+			}
+		},
+		"node_modules/micro-spelling-correcter": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/micro-spelling-correcter/-/micro-spelling-correcter-1.1.1.tgz",
+			"integrity": "sha512-lkJ3Rj/mtjlRcHk6YyCbvZhyWTOzdBvTHsxMmZSk5jxN1YyVSQ+JETAom55mdzfcyDrY/49Z7UCW760BK30crg==",
+			"dev": true,
+			"license": "CC0-1.0"
+		},
+		"node_modules/micromatch": {
+			"version": "4.0.8",
+			"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+			"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"braces": "^3.0.3",
+				"picomatch": "^2.3.1"
+			},
+			"engines": {
+				"node": ">=8.6"
+			}
+		},
+		"node_modules/micromatch/node_modules/picomatch": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+			"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8.6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/jonschlinkert"
+			}
+		},
+		"node_modules/mime-db": {
+			"version": "1.52.0",
+			"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+			"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"engines": {
+				"node": ">= 0.6"
+			}
+		},
+		"node_modules/mime-types": {
+			"version": "2.1.35",
+			"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+			"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"mime-db": "1.52.0"
+			},
+			"engines": {
+				"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==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/mimic-function": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+			"integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/min-indent": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+			"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/minimatch": {
+			"version": "3.1.2",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+			"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"brace-expansion": "^1.1.7"
+			},
+			"engines": {
+				"node": "*"
+			}
+		},
+		"node_modules/minimist": {
+			"version": "1.2.8",
+			"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+			"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+			"license": "MIT",
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/minipass": {
+			"version": "7.1.2",
+			"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+			"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+			"dev": true,
+			"license": "ISC",
+			"engines": {
+				"node": ">=16 || 14 >=14.17"
+			}
+		},
+		"node_modules/minizlib": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz",
+			"integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"minipass": "^7.0.4",
+				"rimraf": "^5.0.5"
+			},
+			"engines": {
+				"node": ">= 18"
+			}
+		},
+		"node_modules/mkdirp": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+			"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"mkdirp": "dist/cjs/src/bin.js"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/ms": {
+			"version": "2.1.3",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+			"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+			"license": "MIT"
+		},
+		"node_modules/murmur-32": {
+			"version": "0.2.0",
+			"resolved": "https://registry.npmjs.org/murmur-32/-/murmur-32-0.2.0.tgz",
+			"integrity": "sha512-ZkcWZudylwF+ir3Ld1n7gL6bI2mQAzXvSobPwVtu8aYi2sbXeipeSkdcanRLzIofLcM5F53lGaKm2dk7orBi7Q==",
+			"license": "MIT",
+			"dependencies": {
+				"encode-utf8": "^1.0.3",
+				"fmix": "^0.1.0",
+				"imul": "^1.0.0"
+			}
+		},
+		"node_modules/nan": {
+			"version": "2.22.0",
+			"resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz",
+			"integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==",
+			"license": "MIT"
+		},
+		"node_modules/natural-compare": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+			"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/neo-async": {
+			"version": "2.6.2",
+			"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+			"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/nice-try": {
+			"version": "1.0.5",
+			"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+			"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+			"license": "MIT"
+		},
+		"node_modules/node-fetch": {
+			"version": "2.7.0",
+			"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+			"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"whatwg-url": "^5.0.0"
+			},
+			"engines": {
+				"node": "4.x || >=6.0.0"
+			},
+			"peerDependencies": {
+				"encoding": "^0.1.0"
+			},
+			"peerDependenciesMeta": {
+				"encoding": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/node-gyp-build": {
+			"version": "4.8.4",
+			"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
+			"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"node-gyp-build": "bin.js",
+				"node-gyp-build-optional": "optional.js",
+				"node-gyp-build-test": "build-test.js"
+			}
+		},
+		"node_modules/node-releases": {
+			"version": "2.0.19",
+			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+			"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/nofilter": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz",
+			"integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12.19"
+			}
+		},
+		"node_modules/nopt": {
+			"version": "8.1.0",
+			"resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz",
+			"integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"abbrev": "^3.0.0"
+			},
+			"bin": {
+				"nopt": "bin/nopt.js"
+			},
+			"engines": {
+				"node": "^18.17.0 || >=20.5.0"
+			}
+		},
+		"node_modules/normalize-package-data": {
+			"version": "2.5.0",
+			"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+			"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"dependencies": {
+				"hosted-git-info": "^2.1.4",
+				"resolve": "^1.10.0",
+				"semver": "2 || 3 || 4 || 5",
+				"validate-npm-package-license": "^3.0.1"
+			}
+		},
+		"node_modules/normalize-package-data/node_modules/resolve": {
+			"version": "1.22.10",
+			"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+			"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-core-module": "^2.16.0",
+				"path-parse": "^1.0.7",
+				"supports-preserve-symlinks-flag": "^1.0.0"
+			},
+			"bin": {
+				"resolve": "bin/resolve"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/normalize-package-data/node_modules/semver": {
+			"version": "5.7.2",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+			"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+			"dev": true,
+			"license": "ISC",
+			"bin": {
+				"semver": "bin/semver"
+			}
+		},
+		"node_modules/npm-run-path": {
+			"version": "5.3.0",
+			"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
+			"integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
+			"license": "MIT",
+			"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==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/obj-props": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/obj-props/-/obj-props-1.4.0.tgz",
+			"integrity": "sha512-p7p/7ltzPDiBs6DqxOrIbtRdwxxVRBj5ROukeNb9RgA+fawhrz5n2hpNz8DDmYR//tviJSj7nUnlppGmONkjiQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/object-inspect": {
+			"version": "1.13.4",
+			"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+			"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/object-keys": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+			"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/object.assign": {
+			"version": "4.1.7",
+			"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+			"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"call-bound": "^1.0.3",
+				"define-properties": "^1.2.1",
+				"es-object-atoms": "^1.0.0",
+				"has-symbols": "^1.1.0",
+				"object-keys": "^1.1.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/object.values": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
+			"integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"call-bound": "^1.0.3",
+				"define-properties": "^1.2.1",
+				"es-object-atoms": "^1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/once": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+			"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+			"license": "ISC",
+			"dependencies": {
+				"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==",
+			"license": "MIT",
+			"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",
+			"integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"define-lazy-prop": "^2.0.0",
+				"is-docker": "^2.1.1",
+				"is-wsl": "^2.2.0"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/open-editor": {
+			"version": "4.1.1",
+			"resolved": "https://registry.npmjs.org/open-editor/-/open-editor-4.1.1.tgz",
+			"integrity": "sha512-SYtGeZ9Zkzj/naoZaEF9LzwDYEGwuqQ4Fx5E3xdVRN98LFJjvMhG/ElByFEOVOiXepGra/Wi1fA4i/E1fXSBsw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"env-editor": "^1.1.0",
+				"execa": "^5.1.1",
+				"line-column-path": "^3.0.0",
+				"open": "^8.4.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/open-editor/node_modules/execa": {
+			"version": "5.1.1",
+			"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+			"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"cross-spawn": "^7.0.3",
+				"get-stream": "^6.0.0",
+				"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/open-editor/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==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/open-editor/node_modules/human-signals": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+			"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"engines": {
+				"node": ">=10.17.0"
+			}
+		},
+		"node_modules/open-editor/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==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/open-editor/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==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/open-editor/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==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"path-key": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/open-editor/node_modules/onetime": {
+			"version": "5.1.2",
+			"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+			"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"mimic-fn": "^2.1.0"
+			},
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/open-editor/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==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/open-editor/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==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/open/node_modules/define-lazy-prop": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+			"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/optionator": {
+			"version": "0.9.4",
+			"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+			"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"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.5"
+			},
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
+		"node_modules/ora": {
+			"version": "8.2.0",
+			"resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
+			"integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
+			"license": "MIT",
+			"dependencies": {
+				"chalk": "^5.3.0",
+				"cli-cursor": "^5.0.0",
+				"cli-spinners": "^2.9.2",
+				"is-interactive": "^2.0.0",
+				"is-unicode-supported": "^2.0.0",
+				"log-symbols": "^6.0.0",
+				"stdin-discarder": "^0.2.2",
+				"string-width": "^7.2.0",
+				"strip-ansi": "^7.1.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/own-keys": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
+			"integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"get-intrinsic": "^1.2.6",
+				"object-keys": "^1.1.1",
+				"safe-push-apply": "^1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/p-finally": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+			"integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/p-limit": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+			"integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"yocto-queue": "^1.0.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/p-locate": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
+			"integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"p-limit": "^4.0.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/p-map": {
+			"version": "7.0.3",
+			"resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz",
+			"integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/p-try": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+			"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/package-config": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/package-config/-/package-config-5.0.0.tgz",
+			"integrity": "sha512-GYTTew2slBcYdvRHqjhwaaydVMvn/qrGC323+nKclYioNSLTDUM/lGgtGTgyHVtYcozb+XkE8CNhwcraOmZ9Mg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"find-up-simple": "^1.0.0",
+				"load-json-file": "^7.0.1"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/package-json-from-dist": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+			"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+			"dev": true,
+			"license": "BlueOak-1.0.0"
+		},
+		"node_modules/parent-module": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+			"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"callsites": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/parent-module/node_modules/callsites": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+			"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/parse-color": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz",
+			"integrity": "sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==",
+			"license": "MIT",
+			"dependencies": {
+				"color-convert": "~0.5.0"
+			}
+		},
+		"node_modules/parse-json": {
+			"version": "5.2.0",
+			"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+			"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@babel/code-frame": "^7.0.0",
+				"error-ex": "^1.3.1",
+				"json-parse-even-better-errors": "^2.3.0",
+				"lines-and-columns": "^1.1.6"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/parse-ms": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
+			"integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/path-exists": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+			"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/path-is-absolute": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+			"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/path-key": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+			"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/path-parse": {
+			"version": "1.0.7",
+			"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+			"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/path-scurry": {
+			"version": "1.11.1",
+			"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+			"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+			"dev": true,
+			"license": "BlueOak-1.0.0",
+			"dependencies": {
+				"lru-cache": "^10.2.0",
+				"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+			},
+			"engines": {
+				"node": ">=16 || 14 >=14.18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/path-scurry/node_modules/lru-cache": {
+			"version": "10.4.3",
+			"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+			"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/path-type": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz",
+			"integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/picocolors": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+			"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+			"dev": true,
+			"license": "ISC"
+		},
+		"node_modules/picomatch": {
+			"version": "4.0.2",
+			"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+			"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/jonschlinkert"
+			}
+		},
+		"node_modules/pkg-dir": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz",
+			"integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"find-up": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/pkg-dir/node_modules/find-up": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+			"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"locate-path": "^6.0.0",
+				"path-exists": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/pkg-dir/node_modules/locate-path": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+			"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"p-locate": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/pkg-dir/node_modules/p-limit": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+			"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"yocto-queue": "^0.1.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/pkg-dir/node_modules/p-locate": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+			"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"p-limit": "^3.0.2"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/pkg-dir/node_modules/yocto-queue": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+			"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/plist": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
+			"integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==",
+			"license": "MIT",
+			"dependencies": {
+				"@xmldom/xmldom": "^0.8.8",
+				"base64-js": "^1.5.1",
+				"xmlbuilder": "^15.1.1"
+			},
+			"engines": {
+				"node": ">=10.4.0"
+			}
+		},
+		"node_modules/plur": {
+			"version": "5.1.0",
+			"resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz",
+			"integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"irregular-plurals": "^3.3.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/pluralize": {
+			"version": "8.0.0",
+			"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
+			"integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/possible-typed-array-names": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+			"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/prelude-ls": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+			"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
+		"node_modules/prettier": {
+			"version": "3.5.0",
+			"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz",
+			"integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"prettier": "bin/prettier.cjs"
+			},
+			"engines": {
+				"node": ">=14"
+			},
+			"funding": {
+				"url": "https://github.com/prettier/prettier?sponsor=1"
+			}
+		},
+		"node_modules/prettier-linter-helpers": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+			"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"fast-diff": "^1.1.2"
+			},
+			"engines": {
+				"node": ">=6.0.0"
+			}
+		},
+		"node_modules/pretty-ms": {
+			"version": "9.2.0",
+			"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz",
+			"integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"parse-ms": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/proto-props": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/proto-props/-/proto-props-2.0.0.tgz",
+			"integrity": "sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/pseudomap": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+			"integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
+			"license": "ISC"
+		},
+		"node_modules/pump": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
+			"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
+			"license": "MIT",
+			"dependencies": {
+				"end-of-stream": "^1.1.0",
+				"once": "^1.3.1"
+			}
+		},
+		"node_modules/punycode": {
+			"version": "2.3.1",
+			"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+			"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/queue-microtask": {
+			"version": "1.2.3",
+			"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+			"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			],
+			"license": "MIT"
+		},
+		"node_modules/random-path": {
+			"version": "0.1.2",
+			"resolved": "https://registry.npmjs.org/random-path/-/random-path-0.1.2.tgz",
+			"integrity": "sha512-4jY0yoEaQ5v9StCl5kZbNIQlg1QheIDBrdkDn53EynpPb9FgO6//p3X/tgMnrC45XN6QZCzU1Xz/+pSSsJBpRw==",
+			"license": "MIT",
+			"dependencies": {
+				"base32-encode": "^0.1.0 || ^1.0.0",
+				"murmur-32": "^0.1.0 || ^0.2.0"
+			}
+		},
+		"node_modules/randombytes": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+			"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"safe-buffer": "^5.1.0"
+			}
+		},
+		"node_modules/read-pkg": {
+			"version": "5.2.0",
+			"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+			"integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@types/normalize-package-data": "^2.4.0",
+				"normalize-package-data": "^2.5.0",
+				"parse-json": "^5.0.0",
+				"type-fest": "^0.6.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/read-pkg-up": {
+			"version": "7.0.1",
+			"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+			"integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"find-up": "^4.1.0",
+				"read-pkg": "^5.2.0",
+				"type-fest": "^0.8.1"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/read-pkg-up/node_modules/find-up": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+			"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"locate-path": "^5.0.0",
+				"path-exists": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/read-pkg-up/node_modules/locate-path": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+			"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"p-locate": "^4.1.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/read-pkg-up/node_modules/p-limit": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+			"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"p-try": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/read-pkg-up/node_modules/p-locate": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+			"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"p-limit": "^2.2.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/read-pkg-up/node_modules/type-fest": {
+			"version": "0.8.1",
+			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+			"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+			"dev": true,
+			"license": "(MIT OR CC0-1.0)",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/read-pkg/node_modules/type-fest": {
+			"version": "0.6.0",
+			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+			"integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+			"dev": true,
+			"license": "(MIT OR CC0-1.0)",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/reflect.getprototypeof": {
+			"version": "1.0.10",
+			"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
+			"integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"define-properties": "^1.2.1",
+				"es-abstract": "^1.23.9",
+				"es-errors": "^1.3.0",
+				"es-object-atoms": "^1.0.0",
+				"get-intrinsic": "^1.2.7",
+				"get-proto": "^1.0.1",
+				"which-builtin-type": "^1.2.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/regexp-tree": {
+			"version": "0.1.27",
+			"resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
+			"integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==",
+			"dev": true,
+			"license": "MIT",
+			"bin": {
+				"regexp-tree": "bin/regexp-tree"
+			}
+		},
+		"node_modules/regexp.prototype.flags": {
+			"version": "1.5.4",
+			"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
+			"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"define-properties": "^1.2.1",
+				"es-errors": "^1.3.0",
+				"get-proto": "^1.0.1",
+				"gopd": "^1.2.0",
+				"set-function-name": "^2.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/regjsparser": {
+			"version": "0.10.0",
+			"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz",
+			"integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"dependencies": {
+				"jsesc": "~0.5.0"
+			},
+			"bin": {
+				"regjsparser": "bin/parser"
+			}
+		},
+		"node_modules/regjsparser/node_modules/jsesc": {
+			"version": "0.5.0",
+			"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+			"integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
+			"dev": true,
+			"bin": {
+				"jsesc": "bin/jsesc"
+			}
+		},
+		"node_modules/repeat-string": {
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+			"integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10"
+			}
+		},
+		"node_modules/require-directory": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+			"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/require-from-string": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+			"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/resolve": {
+			"version": "2.0.0-next.5",
+			"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
+			"integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-core-module": "^2.13.0",
+				"path-parse": "^1.0.7",
+				"supports-preserve-symlinks-flag": "^1.0.0"
+			},
+			"bin": {
+				"resolve": "bin/resolve"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/resolve-cwd": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+			"integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"resolve-from": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/resolve-from": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+			"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/resolve-pkg-maps": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+			"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+			"dev": true,
+			"license": "MIT",
+			"funding": {
+				"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+			}
+		},
+		"node_modules/restore-cursor": {
+			"version": "5.1.0",
+			"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+			"integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
+			"license": "MIT",
+			"dependencies": {
+				"onetime": "^7.0.0",
+				"signal-exit": "^4.1.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/restore-cursor/node_modules/onetime": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+			"integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
+			"license": "MIT",
+			"dependencies": {
+				"mimic-function": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/reusify": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+			"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"iojs": ">=1.0.0",
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/rimraf": {
+			"version": "5.0.10",
+			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
+			"integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"glob": "^10.3.7"
+			},
+			"bin": {
+				"rimraf": "dist/esm/bin.mjs"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/rimraf/node_modules/brace-expansion": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+			"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"balanced-match": "^1.0.0"
+			}
+		},
+		"node_modules/rimraf/node_modules/glob": {
+			"version": "10.4.5",
+			"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+			"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"foreground-child": "^3.1.0",
+				"jackspeak": "^3.1.2",
+				"minimatch": "^9.0.4",
+				"minipass": "^7.1.2",
+				"package-json-from-dist": "^1.0.0",
+				"path-scurry": "^1.11.1"
+			},
+			"bin": {
+				"glob": "dist/esm/bin.mjs"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/rimraf/node_modules/minimatch": {
+			"version": "9.0.5",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+			"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"brace-expansion": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=16 || 14 >=14.17"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/run-parallel": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+			"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			],
+			"license": "MIT",
+			"dependencies": {
+				"queue-microtask": "^1.2.2"
+			}
+		},
+		"node_modules/safe-array-concat": {
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
+			"integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"call-bound": "^1.0.2",
+				"get-intrinsic": "^1.2.6",
+				"has-symbols": "^1.1.0",
+				"isarray": "^2.0.5"
+			},
+			"engines": {
+				"node": ">=0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/safe-buffer": {
+			"version": "5.2.1",
+			"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+			"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			],
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/safe-push-apply": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
+			"integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"es-errors": "^1.3.0",
+				"isarray": "^2.0.5"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/safe-regex-test": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+			"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.2",
+				"es-errors": "^1.3.0",
+				"is-regex": "^1.2.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/schema-utils": {
+			"version": "3.3.0",
+			"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+			"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@types/json-schema": "^7.0.8",
+				"ajv": "^6.12.5",
+				"ajv-keywords": "^3.5.2"
+			},
+			"engines": {
+				"node": ">= 10.13.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/webpack"
+			}
+		},
+		"node_modules/semver": {
+			"version": "7.7.1",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+			"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+			"dev": true,
+			"license": "ISC",
+			"bin": {
+				"semver": "bin/semver.js"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/serialize-error": {
+			"version": "7.0.1",
+			"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
+			"integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"type-fest": "^0.13.1"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/serialize-javascript": {
+			"version": "6.0.2",
+			"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+			"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
+			"dev": true,
+			"license": "BSD-3-Clause",
+			"peer": true,
+			"dependencies": {
+				"randombytes": "^2.1.0"
+			}
+		},
+		"node_modules/set-function-length": {
+			"version": "1.2.2",
+			"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+			"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"define-data-property": "^1.1.4",
+				"es-errors": "^1.3.0",
+				"function-bind": "^1.1.2",
+				"get-intrinsic": "^1.2.4",
+				"gopd": "^1.0.1",
+				"has-property-descriptors": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/set-function-name": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+			"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"define-data-property": "^1.1.4",
+				"es-errors": "^1.3.0",
+				"functions-have-names": "^1.2.3",
+				"has-property-descriptors": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/set-proto": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
+			"integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"dunder-proto": "^1.0.1",
+				"es-errors": "^1.3.0",
+				"es-object-atoms": "^1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/shebang-command": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+			"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+			"license": "MIT",
+			"dependencies": {
+				"shebang-regex": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/shebang-regex": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+			"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/side-channel": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+			"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"es-errors": "^1.3.0",
+				"object-inspect": "^1.13.3",
+				"side-channel-list": "^1.0.0",
+				"side-channel-map": "^1.0.1",
+				"side-channel-weakmap": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/side-channel-list": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+			"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"es-errors": "^1.3.0",
+				"object-inspect": "^1.13.3"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/side-channel-map": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+			"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.2",
+				"es-errors": "^1.3.0",
+				"get-intrinsic": "^1.2.5",
+				"object-inspect": "^1.13.3"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/side-channel-weakmap": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+			"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.2",
+				"es-errors": "^1.3.0",
+				"get-intrinsic": "^1.2.5",
+				"object-inspect": "^1.13.3",
+				"side-channel-map": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/signal-exit": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+			"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+			"license": "ISC",
+			"engines": {
+				"node": ">=14"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
+		"node_modules/slash": {
+			"version": "5.1.0",
+			"resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
+			"integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=14.16"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/slice-ansi": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
+			"integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-styles": "^6.0.0",
+				"is-fullwidth-code-point": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/slice-ansi?sponsor=1"
+			}
+		},
+		"node_modules/source-map": {
+			"version": "0.6.1",
+			"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+			"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+			"dev": true,
+			"license": "BSD-3-Clause",
+			"peer": true,
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/source-map-support": {
+			"version": "0.5.21",
+			"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+			"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"buffer-from": "^1.0.0",
+				"source-map": "^0.6.0"
+			}
+		},
+		"node_modules/spdx-correct": {
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
+			"integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"dependencies": {
+				"spdx-expression-parse": "^3.0.0",
+				"spdx-license-ids": "^3.0.0"
+			}
+		},
+		"node_modules/spdx-exceptions": {
+			"version": "2.5.0",
+			"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
+			"integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
+			"dev": true,
+			"license": "CC-BY-3.0"
+		},
+		"node_modules/spdx-expression-parse": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+			"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"spdx-exceptions": "^2.1.0",
+				"spdx-license-ids": "^3.0.0"
+			}
+		},
+		"node_modules/spdx-license-ids": {
+			"version": "3.0.21",
+			"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz",
+			"integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==",
+			"dev": true,
+			"license": "CC0-1.0"
+		},
+		"node_modules/sprintf-js": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+			"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+			"dev": true,
+			"license": "BSD-3-Clause"
+		},
+		"node_modules/stack-utils": {
+			"version": "2.0.6",
+			"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+			"integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"escape-string-regexp": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/stack-utils/node_modules/escape-string-regexp": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+			"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/stdin-discarder": {
+			"version": "0.2.2",
+			"resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
+			"integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/stream-buffers": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
+			"integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==",
+			"license": "Unlicense",
+			"engines": {
+				"node": ">= 0.10.0"
+			}
+		},
+		"node_modules/string-width": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+			"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+			"license": "MIT",
+			"dependencies": {
+				"emoji-regex": "^10.3.0",
+				"get-east-asian-width": "^1.0.0",
+				"strip-ansi": "^7.1.0"
+			},
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/string-width-cjs": {
+			"name": "string-width",
+			"version": "4.2.3",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+			"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"emoji-regex": "^8.0.0",
+				"is-fullwidth-code-point": "^3.0.0",
+				"strip-ansi": "^6.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/string-width-cjs/node_modules/ansi-regex": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/string-width-cjs/node_modules/emoji-regex": {
+			"version": "8.0.0",
+			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/string-width-cjs/node_modules/strip-ansi": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-regex": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/string.prototype.trim": {
+			"version": "1.2.10",
+			"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
+			"integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"call-bound": "^1.0.2",
+				"define-data-property": "^1.1.4",
+				"define-properties": "^1.2.1",
+				"es-abstract": "^1.23.5",
+				"es-object-atoms": "^1.0.0",
+				"has-property-descriptors": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/string.prototype.trimend": {
+			"version": "1.0.9",
+			"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
+			"integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"call-bound": "^1.0.2",
+				"define-properties": "^1.2.1",
+				"es-object-atoms": "^1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/string.prototype.trimstart": {
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+			"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.7",
+				"define-properties": "^1.2.1",
+				"es-object-atoms": "^1.0.0"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/strip-ansi": {
+			"version": "7.1.0",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+			"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+			"license": "MIT",
+			"dependencies": {
+				"ansi-regex": "^6.0.1"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/strip-ansi?sponsor=1"
+			}
+		},
+		"node_modules/strip-ansi-cjs": {
+			"name": "strip-ansi",
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-regex": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/strip-bom": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+			"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/strip-eof": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+			"integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
+			"license": "MIT",
+			"engines": {
+				"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==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/strip-indent": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+			"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"min-indent": "^1.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/strip-json-comments": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+			"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/supertap": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/supertap/-/supertap-3.0.1.tgz",
+			"integrity": "sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"indent-string": "^5.0.0",
+				"js-yaml": "^3.14.1",
+				"serialize-error": "^7.0.1",
+				"strip-ansi": "^7.0.1"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			}
+		},
+		"node_modules/supports-color": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+			"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"has-flag": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/supports-hyperlinks": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz",
+			"integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"has-flag": "^4.0.0",
+				"supports-color": "^7.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/supports-preserve-symlinks-flag": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+			"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/synckit": {
+			"version": "0.9.2",
+			"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz",
+			"integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@pkgr/core": "^0.1.0",
+				"tslib": "^2.6.2"
+			},
+			"engines": {
+				"node": "^14.18.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/unts"
+			}
+		},
+		"node_modules/tapable": {
+			"version": "0.1.10",
+			"resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz",
+			"integrity": "sha512-jX8Et4hHg57mug1/079yitEKWGB3LCwoxByLsNim89LABq8NqgiX+6iYVOsq0vX8uJHkU+DZ5fnq95f800bEsQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.6"
+			}
+		},
+		"node_modules/tar": {
+			"version": "7.4.3",
+			"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
+			"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"@isaacs/fs-minipass": "^4.0.0",
+				"chownr": "^3.0.0",
+				"minipass": "^7.1.2",
+				"minizlib": "^3.0.1",
+				"mkdirp": "^3.0.1",
+				"yallist": "^5.0.0"
+			},
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/temp-dir": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz",
+			"integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=14.16"
+			}
+		},
+		"node_modules/tempy": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz",
+			"integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==",
+			"license": "MIT",
+			"dependencies": {
+				"is-stream": "^3.0.0",
+				"temp-dir": "^3.0.0",
+				"type-fest": "^2.12.2",
+				"unique-string": "^3.0.0"
+			},
+			"engines": {
+				"node": ">=14.16"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/tempy/node_modules/type-fest": {
+			"version": "2.19.0",
+			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+			"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+			"license": "(MIT OR CC0-1.0)",
+			"engines": {
+				"node": ">=12.20"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/terser": {
+			"version": "5.38.1",
+			"resolved": "https://registry.npmjs.org/terser/-/terser-5.38.1.tgz",
+			"integrity": "sha512-GWANVlPM/ZfYzuPHjq0nxT+EbOEDDN3Jwhwdg1D8TU8oSkktp8w64Uq4auuGLxFSoNTRDncTq2hQHX1Ld9KHkA==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"peer": true,
+			"dependencies": {
+				"@jridgewell/source-map": "^0.3.3",
+				"acorn": "^8.8.2",
+				"commander": "^2.20.0",
+				"source-map-support": "~0.5.20"
+			},
+			"bin": {
+				"terser": "bin/terser"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/terser-webpack-plugin": {
+			"version": "5.3.11",
+			"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz",
+			"integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@jridgewell/trace-mapping": "^0.3.25",
+				"jest-worker": "^27.4.5",
+				"schema-utils": "^4.3.0",
+				"serialize-javascript": "^6.0.2",
+				"terser": "^5.31.1"
+			},
+			"engines": {
+				"node": ">= 10.13.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/webpack"
+			},
+			"peerDependencies": {
+				"webpack": "^5.1.0"
+			},
+			"peerDependenciesMeta": {
+				"@swc/core": {
+					"optional": true
+				},
+				"esbuild": {
+					"optional": true
+				},
+				"uglify-js": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/terser-webpack-plugin/node_modules/ajv": {
+			"version": "8.17.1",
+			"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+			"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"fast-deep-equal": "^3.1.3",
+				"fast-uri": "^3.0.1",
+				"json-schema-traverse": "^1.0.0",
+				"require-from-string": "^2.0.2"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/epoberezkin"
+			}
+		},
+		"node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
+			"version": "5.1.0",
+			"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+			"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"fast-deep-equal": "^3.1.3"
+			},
+			"peerDependencies": {
+				"ajv": "^8.8.2"
+			}
+		},
+		"node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+			"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/terser-webpack-plugin/node_modules/schema-utils": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
+			"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@types/json-schema": "^7.0.9",
+				"ajv": "^8.9.0",
+				"ajv-formats": "^2.1.1",
+				"ajv-keywords": "^5.1.0"
+			},
+			"engines": {
+				"node": ">= 10.13.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/webpack"
+			}
+		},
+		"node_modules/text-table": {
+			"version": "0.2.0",
+			"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+			"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"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==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=4"
+			}
+		},
+		"node_modules/tn1150": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/tn1150/-/tn1150-0.1.0.tgz",
+			"integrity": "sha512-DbplOfQFkqG5IHcDyyrs/lkvSr3mPUVsFf/RbDppOshs22yTPnSJWEe6FkYd1txAwU/zcnR905ar2fi4kwF29w==",
+			"license": "MIT",
+			"dependencies": {
+				"unorm": "^1.4.1"
+			},
+			"engines": {
+				"node": ">=0.12"
+			}
+		},
+		"node_modules/to-absolute-glob": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-3.0.0.tgz",
+			"integrity": "sha512-loO/XEWTRqpfcpI7+Jr2RR2Umaaozx1t6OSVWtMi0oy5F/Fxg3IC+D/TToDnxyAGs7uZBGT/6XmyDUxgsObJXA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-absolute": "^1.0.0",
+				"is-negated-glob": "^1.0.0"
+			},
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/to-data-view": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz",
+			"integrity": "sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==",
+			"license": "MIT"
+		},
+		"node_modules/to-regex-range": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+			"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-number": "^7.0.0"
+			},
+			"engines": {
+				"node": ">=8.0"
+			}
+		},
+		"node_modules/tr46": {
+			"version": "0.0.3",
+			"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+			"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/ts-api-utils": {
+			"version": "1.4.3",
+			"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
+			"integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=16"
+			},
+			"peerDependencies": {
+				"typescript": ">=4.2.0"
+			}
+		},
+		"node_modules/tsconfig-paths": {
+			"version": "3.15.0",
+			"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+			"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@types/json5": "^0.0.29",
+				"json5": "^1.0.2",
+				"minimist": "^1.2.6",
+				"strip-bom": "^3.0.0"
+			}
+		},
+		"node_modules/tslib": {
+			"version": "2.8.1",
+			"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+			"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+			"dev": true,
+			"license": "0BSD"
+		},
+		"node_modules/type-check": {
+			"version": "0.4.0",
+			"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+			"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"prelude-ls": "^1.2.1"
+			},
+			"engines": {
+				"node": ">= 0.8.0"
+			}
+		},
+		"node_modules/type-fest": {
+			"version": "0.13.1",
+			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
+			"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
+			"dev": true,
+			"license": "(MIT OR CC0-1.0)",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/typed-array-buffer": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+			"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"es-errors": "^1.3.0",
+				"is-typed-array": "^1.1.14"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			}
+		},
+		"node_modules/typed-array-byte-length": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+			"integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.8",
+				"for-each": "^0.3.3",
+				"gopd": "^1.2.0",
+				"has-proto": "^1.2.0",
+				"is-typed-array": "^1.1.14"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/typed-array-byte-offset": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+			"integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"available-typed-arrays": "^1.0.7",
+				"call-bind": "^1.0.8",
+				"for-each": "^0.3.3",
+				"gopd": "^1.2.0",
+				"has-proto": "^1.2.0",
+				"is-typed-array": "^1.1.15",
+				"reflect.getprototypeof": "^1.0.9"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/typed-array-length": {
+			"version": "1.0.7",
+			"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
+			"integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bind": "^1.0.7",
+				"for-each": "^0.3.3",
+				"gopd": "^1.0.1",
+				"is-typed-array": "^1.1.13",
+				"possible-typed-array-names": "^1.0.0",
+				"reflect.getprototypeof": "^1.0.6"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/typescript": {
+			"version": "5.7.3",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
+			"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"bin": {
+				"tsc": "bin/tsc",
+				"tsserver": "bin/tsserver"
+			},
+			"engines": {
+				"node": ">=14.17"
+			}
+		},
+		"node_modules/unbox-primitive": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+			"integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.3",
+				"has-bigints": "^1.0.2",
+				"has-symbols": "^1.1.0",
+				"which-boxed-primitive": "^1.1.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/unc-path-regex": {
+			"version": "0.1.2",
+			"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+			"integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/undici-types": {
+			"version": "6.20.0",
+			"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+			"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true
+		},
+		"node_modules/unicorn-magic": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+			"integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=18"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/unique-string": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz",
+			"integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==",
+			"license": "MIT",
+			"dependencies": {
+				"crypto-random-string": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/unorm": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
+			"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==",
+			"license": "MIT or GPL-2.0",
+			"engines": {
+				"node": ">= 0.4.0"
+			}
+		},
+		"node_modules/update-browserslist-db": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz",
+			"integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==",
+			"dev": true,
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/browserslist"
+				},
+				{
+					"type": "tidelift",
+					"url": "https://tidelift.com/funding/github/npm/browserslist"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"escalade": "^3.2.0",
+				"picocolors": "^1.1.1"
+			},
+			"bin": {
+				"update-browserslist-db": "cli.js"
+			},
+			"peerDependencies": {
+				"browserslist": ">= 4.21.0"
+			}
+		},
+		"node_modules/uri-js": {
+			"version": "4.4.1",
+			"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+			"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"dependencies": {
+				"punycode": "^2.1.0"
+			}
+		},
+		"node_modules/url-or-path": {
+			"version": "2.3.2",
+			"resolved": "https://registry.npmjs.org/url-or-path/-/url-or-path-2.3.2.tgz",
+			"integrity": "sha512-DOI9KXk0bc/JOmFQHbn25knW2GX/ym7+egKFEFApG3VdDzRlLBMCIrMnruq4AZUGop1W0aiYQ5Vry6clzhxcOQ==",
+			"dev": true,
+			"license": "MIT",
+			"funding": {
+				"url": "https://github.com/fisker/url-or-path?sponsor=1"
+			}
+		},
+		"node_modules/validate-npm-package-license": {
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+			"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"dependencies": {
+				"spdx-correct": "^3.0.0",
+				"spdx-expression-parse": "^3.0.0"
+			}
+		},
+		"node_modules/watchpack": {
+			"version": "2.4.2",
+			"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
+			"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"glob-to-regexp": "^0.4.1",
+				"graceful-fs": "^4.1.2"
+			},
+			"engines": {
+				"node": ">=10.13.0"
+			}
+		},
+		"node_modules/webidl-conversions": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+			"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+			"dev": true,
+			"license": "BSD-2-Clause"
+		},
+		"node_modules/webpack": {
+			"version": "5.97.1",
+			"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz",
+			"integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"@types/eslint-scope": "^3.7.7",
+				"@types/estree": "^1.0.6",
+				"@webassemblyjs/ast": "^1.14.1",
+				"@webassemblyjs/wasm-edit": "^1.14.1",
+				"@webassemblyjs/wasm-parser": "^1.14.1",
+				"acorn": "^8.14.0",
+				"browserslist": "^4.24.0",
+				"chrome-trace-event": "^1.0.2",
+				"enhanced-resolve": "^5.17.1",
+				"es-module-lexer": "^1.2.1",
+				"eslint-scope": "5.1.1",
+				"events": "^3.2.0",
+				"glob-to-regexp": "^0.4.1",
+				"graceful-fs": "^4.2.11",
+				"json-parse-even-better-errors": "^2.3.1",
+				"loader-runner": "^4.2.0",
+				"mime-types": "^2.1.27",
+				"neo-async": "^2.6.2",
+				"schema-utils": "^3.2.0",
+				"tapable": "^2.1.1",
+				"terser-webpack-plugin": "^5.3.10",
+				"watchpack": "^2.4.1",
+				"webpack-sources": "^3.2.3"
+			},
+			"bin": {
+				"webpack": "bin/webpack.js"
+			},
+			"engines": {
+				"node": ">=10.13.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/webpack"
+			},
+			"peerDependenciesMeta": {
+				"webpack-cli": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/webpack-sources": {
+			"version": "3.2.3",
+			"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
+			"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"engines": {
+				"node": ">=10.13.0"
+			}
+		},
+		"node_modules/webpack/node_modules/enhanced-resolve": {
+			"version": "5.18.1",
+			"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
+			"integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"dependencies": {
+				"graceful-fs": "^4.2.4",
+				"tapable": "^2.2.0"
+			},
+			"engines": {
+				"node": ">=10.13.0"
+			}
+		},
+		"node_modules/webpack/node_modules/eslint-scope": {
+			"version": "5.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+			"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"peer": true,
+			"dependencies": {
+				"esrecurse": "^4.3.0",
+				"estraverse": "^4.1.1"
+			},
+			"engines": {
+				"node": ">=8.0.0"
+			}
+		},
+		"node_modules/webpack/node_modules/estraverse": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+			"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"peer": true,
+			"engines": {
+				"node": ">=4.0"
+			}
+		},
+		"node_modules/webpack/node_modules/tapable": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+			"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+			"dev": true,
+			"license": "MIT",
+			"peer": true,
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"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==",
+			"dev": true,
+			"license": "ISC",
+			"engines": {
+				"node": ">=6"
+			}
+		},
+		"node_modules/whatwg-url": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+			"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"tr46": "~0.0.3",
+				"webidl-conversions": "^3.0.0"
+			}
+		},
+		"node_modules/which": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+			"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+			"license": "ISC",
+			"dependencies": {
+				"isexe": "^2.0.0"
+			},
+			"bin": {
+				"node-which": "bin/node-which"
+			},
+			"engines": {
+				"node": ">= 8"
+			}
+		},
+		"node_modules/which-boxed-primitive": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+			"integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-bigint": "^1.1.0",
+				"is-boolean-object": "^1.2.1",
+				"is-number-object": "^1.1.1",
+				"is-string": "^1.1.1",
+				"is-symbol": "^1.1.1"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/which-builtin-type": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+			"integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"call-bound": "^1.0.2",
+				"function.prototype.name": "^1.1.6",
+				"has-tostringtag": "^1.0.2",
+				"is-async-function": "^2.0.0",
+				"is-date-object": "^1.1.0",
+				"is-finalizationregistry": "^1.1.0",
+				"is-generator-function": "^1.0.10",
+				"is-regex": "^1.2.1",
+				"is-weakref": "^1.0.2",
+				"isarray": "^2.0.5",
+				"which-boxed-primitive": "^1.1.0",
+				"which-collection": "^1.0.2",
+				"which-typed-array": "^1.1.16"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/which-collection": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+			"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"is-map": "^2.0.3",
+				"is-set": "^2.0.3",
+				"is-weakmap": "^2.0.2",
+				"is-weakset": "^2.0.3"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/which-typed-array": {
+			"version": "1.1.18",
+			"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz",
+			"integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"available-typed-arrays": "^1.0.7",
+				"call-bind": "^1.0.8",
+				"call-bound": "^1.0.3",
+				"for-each": "^0.3.3",
+				"gopd": "^1.2.0",
+				"has-tostringtag": "^1.0.2"
+			},
+			"engines": {
+				"node": ">= 0.4"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/word-wrap": {
+			"version": "1.2.5",
+			"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+			"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+			"dev": true,
+			"license": "MIT",
+			"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",
+			"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-styles": "^4.0.0",
+				"string-width": "^4.1.0",
+				"strip-ansi": "^6.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+			}
+		},
+		"node_modules/wrap-ansi-cjs": {
+			"name": "wrap-ansi",
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+			"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-styles": "^4.0.0",
+				"string-width": "^4.1.0",
+				"strip-ansi": "^6.0.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+			}
+		},
+		"node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+			"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-convert": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
+			}
+		},
+		"node_modules/wrap-ansi-cjs/node_modules/color-convert": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+			"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-name": "~1.1.4"
+			},
+			"engines": {
+				"node": ">=7.0.0"
+			}
+		},
+		"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
+			"version": "8.0.0",
+			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/wrap-ansi-cjs/node_modules/string-width": {
+			"version": "4.2.3",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+			"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"emoji-regex": "^8.0.0",
+				"is-fullwidth-code-point": "^3.0.0",
+				"strip-ansi": "^6.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-regex": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/wrap-ansi/node_modules/ansi-regex": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/wrap-ansi/node_modules/ansi-styles": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+			"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-convert": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
+			}
+		},
+		"node_modules/wrap-ansi/node_modules/color-convert": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+			"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"color-name": "~1.1.4"
+			},
+			"engines": {
+				"node": ">=7.0.0"
+			}
+		},
+		"node_modules/wrap-ansi/node_modules/emoji-regex": {
+			"version": "8.0.0",
+			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/wrap-ansi/node_modules/string-width": {
+			"version": "4.2.3",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+			"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"emoji-regex": "^8.0.0",
+				"is-fullwidth-code-point": "^3.0.0",
+				"strip-ansi": "^6.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/wrap-ansi/node_modules/strip-ansi": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-regex": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/wrappy": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+			"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+			"license": "ISC"
+		},
+		"node_modules/write-file-atomic": {
+			"version": "6.0.0",
+			"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-6.0.0.tgz",
+			"integrity": "sha512-GmqrO8WJ1NuzJ2DrziEI2o57jKAVIQNf8a18W3nCYU3H7PNWqCCVTeH6/NQE93CIllIgQS98rrmVkYgTX9fFJQ==",
+			"dev": true,
+			"license": "ISC",
+			"dependencies": {
+				"imurmurhash": "^0.1.4",
+				"signal-exit": "^4.0.1"
+			},
+			"engines": {
+				"node": "^18.17.0 || >=20.5.0"
+			}
+		},
+		"node_modules/xmlbuilder": {
+			"version": "15.1.1",
+			"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
+			"integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=8.0"
+			}
+		},
+		"node_modules/xo": {
+			"version": "0.56.0",
+			"resolved": "https://registry.npmjs.org/xo/-/xo-0.56.0.tgz",
+			"integrity": "sha512-ohzSqgQ8POgZ3KNaEK/gxDovb6h3cglxv8+xi9Dn7gmRe8g4qotpOZpMs5ACJhvkJDmJOhiKbk6Uq6Mx1Di9DA==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@eslint/eslintrc": "^2.1.0",
+				"@typescript-eslint/eslint-plugin": "^6.0.0",
+				"@typescript-eslint/parser": "^6.0.0",
+				"arrify": "^3.0.0",
+				"cosmiconfig": "^8.2.0",
+				"define-lazy-prop": "^3.0.0",
+				"eslint": "^8.45.0",
+				"eslint-config-prettier": "^8.8.0",
+				"eslint-config-xo": "^0.43.1",
+				"eslint-config-xo-typescript": "^1.0.0",
+				"eslint-formatter-pretty": "^5.0.0",
+				"eslint-import-resolver-webpack": "^0.13.2",
+				"eslint-plugin-ava": "^14.0.0",
+				"eslint-plugin-eslint-comments": "^3.2.0",
+				"eslint-plugin-import": "~2.27.5",
+				"eslint-plugin-n": "^16.0.1",
+				"eslint-plugin-no-use-extend-native": "^0.5.0",
+				"eslint-plugin-prettier": "^5.0.0",
+				"eslint-plugin-unicorn": "^48.0.0",
+				"esm-utils": "^4.1.2",
+				"find-cache-dir": "^4.0.0",
+				"find-up": "^6.3.0",
+				"get-stdin": "^9.0.0",
+				"get-tsconfig": "^4.6.2",
+				"globby": "^13.2.2",
+				"imurmurhash": "^0.1.4",
+				"json-stable-stringify-without-jsonify": "^1.0.1",
+				"lodash-es": "^4.17.21",
+				"meow": "^12.0.1",
+				"micromatch": "^4.0.5",
+				"open-editor": "^4.0.0",
+				"prettier": "^3.0.0",
+				"semver": "^7.5.4",
+				"slash": "^5.1.0",
+				"to-absolute-glob": "^3.0.0",
+				"typescript": "^5.1.6"
+			},
+			"bin": {
+				"xo": "cli.js"
+			},
+			"engines": {
+				"node": ">=16"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/xo/node_modules/globby": {
+			"version": "13.2.2",
+			"resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz",
+			"integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"dir-glob": "^3.0.1",
+				"fast-glob": "^3.3.0",
+				"ignore": "^5.2.4",
+				"merge2": "^1.4.1",
+				"slash": "^4.0.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/xo/node_modules/globby/node_modules/slash": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
+			"integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/xo/node_modules/ignore": {
+			"version": "5.3.2",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+			"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">= 4"
+			}
+		},
+		"node_modules/xo/node_modules/meow": {
+			"version": "12.1.1",
+			"resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz",
+			"integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=16.10"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/xtend": {
+			"version": "4.0.2",
+			"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+			"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=0.4"
+			}
+		},
+		"node_modules/y18n": {
+			"version": "5.0.8",
+			"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+			"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+			"dev": true,
+			"license": "ISC",
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/yallist": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+			"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+			"dev": true,
+			"license": "BlueOak-1.0.0",
+			"engines": {
+				"node": ">=18"
+			}
+		},
+		"node_modules/yargs": {
+			"version": "17.7.2",
+			"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+			"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"cliui": "^8.0.1",
+				"escalade": "^3.1.1",
+				"get-caller-file": "^2.0.5",
+				"require-directory": "^2.1.1",
+				"string-width": "^4.2.3",
+				"y18n": "^5.0.5",
+				"yargs-parser": "^21.1.1"
+			},
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/yargs-parser": {
+			"version": "21.1.1",
+			"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+			"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+			"dev": true,
+			"license": "ISC",
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/yargs/node_modules/ansi-regex": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/yargs/node_modules/emoji-regex": {
+			"version": "8.0.0",
+			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+			"dev": true,
+			"license": "MIT"
+		},
+		"node_modules/yargs/node_modules/is-fullwidth-code-point": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/yargs/node_modules/string-width": {
+			"version": "4.2.3",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+			"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"emoji-regex": "^8.0.0",
+				"is-fullwidth-code-point": "^3.0.0",
+				"strip-ansi": "^6.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/yargs/node_modules/strip-ansi": {
+			"version": "6.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"ansi-regex": "^5.0.1"
+			},
+			"engines": {
+				"node": ">=8"
+			}
+		},
+		"node_modules/yocto-queue": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz",
+			"integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": ">=12.20"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		}
+	}
+}
diff --git a/scripts/build.sh b/scripts/build.sh
new file mode 100755
index 0000000..5b573e6
--- /dev/null
+++ b/scripts/build.sh
@@ -0,0 +1,139 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Add standard Nix environment variables
+out="${out:-release}"
+
+# Build Documentation @ https://developer.apple.com/forums/thread/737894
+APPLE_TEAM_ID="4399GN35BJ"
+CODE_SIGN_IDENTITY="Developer ID Application: Coder Technologies Inc (${APPLE_TEAM_ID})"
+
+# Default values pulled in from env
+APP_PROF_PATH=${APP_PROF_PATH:-""}
+EXT_PROF_PATH=${EXT_PROF_PATH:-""}
+KEYCHAIN=${KEYCHAIN:-""}
+
+# Function to display usage
+usage() {
+  echo "Usage: $0 [--app-prof-path <path>] [--ext-prof-path <path>] [--keychain <path>]"
+  echo "  --app-prof-path <path>  Set the APP_PROF_PATH variable"
+  echo "  --ext-prof-path <path>  Set the EXT_PROF_PATH variable"
+  echo "  --keychain      <path>  Set the KEYCHAIN variable"
+  echo "  -h, --help              Display this help message"
+}
+
+# Parse command line arguments
+while [[ "$#" -gt 0 ]]; do
+  case $1 in
+  --app-prof-path)
+    APP_PROF_PATH="$2"
+    shift 2
+    ;;
+  --ext-prof-path)
+    EXT_PROF_PATH="$2"
+    shift 2
+    ;;
+  --keychain)
+    KEYCHAIN="$2"
+    shift 2
+    ;;
+  -h | --help)
+    usage
+    exit 0
+    ;;
+  *)
+    echo "Unknown parameter passed: $1"
+    usage
+    exit 1
+    ;;
+  esac
+done
+
+# Check if required variables are set
+if [[ -z "$APP_PROF_PATH" || -z "$EXT_PROF_PATH" || -z "$KEYCHAIN" ]]; then
+  echo "Missing required values"
+  echo "APP_PROF_PATH: $APP_PROF_PATH"
+  echo "EXT_PROF_PATH: $EXT_PROF_PATH"
+  echo "KEYCHAIN: $KEYCHAIN"
+  echo
+  usage
+  exit 1
+fi
+
+XCODE_PROVISIONING_PROFILES_DIR="$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"
+ALT_PROVISIONING_PROFILES_DIR="$HOME/Library/MobileDevice/Provisioning Profiles"
+mkdir -p "$XCODE_PROVISIONING_PROFILES_DIR"
+mkdir -p "$ALT_PROVISIONING_PROFILES_DIR"
+
+get_uuid() {
+  strings "$1" | grep -E -o '[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}'
+}
+
+# Extract the ID of each provisioning profile
+APP_PROVISIONING_PROFILE_ID=$(get_uuid "$APP_PROF_PATH")
+EXT_PROVISIONING_PROFILE_ID=$(get_uuid "$EXT_PROF_PATH")
+PTP_SUFFIX="-systemextension"
+
+# Install Provisioning Profiles
+cp "$APP_PROF_PATH" "${XCODE_PROVISIONING_PROFILES_DIR}/${APP_PROVISIONING_PROFILE_ID}.provisionprofile"
+cp "$APP_PROF_PATH" "${ALT_PROVISIONING_PROFILES_DIR}/${APP_PROVISIONING_PROFILE_ID}.provisionprofile"
+cp "$EXT_PROF_PATH" "${XCODE_PROVISIONING_PROFILES_DIR}/${EXT_PROVISIONING_PROFILE_ID}.provisionprofile"
+cp "$EXT_PROF_PATH" "${ALT_PROVISIONING_PROFILES_DIR}/${EXT_PROVISIONING_PROFILE_ID}.provisionprofile"
+
+export APP_PROVISIONING_PROFILE_ID
+export EXT_PROVISIONING_PROFILE_ID
+export PTP_SUFFIX
+
+make clean/project clean/build
+
+make
+
+xcodebuild \
+  -project "Coder Desktop/Coder Desktop.xcodeproj" \
+  -scheme "Coder Desktop" \
+  -configuration "Release" \
+  -skipPackagePluginValidation \
+  CODE_SIGN_STYLE=Manual \
+  CODE_SIGN_IDENTITY="$CODE_SIGN_IDENTITY" \
+  CODE_SIGN_INJECT_BASE_ENTITLEMENTS=NO \
+  CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION=YES \
+  OTHER_CODE_SIGN_FLAGS='--timestamp' | LC_ALL="en_US.UTF-8" xcpretty
+
+BUILT_APP_PATH="./build/Coder Desktop.app"
+DMG_PATH="$out/Coder Desktop.dmg"
+DSYM_ZIPPED_PATH="$out/coder-desktop-universal-dsym.zip"
+APP_ZIPPED_PATH="$out/coder-desktop-universal.zip"
+
+mkdir -p "$out"
+mkdir build
+
+ditto "$(find "$HOME/Library/Developer/Xcode/DerivedData" -name "Coder Desktop.app")" "$BUILT_APP_PATH"
+
+create-dmg \
+  --identity="$CODE_SIGN_IDENTITY" \
+  "$BUILT_APP_PATH" \
+  "$(dirname "$BUILT_APP_PATH")"
+
+mv "$(dirname "$BUILT_APP_PATH")"/Coder\ Desktop*.dmg "$DMG_PATH"
+
+# Notarize
+xcrun notarytool store-credentials "notarytool-credentials" \
+  --apple-id "$APPLE_ID" \
+  --team-id "$APPLE_TEAM_ID" \
+  --password "$APPLE_ID_PASSWORD" \
+  --keychain "$KEYCHAIN"
+
+xcrun notarytool submit "$DMG_PATH" \
+  --keychain-profile "notarytool-credentials" \
+  --keychain "$KEYCHAIN" \
+  --wait
+
+# Staple the notarization to the app and dmg, so they work without internet
+xcrun stapler staple "$DMG_PATH"
+xcrun stapler staple "$BUILT_APP_PATH"
+
+# Add dsym to build artifacts
+zip -9 -r --symlinks "$DSYM_ZIPPED_PATH" "$(find "$HOME/Library/Developer/Xcode/DerivedData" -name "Coder Desktop.app.dSYM")"
+
+# Add zipped app to build artifacts
+zip -9 -r --symlinks "$APP_ZIPPED_PATH" "$BUILT_APP_PATH"

From 071bf7ed10ec7e5c4fd9cfb2003d8914342c00f3 Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Wed, 12 Feb 2025 18:23:43 +1100
Subject: [PATCH 8/9] ignore package-lock in git diff

---
 .gitattributes | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 .gitattributes

diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..effdf65
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+nix/create-dmg/package-lock.json -diff
\ No newline at end of file

From d74acf78657fde9316d5fb16d029795c0a4c1731 Mon Sep 17 00:00:00 2001
From: Thomas Kosiewski <tk@coder.com>
Date: Wed, 12 Feb 2025 12:37:01 +0100
Subject: [PATCH 9/9] fetch tags

Change-Id: I9330b6c05af3b0103905d48ef93936a399a2c6b3
Signed-off-by: Thomas Kosiewski <tk@coder.com>
---
 .github/workflows/ci.yml      | 6 ++++++
 .github/workflows/release.yml | 2 ++
 2 files changed, 8 insertions(+)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 70d81e9..3d06a29 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -24,6 +24,8 @@ jobs:
           fetch-depth: 1
           persist-credentials: false
 
+      - run: git fetch --tags
+
       - name: Switch XCode Version
         uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
         with:
@@ -46,6 +48,8 @@ jobs:
           fetch-depth: 1
           persist-credentials: false
 
+      - run: git fetch --tags
+
       - name: Switch XCode Version
         uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
         with:
@@ -68,6 +72,8 @@ jobs:
           fetch-depth: 1
           persist-credentials: false
 
+      - run: git fetch --tags
+
       - name: Setup Nix
         uses: ./.github/actions/nix-devshell
 
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6a546bf..1ef9e88 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -20,6 +20,8 @@ jobs:
           fetch-depth: 1
           persist-credentials: false
 
+      - run: git fetch --tags
+
       - name: Switch XCode Version
         uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
         with: