All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/30] Add vendor support for go, npm and rust
@ 2025-02-11 15:00 Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 01/30] classes: create-spdx-2.2: use expanded FetchData for downloaded packages Stefan Herbrechtsmeier
                   ` (30 more replies)
  0 siblings, 31 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier, bitbake-devel

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

The series adds on-the-fly support for package manager specific
dependencies and vendor directories. It contains the following changes:
1. Adds an early fetch, unpack and patch task to unpack and patch source
   code with an embedded lock file for dependencies.
2. Parse the go.sum, Cargo.lock and package-lock.json lock files and
   resolve the dependencies to SRC_URIs.
3. Save the SRC_URIs in a file and adapt all SRC_URIs users to handle
   the SRC_URI files beside the SRC_URIs in the recipe.
4. Create a package manager specific vendor directory during unpack to
   support additional patching of the dependencies.
5. Add the dependency name and version to the SBOM.
6. Simplify the npm support


Stefan Herbrechtsmeier (30):
  classes: create-spdx-2.2: use expanded FetchData for downloaded
    packages
  lib: spdx30_tasks: use expanded FetchData for download files
  classes: create-spdx-2.2: use name and version for download
    dependencies
  lib: bb: fetch2: add support to unpack .crate files
  lib: oe: add vendor module
  lib: oe: vendor: add cargo support
  lib: oe: vendor: add go support
  lib: oe: vendor: add npm support
  oeqa: oelib: add vendor tests
  conf: bitbake: add SRC_URI_FILES variable
  classes: go: make source directory configurable
  classes: go-mod: make class customizable
  classes: add nodejs-arch class
  classes: base: add get_src_uris and unpack_src_uris functions
  classes: add early fetch, unpack and patch support
  classes: add vendor class
  classes: add vendor class for cargo
  classes: add vendor class for go
  classes: add vendor class for npm
  classes: add vendor_npm_build class
  python3-bcrypt: mirgrate to vendor cargo class
  python3-cryptography: mirgrate to vendor cargo class
  python3-maturin: mirgrate to vendor cargo class
  python3-rpds-py: mirgrate to vendor cargo class
  librsvg: mirgrate to vendor cargo class
  librsvg: update dependecies to fix RUSTSEC-2024-0421
  [DO NOT MERGE] recipes: add crucible go demo
  [DO NOT MERGE] recipes: add node-red npm demo
  [DO NOT MERGE] recipes: add nucleoidai npm demo
  [DO NOT MERGE] classes: spdx: use version 2.2

 bitbake/lib/bb/fetch2/__init__.py             |    2 +-
 .../crucible/crucible2_2023.11.02.bb          |   18 +
 .../node-red/node-red/package-lock.json       | 6096 +++++++++++++++++
 .../node-red/node-red_4.0.8.bb                |   14 +
 .../nucleoidai/nucleoidai_0.7.10.bb           |   11 +
 meta/classes-global/base.bbclass              |   47 +-
 meta/classes-global/patch.bbclass             |   17 +-
 meta/classes-recipe/early.bbclass             |   61 +
 meta/classes-recipe/go-mod.bbclass            |   10 +-
 meta/classes-recipe/go.bbclass                |   22 +-
 meta/classes-recipe/nodejs-arch.bbclass       |   15 +
 meta/classes-recipe/vendor.bbclass            |   28 +
 meta/classes-recipe/vendor_cargo.bbclass      |   46 +
 meta/classes-recipe/vendor_go.bbclass         |   59 +
 meta/classes-recipe/vendor_npm.bbclass        |  115 +
 meta/classes-recipe/vendor_npm_build.bbclass  |   50 +
 meta/classes/archiver.bbclass                 |    4 +-
 meta/classes/buildhistory.bbclass             |    4 +-
 meta/classes/copyleft_compliance.bbclass      |    2 +-
 meta/classes/create-spdx-2.2.bbclass          |   14 +-
 meta/classes/create-spdx.bbclass              |    2 +-
 meta/classes/externalsrc.bbclass              |    2 +-
 meta/conf/bitbake.conf                        |    1 +
 meta/lib/oe/patch.py                          |   10 +-
 meta/lib/oe/spdx30_tasks.py                   |    5 +-
 meta/lib/oe/vendor/__init__.py                |   28 +
 meta/lib/oe/vendor/cargo.py                   |  121 +
 meta/lib/oe/vendor/go.py                      |   96 +
 meta/lib/oe/vendor/npm.py                     |  141 +
 meta/lib/oeqa/selftest/cases/oelib/vendor.py  |  237 +
 .../python/python3-bcrypt-crates.inc          |   84 -
 .../python/python3-bcrypt_4.2.1.bb            |    4 +-
 .../python/python3-cryptography-crates.inc    |   76 -
 .../python/python3-cryptography.bb            |    4 +-
 .../python/python3-maturin-crates.inc         |  712 --
 .../python/python3-maturin_1.8.1.bb           |    4 +-
 .../python/python3-rpds-py-crates.inc         |   54 -
 .../python/python3-rpds-py_0.22.3.bb          |    4 +-
 meta/recipes-gnome/librsvg/librsvg-crates.inc |  590 --
 ...-to-get-an-updated-idna-rustsec-2024.patch |  398 ++
 meta/recipes-gnome/librsvg/librsvg_2.59.2.bb  |    7 +-
 41 files changed, 7633 insertions(+), 1582 deletions(-)
 create mode 100644 meta-selftest/recipes-support/crucible/crucible2_2023.11.02.bb
 create mode 100644 meta-selftest/recipes-support/node-red/node-red/package-lock.json
 create mode 100644 meta-selftest/recipes-support/node-red/node-red_4.0.8.bb
 create mode 100644 meta-selftest/recipes-support/nucleoidai/nucleoidai_0.7.10.bb
 create mode 100644 meta/classes-recipe/early.bbclass
 create mode 100644 meta/classes-recipe/nodejs-arch.bbclass
 create mode 100644 meta/classes-recipe/vendor.bbclass
 create mode 100644 meta/classes-recipe/vendor_cargo.bbclass
 create mode 100644 meta/classes-recipe/vendor_go.bbclass
 create mode 100644 meta/classes-recipe/vendor_npm.bbclass
 create mode 100644 meta/classes-recipe/vendor_npm_build.bbclass
 create mode 100644 meta/lib/oe/vendor/__init__.py
 create mode 100644 meta/lib/oe/vendor/cargo.py
 create mode 100644 meta/lib/oe/vendor/go.py
 create mode 100644 meta/lib/oe/vendor/npm.py
 create mode 100644 meta/lib/oeqa/selftest/cases/oelib/vendor.py
 delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc
 delete mode 100644 meta/recipes-devtools/python/python3-cryptography-crates.inc
 delete mode 100644 meta/recipes-devtools/python/python3-maturin-crates.inc
 delete mode 100644 meta/recipes-devtools/python/python3-rpds-py-crates.inc
 delete mode 100644 meta/recipes-gnome/librsvg/librsvg-crates.inc
 create mode 100644 meta/recipes-gnome/librsvg/librsvg/0001-update-url-crate-to-get-an-updated-idna-rustsec-2024.patch

-- 
2.39.5



^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH 01/30] classes: create-spdx-2.2: use expanded FetchData for downloaded packages
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 02/30] lib: spdx30_tasks: use expanded FetchData for download files Stefan Herbrechtsmeier
                   ` (29 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Use the expanded list of FetchData objects covering both the given
SRC_URLs and any additional implicit URLs that are added automatically
by the appropriate FetchMethod.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes/create-spdx-2.2.bbclass | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass
index 494bde117f..de993ff5bf 100644
--- a/meta/classes/create-spdx-2.2.bbclass
+++ b/meta/classes/create-spdx-2.2.bbclass
@@ -349,9 +349,10 @@ def add_download_packages(d, doc, recipe):
     import oe.spdx
     import oe.sbom
 
-    for download_idx, src_uri in enumerate(d.getVar('SRC_URI').split()):
-        f = bb.fetch2.FetchData(src_uri, d)
+    urls = d.getVar("SRC_URI").split()
+    fetcher = bb.fetch2.Fetch(urls, d)
 
+    for download_idx, f in enumerate(fetcher.expanded_urldata()):
         for name in f.names:
             package = oe.spdx.SPDXPackage()
             package.name = "%s-source-%d" % (d.getVar("PN"), download_idx + 1)
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 02/30] lib: spdx30_tasks: use expanded FetchData for download files
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 01/30] classes: create-spdx-2.2: use expanded FetchData for downloaded packages Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 03/30] classes: create-spdx-2.2: use name and version for download dependencies Stefan Herbrechtsmeier
                   ` (28 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Use the expanded list of FetchData objects covering both the given
SRC_URLs and any additional implicit URLs that are added automatically
by the appropriate FetchMethod.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/lib/oe/spdx30_tasks.py | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py
index 6a39246fe1..10b1b3fe14 100644
--- a/meta/lib/oe/spdx30_tasks.py
+++ b/meta/lib/oe/spdx30_tasks.py
@@ -343,9 +343,8 @@ def add_download_files(d, objset):
     urls = d.getVar("SRC_URI").split()
     fetch = bb.fetch2.Fetch(urls, d)
 
-    for download_idx, src_uri in enumerate(urls):
-        fd = fetch.ud[src_uri]
-
+    for download_idx, fd in enumerate(fetch.expanded_urldata()):
+        src_uri = fd.url
         for name in fd.names:
             file_name = os.path.basename(fetch.localpath(src_uri))
             if oe.patch.patch_path(src_uri, fetch, "", expand=False):
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 03/30] classes: create-spdx-2.2: use name and version for download dependencies
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 01/30] classes: create-spdx-2.2: use expanded FetchData for downloaded packages Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 02/30] lib: spdx30_tasks: use expanded FetchData for download files Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 04/30] lib: bb: fetch2: add support to unpack .crate files Stefan Herbrechtsmeier
                   ` (27 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Use the name and version parameter from the SRC_URI to determine the
name and version of the download dependency.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes/create-spdx-2.2.bbclass | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass
index de993ff5bf..aa195f5aa7 100644
--- a/meta/classes/create-spdx-2.2.bbclass
+++ b/meta/classes/create-spdx-2.2.bbclass
@@ -358,6 +358,15 @@ def add_download_packages(d, doc, recipe):
             package.name = "%s-source-%d" % (d.getVar("PN"), download_idx + 1)
             package.SPDXID = oe.sbom.get_download_spdxid(d, download_idx + 1)
 
+            vendor = f.parm.get("vendor")
+            if vendor:
+                package_name = f.parm.get("name")
+                if package_name:
+                    package.name = package_name
+                version = f.parm.get("version")
+                if version:
+                    package.versionInfo = version
+
             if f.type == "file":
                 continue
 
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 04/30] lib: bb: fetch2: add support to unpack .crate files
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (2 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 03/30] classes: create-spdx-2.2: use name and version for download dependencies Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 21:22   ` [OE-core] " Richard Purdie
  2025-02-11 15:00 ` [RFC PATCH 05/30] lib: oe: add vendor module Stefan Herbrechtsmeier
                   ` (26 subsequent siblings)
  30 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 bitbake/lib/bb/fetch2/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bitbake/lib/bb/fetch2/__init__.py b/bitbake/lib/bb/fetch2/__init__.py
index de36f06bfc..e4c489d059 100644
--- a/bitbake/lib/bb/fetch2/__init__.py
+++ b/bitbake/lib/bb/fetch2/__init__.py
@@ -1533,7 +1533,7 @@ class FetchMethod(object):
                 tar_cmd += ' --strip-components=%s' %  urldata.parm['striplevel']
             if file.endswith('.tar'):
                 cmd = '%s -f %s' % (tar_cmd, file)
-            elif file.endswith('.tgz') or file.endswith('.tar.gz') or file.endswith('.tar.Z'):
+            elif any(file.endswith(ext) for ext in {'.tgz', '.tar.gz', '.tar.Z', '.crate'}):
                 cmd = '%s -z -f %s' % (tar_cmd, file)
             elif file.endswith('.tbz') or file.endswith('.tbz2') or file.endswith('.tar.bz2'):
                 cmd = 'bzip2 -dc %s | %s -f -' % (file, tar_cmd)
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 05/30] lib: oe: add vendor module
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (3 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 04/30] lib: bb: fetch2: add support to unpack .crate files Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 21:31   ` [OE-core] " Richard Purdie
  2025-02-11 15:00 ` [RFC PATCH 06/30] lib: oe: vendor: add cargo support Stefan Herbrechtsmeier
                   ` (25 subsequent siblings)
  30 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add a vendor package as base for package manager specific
implementations to resolve dependencies and populate vendor directories.
Add common dump and load function for SRC_URI files.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/lib/oe/vendor/__init__.py | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 meta/lib/oe/vendor/__init__.py

diff --git a/meta/lib/oe/vendor/__init__.py b/meta/lib/oe/vendor/__init__.py
new file mode 100644
index 0000000000..d9a22a91ca
--- /dev/null
+++ b/meta/lib/oe/vendor/__init__.py
@@ -0,0 +1,28 @@
+from dataclasses import dataclass
+from typing import List
+
+class VendorError(Exception):
+    def __init__(self, message):
+        self.msg = message
+        super().__init__(message)
+
+    def __str__(self):
+        return self.msg
+
+class ResolveError(VendorError):
+    def __init__(self, message, localpath):
+        msg = "Resolve dependency failure for file: '%s'. %s" % (localpath, message)
+        self.localpath = localpath
+        super().__init__(msg)
+        self.args = (message, localpath)
+
+def dump(fp, uris):
+    for uri in uris:
+        fp.write(uri)
+        fp.write("\n")
+
+def load(fp):
+    return [line.rstrip() for line in fp]
+
+def determine_downloadfilename(type, filename):
+    return f"{type}/{filename}"
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 06/30] lib: oe: vendor: add cargo support
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (4 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 05/30] lib: oe: add vendor module Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-12 10:32   ` [OE-core] " Alexander Kanavin
  2025-02-12 12:45   ` Frédéric Martinsons
  2025-02-11 15:00 ` [RFC PATCH 07/30] lib: oe: vendor: add go support Stefan Herbrechtsmeier
                   ` (24 subsequent siblings)
  30 siblings, 2 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add a vendor module for cargo to resolve dependencies and populate
vendor directories from a Cargo.lock file.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/lib/oe/vendor/cargo.py | 121 ++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100644 meta/lib/oe/vendor/cargo.py

diff --git a/meta/lib/oe/vendor/cargo.py b/meta/lib/oe/vendor/cargo.py
new file mode 100644
index 0000000000..4d0a0034f3
--- /dev/null
+++ b/meta/lib/oe/vendor/cargo.py
@@ -0,0 +1,121 @@
+# Copyright (C) 2024-2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+import json
+import os
+import tomllib
+import bb
+import oe.vendor
+from bb.fetch2 import URI
+from . import ResolveError
+
+VENDOR_TYPE = "cargo"
+
+VENDOR_DIR = "vendor/cargo"
+
+def escape(path):
+    return re.sub(r'([A-Z])', lambda m: '!' + m.group(1).lower(), path)
+
+def determine_subdir(name, version):
+    return f"{name}-{version}"
+
+def determine_uri_path(path, name, version):
+    path = path.rstrip("/")
+    return f"{path}/api/v1/crates/{name}/{version}/download"
+
+def determine_downloadfilename(name, version):
+    filename = f"{name}-{version}.crate"
+    return oe.vendor.determine_downloadfilename(VENDOR_TYPE, filename)
+
+def extend_uri(uri, name, version, subdir, checksum_name=None,
+               checksum_value=None):
+    uri.path = determine_uri_path(uri.path, name, version)
+    params = uri.params
+    params["subdir"] = subdir
+    params["downloadfilename"] = determine_downloadfilename(name, version)
+    if checksum_name and checksum_value:
+        params[checksum_name] = checksum_value
+
+def determine_src_uri(registry, name, version, subdir):
+    uri = URI(registry)
+    extend_uri(uri, name, version, subdir)
+    return str(uri)
+
+def parse_lock_file(lock_file, function):
+    try:
+        with open(lock_file, "rb") as f:
+            crates = tomllib.load(f)
+    except Exception as e:
+        raise ResolveError(f"Invalid file: {str(e)}", lock_file)
+
+    for data in crates.get("package", []):
+        if "source" not in data:
+            continue
+
+        function(data)
+
+def resolve_src_uris(lock_file, registry, base_subdir, vendor_subdir):
+    src_uris = []
+
+    def resolve_src_uri(data):
+        name =  data.get('name')
+        version = data.get('version')
+        source = data.get("source")
+
+        if source.startswith("registry"):
+            checksum_name = "sha256sum"
+            checksum_value = data.get('checksum')
+            uri = URI(source[9:])
+            if (source[9:] == "https://github.com/rust-lang/crates.io-index"):
+                uri = URI(registry)
+                params = uri.params
+                params["name"] = name
+                params["version"] = version
+                params["type"] = VENDOR_TYPE
+                subdir = os.path.join(base_subdir, vendor_subdir)
+                extend_uri(uri, name, version, subdir, checksum_name,
+                           checksum_value)
+            else:
+                raise ResolveError(f"Unsupported cargo registry: {source}",
+                                   lock_file)
+
+        elif source.startswith("git"):
+            repository, _, revision = source.partition("#")
+            uri = URI(repository)
+            params = uri.params
+            scheme, _, protocol = uri.scheme.partition("+")
+            if protocol:
+                params["protocol"] = protocol
+                uri.scheme = scheme
+            params["nobranch"] = "1"
+            subdir = determine_subdir(name, version)
+            params["subdir"] = os.path.join(base_subdir, vendor_subdir, subdir)
+            params["rev"] = revision
+        else:
+            raise ResolveError(f"Unsupported dependency: {name}", lock_file)
+
+        src_uris.append(str(uri))
+
+    parse_lock_file(lock_file, resolve_src_uri)
+
+    return src_uris
+
+def populate_vendor(lock_file, rootdir):
+    def populate_checksum(data):
+        name =  data.get('name')
+        version = data.get('version')
+        source = data.get("source")
+        chechsum = data.get('checksum')
+
+        if source.startswith("registry"):
+            subdir = determine_subdir(name, version)
+            filepath = os.path.join(rootdir, subdir, ".cargo-checksum.json")
+            with open(filepath, "w") as f:
+                json.dump({
+                    "files": {},
+                    "package": chechsum
+                }, f)
+
+    parse_lock_file(lock_file, populate_checksum)
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 07/30] lib: oe: vendor: add go support
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (5 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 06/30] lib: oe: vendor: add cargo support Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 08/30] lib: oe: vendor: add npm support Stefan Herbrechtsmeier
                   ` (23 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add a vendor module for go to resolve dependencies from a go.sum file.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/lib/oe/vendor/go.py | 96 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 meta/lib/oe/vendor/go.py

diff --git a/meta/lib/oe/vendor/go.py b/meta/lib/oe/vendor/go.py
new file mode 100644
index 0000000000..a64d867e47
--- /dev/null
+++ b/meta/lib/oe/vendor/go.py
@@ -0,0 +1,96 @@
+# Copyright (C) 2024-2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+import base64
+import os
+import re
+import urllib.parse
+import bb
+import oe.vendor
+from bb.fetch2 import URI
+from . import ResolveError
+
+VENDOR_TYPE = "go"
+
+def escape(path):
+    return re.sub(r'([A-Z])', lambda m: '!' + m.group(1).lower(), path)
+
+def determine_subdir(module_path):
+    module_path = escape(module_path)
+    return os.path.join(module_path, "@v")
+
+def determine_uri_path(path, module_path, version, extension):
+    subdir = determine_subdir(module_path)
+    version = escape(version)
+    path = path.rstrip("/")
+    return f"{path}/{subdir}/{version}{extension}"
+
+def determine_downloadfilename(module_path, version, extension):
+    subdir = determine_subdir(module_path)
+    filename = f"{subdir}/{version}{extension}"
+    return oe.vendor.determine_downloadfilename(VENDOR_TYPE, filename)
+
+def extend_uri(uri, module_path, version, subdir, extension, checksum_name=None,
+               checksum_value=None):
+    downloadfilename = determine_downloadfilename(module_path, version,
+                                                  extension)
+    uri.path = determine_uri_path(uri.path, module_path, version, extension)
+    params = uri.params
+    params["subdir"] = subdir
+    params["downloadfilename"] = downloadfilename
+    params['unpack'] = "0"
+    if checksum_name and checksum_value:
+        params[checksum_name] = checksum_value
+
+def determine_src_uri(proxy, module_path, version, subdir):
+    uri = URI(proxy)
+    extend_uri(uri, name, version, subdir, ".zip")
+    return str(uri)
+
+def parse_lock_file(lock_file, function):
+    try:
+        with open(lock_file, "r") as f:
+            for line in f:
+                data = line.strip().split()
+                if len(data) != 3:
+                    raise ResolveError(f"Invalid line: {line}", lock_file)
+                function(data)
+    except Exception as e:
+        raise ResolveError(f"Invalid file: {str(e)}", lock_file)
+
+def resolve_src_uris(lock_file, proxy, base_subdir):
+    src_uris = []
+
+    def resolve_src_uri(data):
+        module_path, version, hash = data
+        if version.endswith("/go.mod"):
+            version = version[:-7]
+            extension = ".mod"
+        else:
+            extension = ".zip"
+        if hash.startswith("h1:"):
+            checksum_name = "goh1sum"
+            checksum_value = base64.b64decode(hash[3:]).hex()
+        else:
+            raise ResolveError(f"Invalid hash: {hash}", lock_file)
+
+        uri = URI(proxy)
+        params = uri.params
+        params["name"] = module_path
+        params["version"] = version
+        if extension == ".zip":
+            params["vendor"] = VENDOR_TYPE
+        subdir = os.path.join(base_subdir, "cache/download",
+                              determine_subdir(module_path))
+        extend_uri(uri, module_path, version, subdir, extension, checksum_name,
+                   checksum_value)
+
+        src_uri = str(uri)
+        src_uri = urllib.parse.unquote(src_uri)
+        src_uris.append(src_uri)
+
+    parse_lock_file(lock_file, resolve_src_uri)
+
+    return src_uris
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 08/30] lib: oe: vendor: add npm support
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (6 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 07/30] lib: oe: vendor: add go support Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 09/30] oeqa: oelib: add vendor tests Stefan Herbrechtsmeier
                   ` (22 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add a vendor module for npm to resolve dependencies from a
package-lock.json file.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/lib/oe/vendor/npm.py | 141 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)
 create mode 100644 meta/lib/oe/vendor/npm.py

diff --git a/meta/lib/oe/vendor/npm.py b/meta/lib/oe/vendor/npm.py
new file mode 100644
index 0000000000..6dcd756dcd
--- /dev/null
+++ b/meta/lib/oe/vendor/npm.py
@@ -0,0 +1,141 @@
+# Copyright (C) 2024-2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+import base64
+import glob
+import json
+import os
+import shutil
+import urllib.parse
+import bb
+import oe.vendor
+from bb.fetch2 import URI
+from . import ResolveError
+
+DEFAULT_REGISTRY = "https://registry.npmjs.org"
+VENDOR_TYPE = "npm"
+
+def determine_uri_path(path, name, version):
+    return f"{path.rstrip('/')}/{name}/-/{name.split('/')[-1]}-{version}.tgz"
+
+def determine_downloadfilename(name, version):
+    filename = f"{name.replace('/', '-')}-{version}.tgz"
+    return oe.vendor.determine_downloadfilename(VENDOR_TYPE, filename)
+
+def extend_uri(uri, name, version, subdir, checksum_name=None,
+               checksum_value=None):
+    params = uri.params
+    params["subdir"] = subdir
+    params["downloadfilename"] = determine_downloadfilename(name, version)
+    params["striplevel"] = "1"
+    if checksum_name and checksum_value:
+        params[checksum_name] = checksum_value
+
+def determine_src_uri(registry, name, version, subdir):
+    uri = URI(registry)
+    uri.path = determine_uri_path(uri.path, name, version)
+    extend_uri(uri, name, version, subdir)
+    return str(uri)
+
+def parse_lock_file(lock_file, function, dev, bundle):
+    try:
+        with open(lock_file, "r") as f:
+            package_lock = json.load(f)
+    except Exception as e:
+        raise ResolveError(f"Invalid file: {str(e)}", lock_file)
+
+    packages = package_lock.get("packages")
+    if not packages:
+        raise ResolveError("Invalid file format", lock_file)
+
+    for location, data in packages.items():
+        # Skip empty main and local link target packages
+        if not location.startswith('node_modules/'):
+            continue
+        elif not dev and data.get("dev", False):
+            continue
+        elif not bundle and data.get("inBundle", False):
+            continue
+        name = location.split('node_modules/')[-1]
+        function(name, data, location)
+
+def resolve_src_uris(lock_file, registry, base_subdir, dev=False):
+    src_uris = []
+
+    def resolve_src_uri(name, data, location):
+        integrity = data.get("integrity")
+        resolved = data.get("resolved")
+        name = data.get("name", name)
+        version = data.get("version")
+        link = data.get("link", False)
+
+        if integrity:
+            algorithm, value = integrity.split("-", maxsplit=1)
+            checksum_name = f"{algorithm}sum"
+            checksum_value = base64.b64decode(value).hex()
+
+        if resolved.startswith(DEFAULT_REGISTRY):
+            resolved = resolved.replace(DEFAULT_REGISTRY, registry)
+
+        subdir = os.path.join(base_subdir, location)
+
+        # Skip link sources
+        if link:
+            return
+
+        # Handle registry sources
+        elif version and integrity:
+            # Handle duplicate dependencies without url
+            if not resolved:
+                return
+
+            uri = URI(resolved)
+            params = uri.params
+            params["name"] = name
+            params["version"] = version
+            params["vendor"] = VENDOR_TYPE
+            extend_uri(uri, name, version, subdir, checksum_name,
+                       checksum_value)
+
+        # Handle http tarball sources
+        elif resolved.startswith("http") and integrity:
+            uri = URI(resolved)
+            params = uri.params
+            params["name"] = name
+            params["subdir"] = subdir
+            params["striplevel"] = "1"
+            params[checksum_name] = checksum_value
+
+        # Skip local tarball
+        elif resolved.startswith("file"):
+            return
+
+        # Handle git sources
+        elif resolved.startswith("git"):
+            resolved = resolved.replace("+ssh://git@github.com", "+https://github.com")
+            repository, _, revision = resolved.partition("#")
+            uri = URI(repository)
+            params = uri.params
+            scheme, _, protocol = uri.scheme.partition("+")
+            if protocol:
+                if protocol == "ssh" and uri.user == "git":
+                    protocol = "https"
+                    uri.user = ""
+                params["protocol"] = protocol
+                uri.scheme = scheme
+            params["nobranch"] = "1"
+            params["subdir"] = subdir
+            params["rev"] = revision
+
+        else:
+            raise ResolveError(f"Unsupported dependency: {name}", lock_file)
+
+        src_uri = str(uri)
+        src_uri = urllib.parse.unquote(src_uri)
+        src_uris.append(src_uri)
+
+    parse_lock_file(lock_file, resolve_src_uri, dev, False)
+
+    return src_uris
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 09/30] oeqa: oelib: add vendor tests
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (7 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 08/30] lib: oe: vendor: add npm support Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable Stefan Herbrechtsmeier
                   ` (21 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add tests for the vendor package

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/lib/oeqa/selftest/cases/oelib/vendor.py | 237 +++++++++++++++++++
 1 file changed, 237 insertions(+)
 create mode 100644 meta/lib/oeqa/selftest/cases/oelib/vendor.py

diff --git a/meta/lib/oeqa/selftest/cases/oelib/vendor.py b/meta/lib/oeqa/selftest/cases/oelib/vendor.py
new file mode 100644
index 0000000000..e245b25098
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/oelib/vendor.py
@@ -0,0 +1,237 @@
+#
+# Copyright OpenEmbedded Contributors
+#
+# SPDX-License-Identifier: MIT
+#
+
+import io
+import tempfile
+
+from unittest.case import TestCase
+from oe.vendor import cargo, go, npm
+
+class VendorTestCase(TestCase):
+    def setUp(self):
+        self._t = tempfile.TemporaryDirectory()
+        self.tmpdir = self._t.name
+        self.addCleanup(self._t.cleanup)
+
+class TestCargoVendor(VendorTestCase):
+    def create_cargo_lock_file(self, data):
+        import tomllib
+        filename = os.path.join(self.tmpdir, "Cargo.lock")
+        with open(filename, "w") as f:
+            for package in data.get("package", []):
+                f.write("\n[[package]]\n")
+                for key in package.keys():
+                    f.write(f'{key} = "{package[key]}"\n')
+        return filename
+
+    def test_valid(self):
+        filename = self.create_cargo_lock_file({
+            "package": [
+                {
+                    "name": "regex",
+                    "version": "1.4.0",
+                    "source": "registry+https://github.com/rust-lang/crates.io-index",
+                    "checksum": "36f45b719a674bf4b828ff318906d6c133264c793eff7a41e30074a45b5099e2"
+                }, {
+                    "name": "regex",
+                    "version": "1.5.0",
+                    "source": "git+https://github.com/rust-lang/regex.git#9f9f693768c584971a4d53bc3c586c33ed3a6831"
+                }
+            ]
+        })
+        expected_uris = [
+            "https://proxy.com/cargo/api/v1/crates/regex/1.4.0/download;"
+                "name=regex;"
+                "version=1.4.0;"
+                "type=cargo;"
+                "subdir=dummy-4.5.6/vendor;"
+                "downloadfilename=cargo/regex-1.4.0.crate;"
+                "sha256sum=36f45b719a674bf4b828ff318906d6c133264c793eff7a41e30074a45b5099e2",
+            "git://github.com/rust-lang/regex.git;"
+                "protocol=https;"
+                "nobranch=1;"
+                "subdir=dummy-4.5.6/vendor/regex-1.5.0;"
+                "rev=9f9f693768c584971a4d53bc3c586c33ed3a6831"
+        ]
+        uris = cargo.resolve_src_uris(filename, "https://proxy.com/cargo",
+                                      "dummy-4.5.6", "vendor")
+        self.assertListEqual(uris, expected_uris)
+
+#
+# Go
+#
+class TestGoVendor(VendorTestCase):
+    def create_go_sum_file(self, data):
+        filename = os.path.join(self.tmpdir, "go.sum")
+        with open(filename, 'w') as f:
+            for module_path, version, hash in data:
+                f.write(f"{module_path} {version} {hash}\n")
+        return filename
+
+    def test_resolve_src_uris(self):
+        filename = self.create_go_sum_file([
+            (
+                "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob",
+                "v1.0.0",
+                "h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY="
+            ), (
+                "gopkg.in/ini.v1",
+                "v1.67.0/go.mod",
+                "h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k="
+            )
+        ])
+        expected_src_uris = [
+            "https://proxy.com/go/github.com/!azure/azure-sdk-for-go/sdk/storage/azblob/@v/v1.0.0.zip;"
+                "name=github.com/Azure/azure-sdk-for-go/sdk/storage/azblob;"
+                "version=v1.0.0;"
+                "vendor=go;"
+                "subdir=dummy-cache/cache/download/github.com/!azure/azure-sdk-for-go/sdk/storage/azblob/@v;"
+                "downloadfilename=go/github.com/!azure/azure-sdk-for-go/sdk/storage/azblob/@v/v1.0.0.zip;"
+                "unpack=0;"
+                "goh1sum=bbf2cb00e160b0cbfb1e634be10b9f839f32faa12518eb79aafd33d665119116",
+            "https://proxy.com/go/gopkg.in/ini.v1/@v/v1.67.0.mod;"
+                "name=gopkg.in/ini.v1;"
+                "version=v1.67.0;"
+                "subdir=dummy-cache/cache/download/gopkg.in/ini.v1/@v;"
+                "downloadfilename=go/gopkg.in/ini.v1/@v/v1.67.0.mod;"
+                "unpack=0;"
+                "goh1sum=a4d2dff16522c8d12d423baee46e6f4e6d3a4c4bfdb6c220780bcaf213ab3f89"
+        ]
+        src_uris = go.resolve_src_uris(filename, "https://proxy.com/go",
+                                       "dummy-cache")
+        self.assertListEqual(src_uris, expected_src_uris)
+
+#
+# npm
+#
+class TestNpmVendor(VendorTestCase):
+    def create_package_lock_file(self, data):
+        import json
+        filename = os.path.join(self.tmpdir, "package-lock.json")
+        with open(filename, 'w') as f:
+            json.dump(data, f)
+        return filename
+
+    def test_resolve_src_uris(self):
+        filename = self.create_package_lock_file({
+            "packages": {
+                "node_modules/array-flatten": {
+                    "version": "1.1.1",
+                    "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+                    "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+                },
+                "node_modules/array-flatten/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=="
+                },
+                "node_modules/cookie": {
+                    "resolved": "git+https://github.com/jshttp/cookie.git#aec1177c7da67e3b3273df96cf476824dbc9ae09"
+                },
+                "node_modules/jsdoc-nr-template": {
+                    "version": "1.0.0",
+                    "resolved": "git+ssh://git@github.com/node-red/jsdoc-nr-template.git#3c7c8f96d585c7c5918a2e63519310e1297e162d"
+                },
+                "node_modules/accepts": {
+                    "version": "1.3.8",
+                    "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+                    "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+                    "inBundle": True
+                },
+                "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=="
+                },
+                "node_modules/example-package": {
+                    "name": "example-package",
+                    "version": "1.2.3",
+                    "resolved": "https://example.com/npm/example-package/-/example-package-1.2.3.tgz",
+                    "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="
+                },
+                "node_modules/tarball": {
+                    "name": "tarball",
+                    "resolved": "https://example.com/tarball.tgz",
+                    "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="
+                },
+                "node_modules/content-type": {
+                    "version": "1.0.4",
+                    "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+                    "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+                    "dev": True
+                },
+                "node_modules/karma": {
+                    "resolved": "",
+                    "link": True
+                },
+            }
+        })
+        expected_common_src_uris = [
+            "https://registry.com/npm/array-flatten/-/array-flatten-1.1.1.tgz;"
+                "name=array-flatten;"
+                "version=1.1.1;"
+                "vendor=npm;"
+                "subdir=dummy-4.5.6/node_modules/array-flatten;"
+                "downloadfilename=npm/array-flatten-1.1.1.tgz;"
+                "striplevel=1;"
+                "sha1sum=9a5f699051b1e7073328f2a008968b64ea2955d2",
+            "https://registry.com/npm/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz;"
+                "name=@nodelib/fs.stat;"
+                "version=2.0.5;"
+                "vendor=npm;"
+                "subdir=dummy-4.5.6/node_modules/array-flatten/node_modules/@nodelib/fs.stat;"
+                "downloadfilename=npm/@nodelib-fs.stat-2.0.5.tgz;"
+                "striplevel=1;"
+                "sha512sum=46484f3e9db3aea0c0400ff68cd867ced70f025bfae17761229edaef8e78039a2f23b06e93182decc5fbb9dc00bb7ce0d437293d4d2bcf7555d5279aaaf638f8",
+            "git://github.com/jshttp/cookie.git;"
+                "protocol=https;nobranch=1;"
+                "subdir=dummy-4.5.6/node_modules/cookie;"
+                "rev=aec1177c7da67e3b3273df96cf476824dbc9ae09",
+            "git://github.com/node-red/jsdoc-nr-template.git;"
+                "protocol=https;nobranch=1;"
+                "subdir=dummy-4.5.6/node_modules/jsdoc-nr-template;"
+                "rev=3c7c8f96d585c7c5918a2e63519310e1297e162d",
+            "https://registry.com/npm/string-width/-/string-width-4.2.3.tgz;"
+                "name=string-width;"
+                "version=4.2.3;"
+                "vendor=npm;"
+                "subdir=dummy-4.5.6/node_modules/string-width-cjs;"
+                "downloadfilename=npm/string-width-4.2.3.tgz;"
+                "striplevel=1;"
+                "sha512sum=c0ac90450a63274b08a7ad84ad265d1ac8cc256b1aa79a1136284786ee86ec954effd8c807a5327af2feb57b8eaab9e0f23fdcc4a4d6c96530bd24eb8a2673fe",
+            "https://example.com/npm/example-package/-/example-package-1.2.3.tgz;"
+                "name=example-package;"
+                "version=1.2.3;"
+                "vendor=npm;"
+                "subdir=dummy-4.5.6/node_modules/example-package;"
+                "downloadfilename=npm/example-package-1.2.3.tgz;"
+                "striplevel=1;"
+                "sha512sum=c0ac90450a63274b08a7ad84ad265d1ac8cc256b1aa79a1136284786ee86ec954effd8c807a5327af2feb57b8eaab9e0f23fdcc4a4d6c96530bd24eb8a2673fe",
+            "https://example.com/tarball.tgz;"
+                "name=tarball;"
+                "subdir=dummy-4.5.6/node_modules/tarball;"
+                "striplevel=1;"
+                "sha512sum=c0ac90450a63274b08a7ad84ad265d1ac8cc256b1aa79a1136284786ee86ec954effd8c807a5327af2feb57b8eaab9e0f23fdcc4a4d6c96530bd24eb8a2673fe"
+        ]
+        expected_dev_src_uris = [
+            "https://registry.com/npm/content-type/-/content-type-1.0.4.tgz;"
+                "name=content-type;"
+                "version=1.0.4;"
+                "vendor=npm;"
+                "subdir=dummy-4.5.6/node_modules/content-type;"
+                "downloadfilename=npm/content-type-1.0.4.tgz;"
+                "striplevel=1;"
+                "sha512sum=8483f71043ecf2d07d013d4bf8d52ab70380a6ce269366686fcf4c5973078c75a0f668a517f8f8a2c9e740b5c108114193fb6f206fed51cf663942623c184f5c"
+        ]
+        for dev in [False, True]:
+            src_uris = npm.resolve_src_uris(filename,
+                                            "https://registry.com/npm",
+                                            "dummy-4.5.6", dev)
+            expected_src_uris = expected_common_src_uris
+            if dev:
+                expected_src_uris += expected_dev_src_uris
+            self.assertListEqual(src_uris, expected_src_uris)
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (8 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 09/30] oeqa: oelib: add vendor tests Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 16:22   ` [bitbake-devel] " Peter Kjellerstedt
  2025-02-11 19:06   ` Peter Kjellerstedt
  2025-02-11 15:00 ` [RFC PATCH 11/30] classes: go: make source directory configurable Stefan Herbrechtsmeier
                   ` (20 subsequent siblings)
  30 siblings, 2 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier, bitbake-devel

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add the variable SRC_URI_FILES to collect files whichs contains
additional SRC_URI lines.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/conf/bitbake.conf | 1 +
 1 file changed, 1 insertion(+)

diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf
index 8b607088c6..ed67500ba7 100644
--- a/meta/conf/bitbake.conf
+++ b/meta/conf/bitbake.conf
@@ -745,6 +745,7 @@ AUTOREV = "${@bb.fetch2.get_autorev(d)}"
 SRCPV = ""
 
 SRC_URI = ""
+SRC_URI_FILES = ""
 
 # Use pseudo as the fakeroot implementation
 PSEUDO_LOCALSTATEDIR ?= "${WORKDIR}/pseudo/"
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 11/30] classes: go: make source directory configurable
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (9 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 12/30] classes: go-mod: make class customizable Stefan Herbrechtsmeier
                   ` (19 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

The go class assume a specific layout inside the source directory and
requires the GO_SRCURI_DESTSUFFIX as destsuffix for the fetcher. Make
the source directory configurable via GO_SRC_DIR because it is uncommon
and isn’t required for go mod. Additionally make the unpack directory
configurable via GO_INSTALL_PREFIX.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-recipe/go.bbclass | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/meta/classes-recipe/go.bbclass b/meta/classes-recipe/go.bbclass
index e3e4782025..cd6367278c 100644
--- a/meta/classes-recipe/go.bbclass
+++ b/meta/classes-recipe/go.bbclass
@@ -70,8 +70,9 @@ export CGO_CPPFLAGS ?= "${CPPFLAGS}"
 export CGO_CXXFLAGS ?= "${CXXFLAGS}"
 export CGO_LDFLAGS ?= "${LDFLAGS}"
 
-GO_INSTALL ?= "${GO_IMPORT}/..."
-GO_INSTALL_FILTEROUT ?= "${GO_IMPORT}/vendor/"
+GO_INSTALL_PREFIX ?= "${GO_IMPORT}"
+GO_INSTALL ?= "${GO_INSTALL_PREFIX}/..."
+GO_INSTALL_FILTEROUT ?= "${GO_INSTALL_PREFIX}/vendor/"
 
 B = "${WORKDIR}/build"
 export GOPATH = "${B}"
@@ -80,7 +81,8 @@ export GOPROXY ??= "https://proxy.golang.org,direct"
 export GOTMPDIR ?= "${WORKDIR}/build-tmp"
 GOTMPDIR[vardepvalue] = ""
 
-GO_SRCURI_DESTSUFFIX = "${@os.path.join(os.path.basename(d.getVar('S')), 'src', d.getVar('GO_IMPORT')) + '/'}"
+GO_SRC_DIR ??= "src/${GO_IMPORT}"
+GO_SRCURI_DESTSUFFIX ?= "${@os.path.join(os.path.basename(d.getVar('S')), d.getVar('GO_SRC_DIR')) + '/'}"
 
 go_list_packages() {
 	${GO} list -f '{{.ImportPath}}' ${GOBUILDFLAGS} ${GO_INSTALL} | \
@@ -95,7 +97,9 @@ go_list_package_tests() {
 }
 
 go_do_configure() {
-	ln -snf ${S}/src ${B}/
+	if [ -n "${GO_SRCURI_DESTSUFFIX}" ]; then
+		ln -snf ${S}/src ${B}/
+	fi
 }
 do_configure[dirs] =+ "${GOTMPDIR}"
 
@@ -114,7 +118,7 @@ do_compile[cleandirs] = "${B}/bin ${B}/pkg"
 
 go_do_install() {
 	install -d ${D}${libdir}/go/src/${GO_IMPORT}
-	tar -C ${S}/src/${GO_IMPORT} -cf - --exclude-vcs --exclude '*.test' --exclude 'testdata' . | \
+	tar -C ${S}/${GO_SRC_DIR} -cf - --exclude-vcs --exclude '*.test' --exclude 'testdata' . | \
 		tar -C ${D}${libdir}/go/src/${GO_IMPORT} --no-same-owner -xf -
 	tar -C ${B} -cf - --exclude-vcs --exclude '*.test' --exclude 'testdata' pkg | \
 		tar -C ${D}${libdir}/go --no-same-owner -xf -
@@ -127,14 +131,14 @@ go_do_install() {
 
 go_stage_testdata() {
 	oldwd="$PWD"
-	cd ${S}/src
-	find ${GO_IMPORT} -depth -type d -name testdata | while read d; do
+	cd ${S}/${GO_SRC_DIR}
+	find . -depth -type d -name testdata -printf '%P\n'| while read d; do
 		if echo "$d" | grep -q '/vendor/'; then
 			continue
 		fi
 		parent=`dirname $d`
-		install -d ${D}${PTEST_PATH}/$parent
-		cp --preserve=mode,timestamps -R $d ${D}${PTEST_PATH}/$parent/
+		install -d ${D}${PTEST_PATH}/${GO_IMPORT}/$parent
+		cp --preserve=mode,timestamps -R $d ${D}${PTEST_PATH}/${GO_IMPORT}/$parent/
 	done
 	cd "$oldwd"
 }
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 12/30] classes: go-mod: make class customizable
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (10 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 11/30] classes: go: make source directory configurable Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 13/30] classes: add nodejs-arch class Stefan Herbrechtsmeier
                   ` (18 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-recipe/go-mod.bbclass | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/meta/classes-recipe/go-mod.bbclass b/meta/classes-recipe/go-mod.bbclass
index 93ae72235f..04651ebd8a 100644
--- a/meta/classes-recipe/go-mod.bbclass
+++ b/meta/classes-recipe/go-mod.bbclass
@@ -22,13 +22,15 @@ GOBUILDFLAGS:append = " -modcacherw"
 
 inherit go
 
-export GOMODCACHE = "${S}/pkg/mod"
-GO_MOD_CACHE_DIR = "${@os.path.relpath(d.getVar('GOMODCACHE'), d.getVar('WORKDIR'))}"
+export GOMODCACHE ?= "${S}/pkg/mod"
+GO_MOD_CACHE_DIR ?= "${@os.path.relpath(d.getVar('GOMODCACHE'), d.getVar('WORKDIR'))}"
 do_unpack[cleandirs] += "${GOMODCACHE}"
 
 GO_WORKDIR ?= "${GO_IMPORT}"
-do_compile[dirs] += "${B}/src/${GO_WORKDIR}"
+GO_WORKPATH ?= "${B}/src/${GO_WORKDIR}"
+do_compile[dirs] += "${GO_WORKPATH}"
 
 # Make go install unpack the module zip files in the module cache directory
 # before the license directory is polulated with license files.
-addtask do_compile before do_populate_lic
+GO_MOD_RECRDEPTASK = "do_populate_lic"
+do_compile[recrdeptask] += "${GO_MOD_RECRDEPTASK}"
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 13/30] classes: add nodejs-arch class
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (11 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 12/30] classes: go-mod: make class customizable Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-12 10:37   ` [OE-core] " Alexander Kanavin
  2025-02-11 15:00 ` [RFC PATCH 14/30] classes: base: add get_src_uris and unpack_src_uris functions Stefan Herbrechtsmeier
                   ` (17 subsequent siblings)
  30 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-recipe/nodejs-arch.bbclass | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 meta/classes-recipe/nodejs-arch.bbclass

diff --git a/meta/classes-recipe/nodejs-arch.bbclass b/meta/classes-recipe/nodejs-arch.bbclass
new file mode 100644
index 0000000000..144eaf8409
--- /dev/null
+++ b/meta/classes-recipe/nodejs-arch.bbclass
@@ -0,0 +1,15 @@
+#
+# Copyright OpenEmbedded Contributors
+#
+# SPDX-License-Identifier: MIT
+#
+
+def map_nodejs_arch(a, d):
+    import re
+
+    if   re.match('i.86$', a): return 'ia32'
+    elif re.match('x86_64$', a): return 'x64'
+    elif re.match('aarch64$', a): return 'arm64'
+    elif re.match('(powerpc64|powerpc64le|ppc64le)$', a): return 'ppc64'
+    elif re.match('powerpc$', a): return 'ppc'
+    return a
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 14/30] classes: base: add get_src_uris and unpack_src_uris functions
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (12 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 13/30] classes: add nodejs-arch class Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 15/30] classes: add early fetch, unpack and patch support Stefan Herbrechtsmeier
                   ` (16 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add get_src_uris and unpack_src_uris functions to share code between the
early and normal tasks. The functions have an early argument to only
handle the recipe SRC_URI and doesn’t parse the SRC_URI_FILES.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-global/base.bbclass         | 47 +++++++++++++++++-------
 meta/classes/archiver.bbclass            |  4 +-
 meta/classes/buildhistory.bbclass        |  4 +-
 meta/classes/copyleft_compliance.bbclass |  2 +-
 meta/classes/create-spdx-2.2.bbclass     |  2 +-
 meta/classes/externalsrc.bbclass         |  2 +-
 6 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/meta/classes-global/base.bbclass b/meta/classes-global/base.bbclass
index 924f319999..2571dab3ba 100644
--- a/meta/classes-global/base.bbclass
+++ b/meta/classes-global/base.bbclass
@@ -139,9 +139,24 @@ do_fetch[file-checksums] = "${@bb.fetch.get_checksum_file_list(d)}"
 do_fetch[file-checksums] += " ${@get_lic_checksum_file_list(d)}"
 do_fetch[prefuncs] += "fetcher_hashes_dummyfunc"
 do_fetch[network] = "1"
-python base_do_fetch() {
 
-    src_uri = (d.getVar('SRC_URI') or "").split()
+def get_src_uris(d, early=False):
+    import oe.vendor
+
+    src_uris = (d.getVar("SRC_URI") or "").split()
+    if early:
+        return src_uris
+
+    src_uri_files = (d.getVar("SRC_URI_FILES") or "").split()
+    for fn in src_uri_files:
+        with open(fn, "r") as f:
+            u = oe.vendor.load(f)
+            src_uris.extend(u)
+
+    return src_uris
+
+def fetch_src_uris(d, early=False):
+    src_uri = get_src_uris(d, early)
     if not src_uri:
         return
 
@@ -150,11 +165,25 @@ python base_do_fetch() {
         fetcher.download()
     except bb.fetch2.BBFetchException as e:
         bb.fatal("Bitbake Fetcher Error: " + repr(e))
+
+python base_do_fetch() {
+    fetch_src_uris(d)
 }
 
 addtask unpack after do_fetch
 do_unpack[cleandirs] = "${UNPACKDIR}"
 
+def unpack_src_uris(d, unpackdir, early=False):
+    src_uri = get_src_uris(d, early)
+    if not src_uri:
+        return []
+
+    try:
+        fetcher = bb.fetch2.Fetch(src_uri, d)
+        fetcher.unpack(unpackdir)
+    except bb.fetch2.BBFetchException as e:
+        bb.fatal("Bitbake Fetcher Error: " + repr(e))
+
 python base_do_unpack() {
     import shutil
 
@@ -162,12 +191,8 @@ python base_do_unpack() {
     # Intentionally keep SOURCE_BASEDIR internal to the task just for SDE
     d.setVar("SOURCE_BASEDIR", sourcedir)
 
-    src_uri = (d.getVar('SRC_URI') or "").split()
-    if not src_uri:
-        return
-
+    unpackdir = d.getVar("UNPACKDIR")
     basedir = None
-    unpackdir = d.getVar('UNPACKDIR')
     workdir = d.getVar('WORKDIR')
     if sourcedir.startswith(workdir) and not sourcedir.startswith(unpackdir):
         basedir = sourcedir.replace(workdir, '').strip("/").split('/')[0]
@@ -175,11 +200,7 @@ python base_do_unpack() {
             bb.utils.remove(workdir + '/' + basedir, True)
             d.setVar("SOURCE_BASEDIR", workdir + '/' + basedir)
 
-    try:
-        fetcher = bb.fetch2.Fetch(src_uri, d)
-        fetcher.unpack(d.getVar('UNPACKDIR'))
-    except bb.fetch2.BBFetchException as e:
-        bb.fatal("Bitbake Fetcher Error: " + repr(e))
+    unpack_src_uris(d, unpackdir)
 
     if basedir and os.path.exists(unpackdir + '/' + basedir):
         # Compatibility magic to ensure ${WORKDIR}/git and ${WORKDIR}/${BP}
@@ -704,7 +725,7 @@ addtask cleanall after do_cleansstate
 do_cleansstate[nostamp] = "1"
 
 python do_cleanall() {
-    src_uri = (d.getVar('SRC_URI') or "").split()
+    src_uri = get_src_uris(d, True)
     if not src_uri:
         return
 
diff --git a/meta/classes/archiver.bbclass b/meta/classes/archiver.bbclass
index df271feddd..c297f6008d 100644
--- a/meta/classes/archiver.bbclass
+++ b/meta/classes/archiver.bbclass
@@ -190,7 +190,7 @@ python do_ar_original() {
 
     ar_outdir = d.getVar('ARCHIVER_OUTDIR')
     bb.note('Archiving the original source...')
-    urls = d.getVar("SRC_URI").split()
+    urls = get_src_uris(d)
     # destsuffix (git fetcher) and subdir (everything else) are allowed to be
     # absolute paths (for example, destsuffix=${S}/foobar).
     # That messes with unpacking inside our tmpdir below, because the fetchers
@@ -332,7 +332,7 @@ python do_ar_configured() {
 python do_ar_mirror() {
     import subprocess
 
-    src_uri = (d.getVar('SRC_URI') or '').split()
+    src_uri = get_src_uris(d)
     if len(src_uri) == 0:
         return
 
diff --git a/meta/classes/buildhistory.bbclass b/meta/classes/buildhistory.bbclass
index d735dd5fb5..1a6bed8a84 100644
--- a/meta/classes/buildhistory.bbclass
+++ b/meta/classes/buildhistory.bbclass
@@ -289,7 +289,7 @@ python buildhistory_emit_pkghistory() {
     rcpinfo.layer = layer
     rcpinfo.license = license
     rcpinfo.config = sortlist(oe.utils.squashspaces(d.getVar('PACKAGECONFIG') or ""))
-    rcpinfo.src_uri = oe.utils.squashspaces(d.getVar('SRC_URI') or "")
+    rcpinfo.src_uri = " ".join(get_src_uris(d))
     write_recipehistory(rcpinfo, d)
 
     bb.build.exec_func("read_subpackage_metadata", d)
@@ -933,7 +933,7 @@ def _get_srcrev_values(d):
     """
 
     scms = []
-    fetcher = bb.fetch.Fetch(d.getVar('SRC_URI').split(), d)
+    fetcher = bb.fetch.Fetch(get_src_uris(d), d)
     urldata = fetcher.ud
     for u in urldata:
         if urldata[u].method.supports_srcrev():
diff --git a/meta/classes/copyleft_compliance.bbclass b/meta/classes/copyleft_compliance.bbclass
index 9ff9956fe9..e16427e9f4 100644
--- a/meta/classes/copyleft_compliance.bbclass
+++ b/meta/classes/copyleft_compliance.bbclass
@@ -29,7 +29,7 @@ python do_prepare_copyleft_sources () {
 
     sources_dir = d.getVar('COPYLEFT_SOURCES_DIR')
     dl_dir = d.getVar('DL_DIR')
-    src_uri = d.getVar('SRC_URI').split()
+    src_uri = get_src_uris(d)
     fetch = bb.fetch2.Fetch(src_uri, d)
     ud = fetch.ud
 
diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass
index aa195f5aa7..43db4f6e3b 100644
--- a/meta/classes/create-spdx-2.2.bbclass
+++ b/meta/classes/create-spdx-2.2.bbclass
@@ -349,7 +349,7 @@ def add_download_packages(d, doc, recipe):
     import oe.spdx
     import oe.sbom
 
-    urls = d.getVar("SRC_URI").split()
+    urls = get_src_uris(d)
     fetcher = bb.fetch2.Fetch(urls, d)
 
     for download_idx, f in enumerate(fetcher.expanded_urldata()):
diff --git a/meta/classes/externalsrc.bbclass b/meta/classes/externalsrc.bbclass
index 70e27a8d35..17a0159bc0 100644
--- a/meta/classes/externalsrc.bbclass
+++ b/meta/classes/externalsrc.bbclass
@@ -65,7 +65,7 @@ python () {
 
         bb.fetch.get_hashvalue(d)
         local_srcuri = []
-        fetch = bb.fetch2.Fetch((d.getVar('SRC_URI') or '').split(), d)
+        fetch = bb.fetch2.Fetch(get_src_uris(d), d)
         for url in fetch.urls:
             url_data = fetch.ud[url]
             parm = url_data.parm
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (13 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 14/30] classes: base: add get_src_uris and unpack_src_uris functions Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 22:27   ` [OE-core] " Richard Purdie
                     ` (2 more replies)
  2025-02-11 15:00 ` [RFC PATCH 16/30] classes: add vendor class Stefan Herbrechtsmeier
                   ` (15 subsequent siblings)
  30 siblings, 3 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add support for early fetch, unpack and patches task which run before
normal patch task. This feature is useful to fetch additional
dependencies based on a patched source before the normal unpack and
patch tasks. The patch are marked as early via an early=1 parameter. An
example use case is a patch for a package manager lock file (Cargo.lock,
go.sum, package-lock.json).

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-global/patch.bbclass | 17 +++++----
 meta/classes-recipe/early.bbclass | 61 +++++++++++++++++++++++++++++++
 meta/lib/oe/patch.py              | 10 +++--
 3 files changed, 77 insertions(+), 11 deletions(-)
 create mode 100644 meta/classes-recipe/early.bbclass

diff --git a/meta/classes-global/patch.bbclass b/meta/classes-global/patch.bbclass
index e5786b1c9a..7fa94c7aa7 100644
--- a/meta/classes-global/patch.bbclass
+++ b/meta/classes-global/patch.bbclass
@@ -82,18 +82,18 @@ python patch_task_postfunc() {
             oe.patch.GitApplyTree.commitIgnored("Add changes from %s" % func, dir=srcsubdir, files=['.'], d=d)
 }
 
-def src_patches(d, all=False, expand=True):
+def src_patches(d, all=False, expand=True, early=False):
     import oe.patch
-    return oe.patch.src_patches(d, all, expand)
+    return oe.patch.src_patches(d, all, expand, early)
 
-def should_apply(parm, d):
+def should_apply(parm, d, early=False):
     """Determine if we should apply the given patch"""
     import oe.patch
-    return oe.patch.should_apply(parm, d)
+    return oe.patch.should_apply(parm, d, early)
 
 should_apply[vardepsexclude] = "DATE SRCDATE"
 
-python patch_do_patch() {
+def apply_patches(d, s, early=False):
     import oe.patch
 
     patchsetmap = {
@@ -113,8 +113,6 @@ python patch_do_patch() {
 
     classes = {}
 
-    s = d.getVar('S')
-
     os.putenv('PATH', d.getVar('PATH'))
 
     # We must use one TMPDIR per process so that the "patch" processes
@@ -124,7 +122,7 @@ python patch_do_patch() {
     process_tmpdir = tempfile.mkdtemp()
     os.environ['TMPDIR'] = process_tmpdir
 
-    for patch in src_patches(d):
+    for patch in src_patches(d, early=early):
         _, _, local, _, _, parm = bb.fetch.decodeurl(patch)
 
         if "patchdir" in parm:
@@ -159,6 +157,9 @@ python patch_do_patch() {
 
     bb.utils.remove(process_tmpdir, True)
     del os.environ['TMPDIR']
+
+python patch_do_patch() {
+    apply_patches(d, d.getVar('S'))
 }
 patch_do_patch[vardepsexclude] = "PATCHRESOLVE"
 
diff --git a/meta/classes-recipe/early.bbclass b/meta/classes-recipe/early.bbclass
new file mode 100644
index 0000000000..e458fd8f7b
--- /dev/null
+++ b/meta/classes-recipe/early.bbclass
@@ -0,0 +1,61 @@
+# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+
+EARLY_UNPACKDIR = "${WORKDIR}/sources-unpack-early"
+
+def get_early_source_dir(d, sourcedir):
+    unpackdir = d.getVar("UNPACKDIR")
+    workdir = d.getVar('WORKDIR')
+    originaldir = unpackdir if sourcedir.startswith(unpackdir) else workdir
+    early_unpackdir = d.getVar("EARLY_UNPACKDIR")
+    return sourcedir.replace(originaldir, early_unpackdir)
+
+python early_do_fetch_early() {
+    fetch_src_uris(d, True)
+}
+addtask fetch_early
+do_fetch_early[dirs] = "${DL_DIR}"
+do_fetch_early[file-checksums] = "${@bb.fetch.get_checksum_file_list(d)}"
+do_fetch[prefuncs] += "fetcher_hashes_dummyfunc"
+do_fetch_early[network] = "1"
+
+python early_do_unpack_early() {
+    unpackdir = d.getVar("EARLY_UNPACKDIR")
+    unpack_src_uris(d, unpackdir, True)
+}
+addtask unpack_early after do_fetch_early
+do_unpack_early[cleandirs] = "${EARLY_UNPACKDIR}"
+
+python early_do_patch_early() {
+    source_dir = d.getVar("S")
+    source_dir = get_early_source_dir(d, source_dir)
+    apply_patches(d, source_dir, True)
+}
+addtask patch_early after do_unpack_early
+do_patch_early[dirs] = "${WORKDIR}"
+do_patch_early[depends] = "${PATCHDEPENDENCY}"
+do_patch_early[vardepsexclude] = "PATCHRESOLVE"
+
+python () {
+    import bb.fetch
+    src_uris = get_src_uris(d, True)
+    for src_uri in src_uris:
+        uri = bb.fetch.URI(src_uri)
+        path = uri.params.get("downloadfilename", uri.path)
+
+        # HTTP/FTP use the wget fetcher
+        if uri.scheme in ("http", "https", "ftp"):
+            d.appendVarFlag('do_fetch_early', 'depends', ' wget-native:do_populate_sysroot')
+
+        # Git packages should DEPEND on git-native
+        elif uri.scheme in ("git", "gitsm"):
+            d.appendVarFlag('do_fetch_early', 'depends', ' git-native:do_populate_sysroot')
+
+        # *.xz should DEPEND on xz-native for unpacking
+        if path.endswith('.xz') or path.endswith('.txz'):
+            d.appendVarFlag('do_fetch_early', 'depends', ' xz-native:do_populate_sysroot')
+}
+
+EXPORT_FUNCTIONS do_fetch_early do_unpack_early do_patch_early
diff --git a/meta/lib/oe/patch.py b/meta/lib/oe/patch.py
index 58c6e34fe8..7737011e5a 100644
--- a/meta/lib/oe/patch.py
+++ b/meta/lib/oe/patch.py
@@ -904,7 +904,7 @@ def patch_path(url, fetch, unpackdir, expand=True):
 
     return local
 
-def src_patches(d, all=False, expand=True):
+def src_patches(d, all=False, expand=True, early=False):
     unpackdir = d.getVar('UNPACKDIR')
     fetch = bb.fetch2.Fetch([], d)
     patches = []
@@ -921,7 +921,7 @@ def src_patches(d, all=False, expand=True):
         parm = urldata.parm
         patchname = parm.get('pname') or os.path.basename(local)
 
-        apply, reason = should_apply(parm, d)
+        apply, reason = should_apply(parm, d, early)
         if not apply:
             if reason:
                 bb.note("Patch %s %s" % (patchname, reason))
@@ -950,8 +950,12 @@ def src_patches(d, all=False, expand=True):
     return patches
 
 
-def should_apply(parm, d):
+def should_apply(parm, d, early=False):
     import bb.utils
+
+    if early and not bb.utils.to_boolean(parm.get('early'), False):
+        return False, "applies to normal patch task only"
+
     if "mindate" in parm or "maxdate" in parm:
         pn = d.getVar('PN')
         srcdate = d.getVar('SRCDATE_%s' % pn)
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 16/30] classes: add vendor class
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (14 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 15/30] classes: add early fetch, unpack and patch support Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 19:17   ` [OE-core] " Peter Kjellerstedt
  2025-02-11 15:00 ` [RFC PATCH 17/30] classes: add vendor class for cargo Stefan Herbrechtsmeier
                   ` (14 subsequent siblings)
  30 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add a common vendor class with a prototype for the do_vendor_resolve
task and common dump and load SRC_URI_FILES function.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-recipe/vendor.bbclass | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 meta/classes-recipe/vendor.bbclass

diff --git a/meta/classes-recipe/vendor.bbclass b/meta/classes-recipe/vendor.bbclass
new file mode 100644
index 0000000000..a99c9a3121
--- /dev/null
+++ b/meta/classes-recipe/vendor.bbclass
@@ -0,0 +1,28 @@
+# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+
+VENDOR_DIR = "${WORKDIR}/vendor"
+
+inherit early
+
+def vendor_dump_uris(filepath, uris, d):
+    import oe.vendor
+    with open(filepath, "w") as f:
+        oe.vendor.dump(f, uris)
+
+def vendor_load_uris(filepath, d):
+    import oe.vendor
+    with open(filepath, "r") as f:
+        return oe.vendor.load(f)
+
+
+python vendor_do_vendor_resolve() {
+    vendor_dump_uris([], d)
+}
+addtask vendor_resolve after do_patch_early before do_fetch
+do_vendor_resolve[cleandirs] += "${VENDOR_DIR}"
+
+EXPORT_FUNCTIONS do_vendor_resolve
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 17/30] classes: add vendor class for cargo
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (15 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 16/30] classes: add vendor class Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 18/30] classes: add vendor class for go Stefan Herbrechtsmeier
                   ` (13 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add a vendor class for cargo to resolve the dependency SRC_URIs from a
Cargo.lock file and populate the crate vendor folder.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-recipe/vendor_cargo.bbclass | 46 ++++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 meta/classes-recipe/vendor_cargo.bbclass

diff --git a/meta/classes-recipe/vendor_cargo.bbclass b/meta/classes-recipe/vendor_cargo.bbclass
new file mode 100644
index 0000000000..495f7e01ce
--- /dev/null
+++ b/meta/classes-recipe/vendor_cargo.bbclass
@@ -0,0 +1,46 @@
+# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+
+# The name of the vendor directory
+CARGO_VENDOR_SUBDIR = "vendor"
+
+# The URL of the crate registry
+CARGO_REGISTRY ?= "https://crates.io"
+
+CARGO_SRC_PATH = "${S}/${CARGO_SRC_DIR}"
+CARGO_SRC_SUBDIR = "${@os.path.relpath(d.getVar('CARGO_SRC_PATH'), d.getVar('WORKDIR'))}"
+CARGO_SRC_URI_FILE = "${VENDOR_DIR}/cargo-source-uris.txt"
+SRC_URI_FILES:append = " ${CARGO_SRC_URI_FILE}"
+
+inherit vendor
+
+CARGO_VENDORING_DIRECTORY = "${CARGO_SRC_PATH}/${CARGO_VENDOR_SUBDIR}"
+
+python vendor_cargo_do_vendor_resolve() {
+    from oe.vendor import cargo
+
+    lock_file_dir = d.getVar("CARGO_LOCK_PATH")
+    lock_file_dir = get_early_source_dir(d, lock_file_dir)
+    registry = d.getVar("CARGO_REGISTRY")
+    src_subdir = d.getVar("CARGO_SRC_SUBDIR")
+    vendor_subdir = d.getVar("CARGO_VENDOR_SUBDIR")
+    uris = cargo.resolve_src_uris(lock_file_dir, registry, src_subdir,
+                                  vendor_subdir)
+    with open(d.getVar("CARGO_SRC_URI_FILE"), "w") as f:
+        oe.vendor.dump(f, uris)
+}
+
+python emulate_crate_vendor() {
+    from oe.vendor import cargo
+
+    lock_file_dir = d.getVar("CARGO_LOCK_PATH")
+    lock_file_dir = get_early_source_dir(d, lock_file_dir)
+    vendor_dir = d.getVar("CARGO_VENDORING_DIRECTORY")
+    cargo.populate_vendor(lock_file_dir, vendor_dir)
+}
+do_unpack[postfuncs] += "emulate_crate_vendor"
+
+EXPORT_FUNCTIONS do_vendor_resolve
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 18/30] classes: add vendor class for go
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (16 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 17/30] classes: add vendor class for cargo Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 22:59   ` [OE-core] " Bruce Ashfield
  2025-02-11 15:00 ` [RFC PATCH 19/30] classes: add vendor class for npm Stefan Herbrechtsmeier
                   ` (12 subsequent siblings)
  30 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add a vendor class for go to resolve the dependency SRC_URIs from a
go.sum file and run populate the go mod vendor folder.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-recipe/vendor_go.bbclass | 59 +++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 meta/classes-recipe/vendor_go.bbclass

diff --git a/meta/classes-recipe/vendor_go.bbclass b/meta/classes-recipe/vendor_go.bbclass
new file mode 100644
index 0000000000..dc5f8d1d8d
--- /dev/null
+++ b/meta/classes-recipe/vendor_go.bbclass
@@ -0,0 +1,59 @@
+# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+
+# The directory of the go.mod file relative to the root directory, per default
+# assume there's a file directly in the root directory
+GO_SRC_DIR ?= ""
+
+# The path to the go.mod file
+GO_MANIFEST_DIR ?= "${GO_SRC_PATH}/go.mod"
+
+# The path to go.sum file
+GO_LOCK_DIR ?= "${@os.path.join(os.path.dirname(d.getVar('GO_MANIFEST_DIR')), 'go.sum')}"
+
+# The URL of the go proxy
+GO_PROXY ?= "https://proxy.golang.org"
+
+GO_SRC_PATH = "${S}/${GO_SRC_DIR}"
+GO_SRC_SUBDIR = "${@os.path.relpath(d.getVar('CARGO_SRC_PATH'), d.getVar('WORKDIR'))}"
+GO_SRC_URI_FILE = "${VENDOR_DIR}/go-source-uris.txt"
+SRC_URI_FILES:append = " ${GO_SRC_URI_FILE}"
+
+inherit go-mod vendor
+
+GO_INSTALL_PREFIX = "."
+GO_SRC_PATH = "${S}"
+GO_SRCURI_DESTSUFFIX = ""
+
+GOMODCACHE = "invalid"
+GO_MOD_CACHE_DIR = "go/pkg/mod"
+GO_WORKPATH = "${GO_SRC_PATH}"
+GO_MOD_RECRDEPTASK = ""
+
+GOBUILDFLAGS:append = " -mod=vendor"
+
+python vendor_go_do_vendor_resolve() {
+    import oe.vendor
+    import oe.vendor.go
+
+    lock_file_dir = d.getVar("GO_LOCK_DIR")
+    lock_file_subdir = get_early_source_dir(d, lock_file_dir)
+    proxy = d.getVar("GO_PROXY")
+    cache_subdir = d.getVar("GO_MOD_CACHE_DIR")
+    src_uris = oe.vendor.go.resolve_src_uris(lock_file_subdir, proxy, cache_subdir)
+    with open(d.getVar("GO_SRC_URI_FILE"), "w") as f:
+        oe.vendor.dump(f, src_uris)
+}
+
+run_go_mod_vendor() {
+    cd ${GO_SRC_PATH}
+    export GOMODCACHE="${UNPACKDIR}/${GO_MOD_CACHE_DIR}"
+    ${GO} mod vendor
+}
+do_unpack[postfuncs] += "run_go_mod_vendor"
+do_unpack[depends] += "${@oe.utils.build_depends_string(d.getVar('DEPENDS_GOLANG'), 'do_populate_sysroot')}"
+
+EXPORT_FUNCTIONS do_vendor_resolve
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 19/30] classes: add vendor class for npm
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (17 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 18/30] classes: add vendor class for go Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 20/30] classes: add vendor_npm_build class Stefan Herbrechtsmeier
                   ` (11 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add a vendor class for npm to resolve the dependency SRC_URIs from a
package-lock.json file and populate the npm node_modules folder. The
class replaces the normal npm class and provide a simplified compile and
install task.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-recipe/vendor_npm.bbclass | 115 +++++++++++++++++++++++++
 1 file changed, 115 insertions(+)
 create mode 100644 meta/classes-recipe/vendor_npm.bbclass

diff --git a/meta/classes-recipe/vendor_npm.bbclass b/meta/classes-recipe/vendor_npm.bbclass
new file mode 100644
index 0000000000..c8bb2b6403
--- /dev/null
+++ b/meta/classes-recipe/vendor_npm.bbclass
@@ -0,0 +1,115 @@
+# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+
+# The directory of the package.json file relative to the root directory, per
+# default assume there's a file directly in the root directory
+NPM_SRC_DIR ?= ""
+
+# The path to the package.json file
+NPM_MANIFEST_FILE ?= "${NPM_SRC_PATH}/package.json"
+
+# The path to package-lock.json file
+NPM_LOCK_FILE ?= "${@os.path.join(os.path.dirname(d.getVar('NPM_MANIFEST_FILE')), 'package-lock.json')}"
+
+# The URL of the npm registry
+NPM_REGISTRY ?= "https://registry.npmjs.org"
+
+# The option to npm install development dependencies
+NPM_INSTALL_DEV ?= "0"
+
+# The option to npm prune development dependencies after install
+NPM_PRUNE_DEV ?= "${@['0', '1'][oe.types.boolean(d.getVar('NPM_INSTALL_DEV'))]}"
+
+# The nodejs architecture of the target
+NPM_ARCH ?= "${@map_nodejs_arch(d.getVar("TARGET_ARCH"), d)}"
+
+inherit nodejs-arch python3native vendor
+
+DEPENDS:append = "nodejs-native"
+RDEPENDS:${PN}:append:class-target = "${@['', ' nodejs'][bb.data.inherits_class('allarch', d)]}"
+
+NPM_SRC_PATH = "${S}/${NPM_SRC_DIR}"
+NPM_SRC_SUBDIR = "${@os.path.relpath(d.getVar('NPM_SRC_PATH'), d.getVar('WORKDIR'))}"
+NPM_SRC_URI_FILE = "${VENDOR_DIR}/npm-source-uris.txt"
+SRC_URI_FILES:append = " ${NPM_SRC_URI_FILE}"
+
+NPM = "npm"
+NPM_CACHE = "${WORKDIR}/cache/npm"
+NPM_COMMON_FLAGS = "\
+    --offline \
+    --fund=false \
+    --audit=false \
+    --cache=${NPM_CACHE} \
+    --loglevel=silly \
+    --foreground-scripts \
+    --release \
+    --nodedir='${RECIPE_SYSROOT_NATIVE}${prefix_native}' \
+    --python=${PYTHON} \
+    --build-from-source \
+"
+NPM_BUILD_FLAGS = "\
+    ${NPM_COMMON_FLAGS} \
+    --arch=${NPM_TARGET_ARCH} \
+    --target_arch=${NPM_TARGET_ARCH} \
+"
+
+export NPM_CONFIG_USERCONFIG = "/dev/null"
+export NPM_CONFIG_GLOBALCONFIG = "null"
+
+def npm_src_uri(d, name=None, version=None, registry=None, subdir=None):
+    import oe.vendor.npm
+    if not name:
+        name = d.getVar("PN")
+    if not version:
+        version = d.getVar("PV")
+    if not registry:
+        registry = d.getVar("NPM_REGISTRY")
+    if not subdir:
+        subdir = os.path.basename(d.getVar("S"))
+    return oe.vendor.npm.determine_src_uri(registry, name, version, subdir)
+
+python vendor_npm_do_vendor_resolve() {
+    import oe.vendor
+    import oe.vendor.npm
+
+    lock_file_dir = d.getVar("NPM_LOCK_FILE")
+    lock_file_dir = get_early_source_dir(d, lock_file_dir)
+    registry = d.getVar("NPM_REGISTRY")
+    src_subdir = d.getVar("NPM_SRC_SUBDIR")
+    dev = oe.types.boolean(d.getVar("NPM_INSTALL_DEV"))
+    src_uris = oe.vendor.npm.resolve_src_uris(lock_file_dir, registry,
+                                              src_subdir, dev)
+    with open(d.getVar("NPM_SRC_URI_FILE"), "w") as f:
+        oe.vendor.dump(f, src_uris)
+}
+
+oe_run_npm() {
+    bbnote ${NPM} "$@"
+    ${NPM} "$@"
+}
+
+vendor_npm_do_compile() {
+    oe_run_npm rebuild ${NPM_BUILD_FLAGS}
+}
+do_compile[cleandirs] += "${NPM_CACHE}"
+
+vendor_npm_do_install() {
+    oe_run_npm install --global --prefix=${D}${exec_prefix}
+    rm ${D}${exec_prefix}/lib/node_modules/${BPN}
+    install -d ${D}${exec_prefix}/lib/node_modules/${BPN}
+    tar -C . -cf - --exclude-vcs . | \
+        tar -C ${D}${exec_prefix}/lib/node_modules/${BPN} --no-same-owner -xf -
+    rm -rf ${D}${exec_prefix}/lib/node_modules/${BPN}/node_modules/.bin
+    if "${@['false', 'true'][oe.types.boolean(d.getVar('NPM_PRUNE_DEV'))]}"; then
+        (cd ${D}${exec_prefix}/lib/node_modules; oe_run_npm prune --omit=dev)
+    fi
+}
+
+FILES:${PN} += " \
+    ${nonarch_libdir}/node_modules/${BPN} \
+"
+
+EXPORT_FUNCTIONS do_vendor_resolve do_compile do_install
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 20/30] classes: add vendor_npm_build class
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (18 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 19/30] classes: add vendor class for npm Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class Stefan Herbrechtsmeier
                   ` (10 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Add a vendor class for npm to build a npm package from source.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes-recipe/vendor_npm_build.bbclass | 50 ++++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 meta/classes-recipe/vendor_npm_build.bbclass

diff --git a/meta/classes-recipe/vendor_npm_build.bbclass b/meta/classes-recipe/vendor_npm_build.bbclass
new file mode 100644
index 0000000000..1cef316e01
--- /dev/null
+++ b/meta/classes-recipe/vendor_npm_build.bbclass
@@ -0,0 +1,50 @@
+# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+
+NPM_BUILD_TARGET ?= "build"
+EXTRA_OENPM_BUILD ?= ""
+NPM_REBUILD ?= "1"
+
+inherit vendor_npm
+
+NPM_INSTALL_DEV = "1"
+NPM_PRUNE_DEV = "1"
+
+NPM_NATIVE_ARCH ?= "${@map_nodejs_arch(d.getVar("BUILD_ARCH"), d)}"
+
+NPM_BUILD_NATIVE_FLAGS = "\
+    ${NPM_COMMON_FLAGS} \
+    --arch=${NPM_NATIVE_ARCH} \
+    --target_arch=${NPM_NATIVE_ARCH} \
+"
+
+NPM_BUILD_NATIVE_ENVS = "\
+    CC="${BUILD_CC}" \
+    CXX="${BUILD_CXX}" \
+    LINK="${BUILD_CC}" \
+    AR="${BUILD_AR}" \
+    CPPFLAGS="${BUILD_CPPFLAGS}" \
+    CFLAGS="${BUILD_CFLAGS}" \
+    CXXFLAGS="${BUILD_CXXFLAGS}" \
+    LDFLAGS="${BUILD_LDFLAGS}" \
+"
+
+oe_run_npm_native() {
+    bbnote "${NPM_BUILD_NATIVE_ENVS} ${NPM} $@"
+    ${NPM_BUILD_NATIVE_ENVS} ${NPM} "$@"
+}
+
+vendor_npm_build_do_compile() {
+    oe_run_npm_native rebuild ${NPM_BUILD_NATIVE_FLAGS}
+
+    oe_run_npm_native run ${NPM_BUILD_TARGET} ${NPM_BUILD_NATIVE_FLAGS} ${EXTRA_OENPM_BUILD}
+
+    if "${@['false', 'true'][oe.types.boolean(d.getVar('NPM_REBUILD'))]}"; then
+        vendor_npm_do_compile
+    fi
+}
+
+EXPORT_FUNCTIONS do_compile
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (19 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 20/30] classes: add vendor_npm_build class Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 21:46   ` [OE-core] " Richard Purdie
  2025-02-11 15:00 ` [RFC PATCH 22/30] python3-cryptography: " Stefan Herbrechtsmeier
                   ` (9 subsequent siblings)
  30 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 .../python/python3-bcrypt-crates.inc          | 84 -------------------
 .../python/python3-bcrypt_4.2.1.bb            |  4 +-
 2 files changed, 1 insertion(+), 87 deletions(-)
 delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc

diff --git a/meta/recipes-devtools/python/python3-bcrypt-crates.inc b/meta/recipes-devtools/python/python3-bcrypt-crates.inc
deleted file mode 100644
index 576abcd7cb..0000000000
--- a/meta/recipes-devtools/python/python3-bcrypt-crates.inc
+++ /dev/null
@@ -1,84 +0,0 @@
-# Autogenerated with 'bitbake -c update_crates python3-bcrypt'
-
-# from src/_bcrypt/Cargo.lock
-SRC_URI += " \
-    crate://crates.io/autocfg/1.4.0 \
-    crate://crates.io/base64/0.22.1 \
-    crate://crates.io/bcrypt/0.16.0 \
-    crate://crates.io/bcrypt-pbkdf/0.10.0 \
-    crate://crates.io/block-buffer/0.10.4 \
-    crate://crates.io/blowfish/0.9.1 \
-    crate://crates.io/byteorder/1.5.0 \
-    crate://crates.io/cfg-if/1.0.0 \
-    crate://crates.io/cipher/0.4.4 \
-    crate://crates.io/cpufeatures/0.2.15 \
-    crate://crates.io/crypto-common/0.1.6 \
-    crate://crates.io/digest/0.10.7 \
-    crate://crates.io/generic-array/0.14.7 \
-    crate://crates.io/getrandom/0.2.15 \
-    crate://crates.io/heck/0.5.0 \
-    crate://crates.io/indoc/2.0.5 \
-    crate://crates.io/inout/0.1.3 \
-    crate://crates.io/libc/0.2.164 \
-    crate://crates.io/memoffset/0.9.1 \
-    crate://crates.io/once_cell/1.20.2 \
-    crate://crates.io/pbkdf2/0.12.2 \
-    crate://crates.io/portable-atomic/1.9.0 \
-    crate://crates.io/proc-macro2/1.0.89 \
-    crate://crates.io/pyo3/0.23.1 \
-    crate://crates.io/pyo3-build-config/0.23.1 \
-    crate://crates.io/pyo3-ffi/0.23.1 \
-    crate://crates.io/pyo3-macros/0.23.1 \
-    crate://crates.io/pyo3-macros-backend/0.23.1 \
-    crate://crates.io/quote/1.0.37 \
-    crate://crates.io/sha2/0.10.8 \
-    crate://crates.io/subtle/2.6.1 \
-    crate://crates.io/syn/2.0.87 \
-    crate://crates.io/target-lexicon/0.12.16 \
-    crate://crates.io/typenum/1.17.0 \
-    crate://crates.io/unicode-ident/1.0.13 \
-    crate://crates.io/unindent/0.2.3 \
-    crate://crates.io/version_check/0.9.5 \
-    crate://crates.io/wasi/0.11.0+wasi-snapshot-preview1 \
-    crate://crates.io/zeroize/1.8.1 \
-"
-
-SRC_URI[autocfg-1.4.0.sha256sum] = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
-SRC_URI[base64-0.22.1.sha256sum] = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
-SRC_URI[bcrypt-0.16.0.sha256sum] = "2b1866ecef4f2d06a0bb77880015fdf2b89e25a1c2e5addacb87e459c86dc67e"
-SRC_URI[bcrypt-pbkdf-0.10.0.sha256sum] = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2"
-SRC_URI[block-buffer-0.10.4.sha256sum] = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
-SRC_URI[blowfish-0.9.1.sha256sum] = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
-SRC_URI[byteorder-1.5.0.sha256sum] = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
-SRC_URI[cfg-if-1.0.0.sha256sum] = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-SRC_URI[cipher-0.4.4.sha256sum] = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
-SRC_URI[cpufeatures-0.2.15.sha256sum] = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6"
-SRC_URI[crypto-common-0.1.6.sha256sum] = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
-SRC_URI[digest-0.10.7.sha256sum] = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
-SRC_URI[generic-array-0.14.7.sha256sum] = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-SRC_URI[getrandom-0.2.15.sha256sum] = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
-SRC_URI[heck-0.5.0.sha256sum] = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-SRC_URI[indoc-2.0.5.sha256sum] = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
-SRC_URI[inout-0.1.3.sha256sum] = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
-SRC_URI[libc-0.2.164.sha256sum] = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
-SRC_URI[memoffset-0.9.1.sha256sum] = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
-SRC_URI[once_cell-1.20.2.sha256sum] = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
-SRC_URI[pbkdf2-0.12.2.sha256sum] = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
-SRC_URI[portable-atomic-1.9.0.sha256sum] = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
-SRC_URI[proc-macro2-1.0.89.sha256sum] = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
-SRC_URI[pyo3-0.23.1.sha256sum] = "7ebb0c0cc0de9678e53be9ccf8a2ab53045e6e3a8be03393ceccc5e7396ccb40"
-SRC_URI[pyo3-build-config-0.23.1.sha256sum] = "80e3ce69c4ec34476534b490e412b871ba03a82e35604c3dfb95fcb6bfb60c09"
-SRC_URI[pyo3-ffi-0.23.1.sha256sum] = "3b09f311c76b36dfd6dd6f7fa6f9f18e7e46a1c937110d283e80b12ba2468a75"
-SRC_URI[pyo3-macros-0.23.1.sha256sum] = "fd4f74086536d1e1deaff99ec0387481fb3325c82e4e48be0e75ab3d3fcb487a"
-SRC_URI[pyo3-macros-backend-0.23.1.sha256sum] = "9e77dfeb76b32bbf069144a5ea0a36176ab59c8db9ce28732d0f06f096bbfbc8"
-SRC_URI[quote-1.0.37.sha256sum] = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
-SRC_URI[sha2-0.10.8.sha256sum] = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
-SRC_URI[subtle-2.6.1.sha256sum] = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
-SRC_URI[syn-2.0.87.sha256sum] = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
-SRC_URI[target-lexicon-0.12.16.sha256sum] = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
-SRC_URI[typenum-1.17.0.sha256sum] = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
-SRC_URI[unicode-ident-1.0.13.sha256sum] = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
-SRC_URI[unindent-0.2.3.sha256sum] = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
-SRC_URI[version_check-0.9.5.sha256sum] = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
-SRC_URI[wasi-0.11.0+wasi-snapshot-preview1.sha256sum] = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-SRC_URI[zeroize-1.8.1.sha256sum] = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
diff --git a/meta/recipes-devtools/python/python3-bcrypt_4.2.1.bb b/meta/recipes-devtools/python/python3-bcrypt_4.2.1.bb
index 004e8ce8b1..9117637744 100644
--- a/meta/recipes-devtools/python/python3-bcrypt_4.2.1.bb
+++ b/meta/recipes-devtools/python/python3-bcrypt_4.2.1.bb
@@ -8,12 +8,10 @@ LDFLAGS += "${@bb.utils.contains('DISTRO_FEATURES', 'ptest', '-fuse-ld=bfd', '',
 
 SRC_URI[sha256sum] = "6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe"
 
-inherit pypi python_setuptools3_rust cargo-update-recipe-crates ptest-python-pytest
+inherit pypi python_setuptools3_rust ptest-python-pytest vendor_cargo
 
 CARGO_SRC_DIR = "src/_bcrypt"
 
-require ${BPN}-crates.inc
-
 RDEPENDS:${PN}:class-target += "\
     python3-cffi \
     python3-ctypes \
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 22/30] python3-cryptography: mirgrate to vendor cargo class
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (20 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 23/30] python3-maturin: " Stefan Herbrechtsmeier
                   ` (8 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 .../python/python3-cryptography-crates.inc    | 76 -------------------
 .../python/python3-cryptography.bb            |  4 +-
 2 files changed, 1 insertion(+), 79 deletions(-)
 delete mode 100644 meta/recipes-devtools/python/python3-cryptography-crates.inc

diff --git a/meta/recipes-devtools/python/python3-cryptography-crates.inc b/meta/recipes-devtools/python/python3-cryptography-crates.inc
deleted file mode 100644
index 18f346aed4..0000000000
--- a/meta/recipes-devtools/python/python3-cryptography-crates.inc
+++ /dev/null
@@ -1,76 +0,0 @@
-# Autogenerated with 'bitbake -c update_crates python3-cryptography'
-
-# from Cargo.lock
-SRC_URI += " \
-    crate://crates.io/asn1/0.20.0 \
-    crate://crates.io/asn1_derive/0.20.0 \
-    crate://crates.io/autocfg/1.4.0 \
-    crate://crates.io/base64/0.22.1 \
-    crate://crates.io/bitflags/2.6.0 \
-    crate://crates.io/cc/1.2.1 \
-    crate://crates.io/cfg-if/1.0.0 \
-    crate://crates.io/foreign-types/0.3.2 \
-    crate://crates.io/foreign-types-shared/0.1.1 \
-    crate://crates.io/heck/0.5.0 \
-    crate://crates.io/indoc/2.0.5 \
-    crate://crates.io/itoa/1.0.14 \
-    crate://crates.io/libc/0.2.166 \
-    crate://crates.io/memoffset/0.9.1 \
-    crate://crates.io/once_cell/1.20.2 \
-    crate://crates.io/openssl/0.10.68 \
-    crate://crates.io/openssl-macros/0.1.1 \
-    crate://crates.io/openssl-sys/0.9.104 \
-    crate://crates.io/pem/3.0.4 \
-    crate://crates.io/pkg-config/0.3.31 \
-    crate://crates.io/portable-atomic/1.10.0 \
-    crate://crates.io/proc-macro2/1.0.92 \
-    crate://crates.io/pyo3/0.23.2 \
-    crate://crates.io/pyo3-build-config/0.23.2 \
-    crate://crates.io/pyo3-ffi/0.23.2 \
-    crate://crates.io/pyo3-macros/0.23.2 \
-    crate://crates.io/pyo3-macros-backend/0.23.2 \
-    crate://crates.io/quote/1.0.37 \
-    crate://crates.io/self_cell/1.0.4 \
-    crate://crates.io/shlex/1.3.0 \
-    crate://crates.io/syn/2.0.89 \
-    crate://crates.io/target-lexicon/0.12.16 \
-    crate://crates.io/unicode-ident/1.0.14 \
-    crate://crates.io/unindent/0.2.3 \
-    crate://crates.io/vcpkg/0.2.15 \
-"
-
-SRC_URI[asn1-0.20.0.sha256sum] = "2d8b84b4ea1de2bf1dcd2a759737ddb328fb6695b2a95eb7e44fed67e3406f32"
-SRC_URI[asn1_derive-0.20.0.sha256sum] = "a200809d0138620b3dba989f1d08d0620e76248bc1e62a2ec1b2df5eb1ee08ad"
-SRC_URI[autocfg-1.4.0.sha256sum] = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
-SRC_URI[base64-0.22.1.sha256sum] = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
-SRC_URI[bitflags-2.6.0.sha256sum] = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
-SRC_URI[cc-1.2.1.sha256sum] = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
-SRC_URI[cfg-if-1.0.0.sha256sum] = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-SRC_URI[foreign-types-0.3.2.sha256sum] = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
-SRC_URI[foreign-types-shared-0.1.1.sha256sum] = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
-SRC_URI[heck-0.5.0.sha256sum] = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-SRC_URI[indoc-2.0.5.sha256sum] = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
-SRC_URI[itoa-1.0.14.sha256sum] = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
-SRC_URI[libc-0.2.166.sha256sum] = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36"
-SRC_URI[memoffset-0.9.1.sha256sum] = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
-SRC_URI[once_cell-1.20.2.sha256sum] = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
-SRC_URI[openssl-0.10.68.sha256sum] = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
-SRC_URI[openssl-macros-0.1.1.sha256sum] = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
-SRC_URI[openssl-sys-0.9.104.sha256sum] = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
-SRC_URI[pem-3.0.4.sha256sum] = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae"
-SRC_URI[pkg-config-0.3.31.sha256sum] = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
-SRC_URI[portable-atomic-1.10.0.sha256sum] = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
-SRC_URI[proc-macro2-1.0.92.sha256sum] = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
-SRC_URI[pyo3-0.23.2.sha256sum] = "f54b3d09cbdd1f8c20650b28e7b09e338881482f4aa908a5f61a00c98fba2690"
-SRC_URI[pyo3-build-config-0.23.2.sha256sum] = "3015cf985888fe66cfb63ce0e321c603706cd541b7aec7ddd35c281390af45d8"
-SRC_URI[pyo3-ffi-0.23.2.sha256sum] = "6fca7cd8fd809b5ac4eefb89c1f98f7a7651d3739dfb341ca6980090f554c270"
-SRC_URI[pyo3-macros-0.23.2.sha256sum] = "34e657fa5379a79151b6ff5328d9216a84f55dc93b17b08e7c3609a969b73aa0"
-SRC_URI[pyo3-macros-backend-0.23.2.sha256sum] = "295548d5ffd95fd1981d2d3cf4458831b21d60af046b729b6fd143b0ba7aee2f"
-SRC_URI[quote-1.0.37.sha256sum] = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
-SRC_URI[self_cell-1.0.4.sha256sum] = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a"
-SRC_URI[shlex-1.3.0.sha256sum] = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-SRC_URI[syn-2.0.89.sha256sum] = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
-SRC_URI[target-lexicon-0.12.16.sha256sum] = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
-SRC_URI[unicode-ident-1.0.14.sha256sum] = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
-SRC_URI[unindent-0.2.3.sha256sum] = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
-SRC_URI[vcpkg-0.2.15.sha256sum] = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
diff --git a/meta/recipes-devtools/python/python3-cryptography.bb b/meta/recipes-devtools/python/python3-cryptography.bb
index 69329ec954..8b69f13ff0 100644
--- a/meta/recipes-devtools/python/python3-cryptography.bb
+++ b/meta/recipes-devtools/python/python3-cryptography.bb
@@ -18,9 +18,7 @@ SRC_URI += "file://0001-pyproject.toml-remove-benchmark-disable-option.patch \
             file://run-ptest \
            "
 
-require ${BPN}-crates.inc
-
-inherit pypi python_maturin cargo-update-recipe-crates pkgconfig
+inherit pypi python_maturin pkgconfig vendor_cargo
 
 DEPENDS += " \
     python3-cffi-native \
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 23/30] python3-maturin: mirgrate to vendor cargo class
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (21 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 22/30] python3-cryptography: " Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 24/30] python3-rpds-py: " Stefan Herbrechtsmeier
                   ` (7 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 .../python/python3-maturin-crates.inc         | 712 ------------------
 .../python/python3-maturin_1.8.1.bb           |   4 +-
 2 files changed, 1 insertion(+), 715 deletions(-)
 delete mode 100644 meta/recipes-devtools/python/python3-maturin-crates.inc

diff --git a/meta/recipes-devtools/python/python3-maturin-crates.inc b/meta/recipes-devtools/python/python3-maturin-crates.inc
deleted file mode 100644
index abb8fe4a62..0000000000
--- a/meta/recipes-devtools/python/python3-maturin-crates.inc
+++ /dev/null
@@ -1,712 +0,0 @@
-# Autogenerated with 'bitbake -c update_crates python3-maturin'
-
-# from Cargo.lock
-SRC_URI += " \
-    crate://crates.io/adler2/2.0.0 \
-    crate://crates.io/ahash/0.8.11 \
-    crate://crates.io/aho-corasick/1.1.3 \
-    crate://crates.io/allocator-api2/0.2.18 \
-    crate://crates.io/anstream/0.6.14 \
-    crate://crates.io/anstyle/1.0.7 \
-    crate://crates.io/anstyle-parse/0.2.4 \
-    crate://crates.io/anstyle-query/1.1.0 \
-    crate://crates.io/anstyle-wincon/3.0.3 \
-    crate://crates.io/anyhow/1.0.89 \
-    crate://crates.io/arbitrary/1.4.1 \
-    crate://crates.io/autocfg/1.3.0 \
-    crate://crates.io/automod/1.0.14 \
-    crate://crates.io/base64/0.21.7 \
-    crate://crates.io/base64/0.22.1 \
-    crate://crates.io/bitflags/1.3.2 \
-    crate://crates.io/bitflags/2.5.0 \
-    crate://crates.io/block-buffer/0.10.4 \
-    crate://crates.io/bstr/1.10.0 \
-    crate://crates.io/bumpalo/3.16.0 \
-    crate://crates.io/byteorder/1.5.0 \
-    crate://crates.io/bytes/1.7.1 \
-    crate://crates.io/bytesize/1.3.0 \
-    crate://crates.io/bzip2/0.4.4 \
-    crate://crates.io/bzip2-sys/0.1.11+1.0.8 \
-    crate://crates.io/cab/0.6.0 \
-    crate://crates.io/camino/1.1.9 \
-    crate://crates.io/cargo-config2/0.1.30 \
-    crate://crates.io/cargo-options/0.7.4 \
-    crate://crates.io/cargo-platform/0.1.8 \
-    crate://crates.io/cargo-xwin/0.18.3 \
-    crate://crates.io/cargo-zigbuild/0.19.7 \
-    crate://crates.io/cargo_metadata/0.19.0 \
-    crate://crates.io/cbindgen/0.27.0 \
-    crate://crates.io/cc/1.1.21 \
-    crate://crates.io/cfb/0.10.0 \
-    crate://crates.io/cfg-if/1.0.0 \
-    crate://crates.io/charset/0.1.5 \
-    crate://crates.io/chumsky/0.9.3 \
-    crate://crates.io/clap/4.5.7 \
-    crate://crates.io/clap_builder/4.5.7 \
-    crate://crates.io/clap_complete/4.5.5 \
-    crate://crates.io/clap_complete_command/0.6.1 \
-    crate://crates.io/clap_complete_nushell/4.5.2 \
-    crate://crates.io/clap_derive/4.5.5 \
-    crate://crates.io/clap_lex/0.7.1 \
-    crate://crates.io/cli-table/0.4.7 \
-    crate://crates.io/colorchoice/1.0.1 \
-    crate://crates.io/configparser/3.1.0 \
-    crate://crates.io/console/0.15.8 \
-    crate://crates.io/content_inspector/0.2.4 \
-    crate://crates.io/core-foundation/0.9.4 \
-    crate://crates.io/core-foundation-sys/0.8.6 \
-    crate://crates.io/cpufeatures/0.2.12 \
-    crate://crates.io/crc/3.2.1 \
-    crate://crates.io/crc-catalog/2.4.0 \
-    crate://crates.io/crc32fast/1.4.2 \
-    crate://crates.io/crossbeam-channel/0.5.13 \
-    crate://crates.io/crossbeam-deque/0.8.5 \
-    crate://crates.io/crossbeam-epoch/0.9.18 \
-    crate://crates.io/crossbeam-utils/0.8.20 \
-    crate://crates.io/crypto-common/0.1.6 \
-    crate://crates.io/data-encoding/2.6.0 \
-    crate://crates.io/deranged/0.3.11 \
-    crate://crates.io/derivative/2.2.0 \
-    crate://crates.io/derive_arbitrary/1.4.1 \
-    crate://crates.io/dialoguer/0.11.0 \
-    crate://crates.io/diff/0.1.13 \
-    crate://crates.io/digest/0.10.7 \
-    crate://crates.io/dirs/5.0.1 \
-    crate://crates.io/dirs-sys/0.4.1 \
-    crate://crates.io/displaydoc/0.2.5 \
-    crate://crates.io/dissimilar/1.0.9 \
-    crate://crates.io/dunce/1.0.5 \
-    crate://crates.io/dyn-clone/1.0.17 \
-    crate://crates.io/either/1.13.0 \
-    crate://crates.io/encode_unicode/0.3.6 \
-    crate://crates.io/encoding_rs/0.8.34 \
-    crate://crates.io/equivalent/1.0.1 \
-    crate://crates.io/errno/0.3.9 \
-    crate://crates.io/expect-test/1.5.0 \
-    crate://crates.io/fastrand/2.1.0 \
-    crate://crates.io/fat-macho/0.4.9 \
-    crate://crates.io/filetime/0.2.23 \
-    crate://crates.io/flate2/1.0.33 \
-    crate://crates.io/fnv/1.0.7 \
-    crate://crates.io/foreign-types/0.3.2 \
-    crate://crates.io/foreign-types-shared/0.1.1 \
-    crate://crates.io/form_urlencoded/1.2.1 \
-    crate://crates.io/fs-err/3.0.0 \
-    crate://crates.io/fs4/0.12.0 \
-    crate://crates.io/futures/0.3.30 \
-    crate://crates.io/futures-channel/0.3.31 \
-    crate://crates.io/futures-core/0.3.31 \
-    crate://crates.io/futures-executor/0.3.30 \
-    crate://crates.io/futures-io/0.3.31 \
-    crate://crates.io/futures-macro/0.3.31 \
-    crate://crates.io/futures-sink/0.3.31 \
-    crate://crates.io/futures-task/0.3.31 \
-    crate://crates.io/futures-timer/3.0.3 \
-    crate://crates.io/futures-util/0.3.31 \
-    crate://crates.io/generic-array/0.14.7 \
-    crate://crates.io/getrandom/0.2.15 \
-    crate://crates.io/glob/0.3.1 \
-    crate://crates.io/globset/0.4.15 \
-    crate://crates.io/goblin/0.9.2 \
-    crate://crates.io/hashbrown/0.14.5 \
-    crate://crates.io/heck/0.4.1 \
-    crate://crates.io/heck/0.5.0 \
-    crate://crates.io/home/0.5.9 \
-    crate://crates.io/humantime/2.1.0 \
-    crate://crates.io/humantime-serde/1.1.1 \
-    crate://crates.io/icu_collections/1.5.0 \
-    crate://crates.io/icu_locid/1.5.0 \
-    crate://crates.io/icu_locid_transform/1.5.0 \
-    crate://crates.io/icu_locid_transform_data/1.5.0 \
-    crate://crates.io/icu_normalizer/1.5.0 \
-    crate://crates.io/icu_normalizer_data/1.5.0 \
-    crate://crates.io/icu_properties/1.5.1 \
-    crate://crates.io/icu_properties_data/1.5.0 \
-    crate://crates.io/icu_provider/1.5.0 \
-    crate://crates.io/icu_provider_macros/1.5.0 \
-    crate://crates.io/idna/1.0.3 \
-    crate://crates.io/idna_adapter/1.2.0 \
-    crate://crates.io/ignore/0.4.23 \
-    crate://crates.io/indexmap/2.5.0 \
-    crate://crates.io/indicatif/0.17.8 \
-    crate://crates.io/indoc/2.0.5 \
-    crate://crates.io/instant/0.1.13 \
-    crate://crates.io/is_terminal_polyfill/1.70.0 \
-    crate://crates.io/itertools/0.12.1 \
-    crate://crates.io/itoa/1.0.11 \
-    crate://crates.io/keyring/2.3.3 \
-    crate://crates.io/lazy_static/1.4.0 \
-    crate://crates.io/lddtree/0.3.7 \
-    crate://crates.io/libc/0.2.158 \
-    crate://crates.io/libmimalloc-sys/0.1.38 \
-    crate://crates.io/libredox/0.1.3 \
-    crate://crates.io/linux-keyutils/0.2.4 \
-    crate://crates.io/linux-raw-sys/0.4.14 \
-    crate://crates.io/litemap/0.7.3 \
-    crate://crates.io/lock_api/0.4.12 \
-    crate://crates.io/lockfree-object-pool/0.1.6 \
-    crate://crates.io/log/0.4.21 \
-    crate://crates.io/lzma-sys/0.1.20 \
-    crate://crates.io/lzxd/0.2.5 \
-    crate://crates.io/mailparse/0.15.0 \
-    crate://crates.io/matchers/0.1.0 \
-    crate://crates.io/memchr/2.7.2 \
-    crate://crates.io/mimalloc/0.1.42 \
-    crate://crates.io/mime/0.3.17 \
-    crate://crates.io/mime_guess/2.0.4 \
-    crate://crates.io/minijinja/2.5.0 \
-    crate://crates.io/minimal-lexical/0.2.1 \
-    crate://crates.io/miniz_oxide/0.8.0 \
-    crate://crates.io/msi/0.8.0 \
-    crate://crates.io/multipart/0.18.0 \
-    crate://crates.io/native-tls/0.2.12 \
-    crate://crates.io/nom/7.1.3 \
-    crate://crates.io/normalize-line-endings/0.3.0 \
-    crate://crates.io/normpath/1.2.0 \
-    crate://crates.io/nu-ansi-term/0.46.0 \
-    crate://crates.io/num-conv/0.1.0 \
-    crate://crates.io/number_prefix/0.4.0 \
-    crate://crates.io/once_cell/1.19.0 \
-    crate://crates.io/openssl/0.10.66 \
-    crate://crates.io/openssl-macros/0.1.1 \
-    crate://crates.io/openssl-probe/0.1.5 \
-    crate://crates.io/openssl-sys/0.9.103 \
-    crate://crates.io/option-ext/0.2.0 \
-    crate://crates.io/os_pipe/1.2.0 \
-    crate://crates.io/overload/0.1.1 \
-    crate://crates.io/parking_lot/0.12.3 \
-    crate://crates.io/parking_lot_core/0.9.10 \
-    crate://crates.io/paste/1.0.15 \
-    crate://crates.io/path-slash/0.2.1 \
-    crate://crates.io/pep440_rs/0.6.6 \
-    crate://crates.io/pep508_rs/0.6.1 \
-    crate://crates.io/percent-encoding/2.3.1 \
-    crate://crates.io/pin-project-lite/0.2.14 \
-    crate://crates.io/pin-utils/0.1.0 \
-    crate://crates.io/pkg-config/0.3.30 \
-    crate://crates.io/plain/0.2.3 \
-    crate://crates.io/platform-info/2.0.3 \
-    crate://crates.io/portable-atomic/1.6.0 \
-    crate://crates.io/powerfmt/0.2.0 \
-    crate://crates.io/ppv-lite86/0.2.17 \
-    crate://crates.io/pretty_assertions/1.4.1 \
-    crate://crates.io/proc-macro-crate/3.1.0 \
-    crate://crates.io/proc-macro2/1.0.85 \
-    crate://crates.io/psm/0.1.21 \
-    crate://crates.io/pyproject-toml/0.11.0 \
-    crate://crates.io/python-pkginfo/0.6.5 \
-    crate://crates.io/quote/1.0.36 \
-    crate://crates.io/quoted_printable/0.5.0 \
-    crate://crates.io/rand/0.8.5 \
-    crate://crates.io/rand_chacha/0.3.1 \
-    crate://crates.io/rand_core/0.6.4 \
-    crate://crates.io/rayon/1.10.0 \
-    crate://crates.io/rayon-core/1.12.1 \
-    crate://crates.io/redox_syscall/0.4.1 \
-    crate://crates.io/redox_syscall/0.5.1 \
-    crate://crates.io/redox_users/0.4.5 \
-    crate://crates.io/regex/1.10.6 \
-    crate://crates.io/regex-automata/0.1.10 \
-    crate://crates.io/regex-automata/0.4.7 \
-    crate://crates.io/regex-syntax/0.6.29 \
-    crate://crates.io/regex-syntax/0.8.4 \
-    crate://crates.io/relative-path/1.9.3 \
-    crate://crates.io/rfc2047-decoder/1.0.6 \
-    crate://crates.io/ring/0.17.8 \
-    crate://crates.io/rstest/0.22.0 \
-    crate://crates.io/rstest_macros/0.22.0 \
-    crate://crates.io/rustc_version/0.4.1 \
-    crate://crates.io/rustflags/0.1.6 \
-    crate://crates.io/rustix/0.38.34 \
-    crate://crates.io/rustls/0.23.19 \
-    crate://crates.io/rustls-pemfile/2.1.3 \
-    crate://crates.io/rustls-pki-types/1.10.0 \
-    crate://crates.io/rustls-webpki/0.102.8 \
-    crate://crates.io/rustversion/1.0.17 \
-    crate://crates.io/ryu/1.0.18 \
-    crate://crates.io/same-file/1.0.6 \
-    crate://crates.io/schannel/0.1.23 \
-    crate://crates.io/schemars/0.8.21 \
-    crate://crates.io/schemars_derive/0.8.21 \
-    crate://crates.io/scopeguard/1.2.0 \
-    crate://crates.io/scroll/0.12.0 \
-    crate://crates.io/scroll_derive/0.12.0 \
-    crate://crates.io/security-framework/2.11.0 \
-    crate://crates.io/security-framework-sys/2.11.0 \
-    crate://crates.io/semver/1.0.23 \
-    crate://crates.io/serde/1.0.216 \
-    crate://crates.io/serde_derive/1.0.216 \
-    crate://crates.io/serde_derive_internals/0.29.1 \
-    crate://crates.io/serde_json/1.0.133 \
-    crate://crates.io/serde_spanned/0.6.6 \
-    crate://crates.io/sha2/0.10.8 \
-    crate://crates.io/sharded-slab/0.1.7 \
-    crate://crates.io/shell-words/1.1.0 \
-    crate://crates.io/shlex/1.3.0 \
-    crate://crates.io/simd-adler32/0.3.7 \
-    crate://crates.io/similar/2.5.0 \
-    crate://crates.io/slab/0.4.9 \
-    crate://crates.io/smallvec/1.13.2 \
-    crate://crates.io/smawk/0.3.2 \
-    crate://crates.io/snapbox/0.6.16 \
-    crate://crates.io/snapbox-macros/0.3.10 \
-    crate://crates.io/socks/0.3.4 \
-    crate://crates.io/spin/0.9.8 \
-    crate://crates.io/stable_deref_trait/1.2.0 \
-    crate://crates.io/stacker/0.1.15 \
-    crate://crates.io/static_assertions/1.1.0 \
-    crate://crates.io/strsim/0.11.1 \
-    crate://crates.io/subtle/2.5.0 \
-    crate://crates.io/syn/1.0.109 \
-    crate://crates.io/syn/2.0.87 \
-    crate://crates.io/synstructure/0.13.1 \
-    crate://crates.io/tar/0.4.43 \
-    crate://crates.io/target-lexicon/0.13.0 \
-    crate://crates.io/tempfile/3.11.0 \
-    crate://crates.io/termcolor/1.4.1 \
-    crate://crates.io/terminal_size/0.3.0 \
-    crate://crates.io/textwrap/0.16.1 \
-    crate://crates.io/thiserror/1.0.64 \
-    crate://crates.io/thiserror/2.0.3 \
-    crate://crates.io/thiserror-impl/1.0.64 \
-    crate://crates.io/thiserror-impl/2.0.3 \
-    crate://crates.io/thread_local/1.1.8 \
-    crate://crates.io/time/0.3.36 \
-    crate://crates.io/time-core/0.1.2 \
-    crate://crates.io/time-macros/0.2.18 \
-    crate://crates.io/tinystr/0.7.6 \
-    crate://crates.io/toml/0.8.15 \
-    crate://crates.io/toml_datetime/0.6.6 \
-    crate://crates.io/toml_edit/0.21.1 \
-    crate://crates.io/toml_edit/0.22.16 \
-    crate://crates.io/tracing/0.1.40 \
-    crate://crates.io/tracing-attributes/0.1.27 \
-    crate://crates.io/tracing-core/0.1.32 \
-    crate://crates.io/tracing-log/0.2.0 \
-    crate://crates.io/tracing-serde/0.1.3 \
-    crate://crates.io/tracing-subscriber/0.3.18 \
-    crate://crates.io/trycmd/0.15.6 \
-    crate://crates.io/twox-hash/1.6.3 \
-    crate://crates.io/typenum/1.17.0 \
-    crate://crates.io/unicase/2.7.0 \
-    crate://crates.io/unicode-ident/1.0.12 \
-    crate://crates.io/unicode-linebreak/0.1.5 \
-    crate://crates.io/unicode-width/0.1.13 \
-    crate://crates.io/unicode-xid/0.2.6 \
-    crate://crates.io/unscanny/0.1.0 \
-    crate://crates.io/untrusted/0.9.0 \
-    crate://crates.io/ureq/2.11.0 \
-    crate://crates.io/url/2.5.4 \
-    crate://crates.io/urlencoding/2.1.3 \
-    crate://crates.io/utf16_iter/1.0.5 \
-    crate://crates.io/utf8_iter/1.0.4 \
-    crate://crates.io/utf8parse/0.2.2 \
-    crate://crates.io/uuid/1.8.0 \
-    crate://crates.io/valuable/0.1.0 \
-    crate://crates.io/vcpkg/0.2.15 \
-    crate://crates.io/version_check/0.9.4 \
-    crate://crates.io/versions/6.2.0 \
-    crate://crates.io/wait-timeout/0.2.0 \
-    crate://crates.io/walkdir/2.5.0 \
-    crate://crates.io/wasi/0.11.0+wasi-snapshot-preview1 \
-    crate://crates.io/webpki-roots/0.26.2 \
-    crate://crates.io/which/7.0.0 \
-    crate://crates.io/wild/2.2.1 \
-    crate://crates.io/winapi/0.3.9 \
-    crate://crates.io/winapi-i686-pc-windows-gnu/0.4.0 \
-    crate://crates.io/winapi-util/0.1.8 \
-    crate://crates.io/winapi-x86_64-pc-windows-gnu/0.4.0 \
-    crate://crates.io/windows-sys/0.48.0 \
-    crate://crates.io/windows-sys/0.52.0 \
-    crate://crates.io/windows-targets/0.48.5 \
-    crate://crates.io/windows-targets/0.52.6 \
-    crate://crates.io/windows_aarch64_gnullvm/0.48.5 \
-    crate://crates.io/windows_aarch64_gnullvm/0.52.6 \
-    crate://crates.io/windows_aarch64_msvc/0.48.5 \
-    crate://crates.io/windows_aarch64_msvc/0.52.6 \
-    crate://crates.io/windows_i686_gnu/0.48.5 \
-    crate://crates.io/windows_i686_gnu/0.52.6 \
-    crate://crates.io/windows_i686_gnullvm/0.52.6 \
-    crate://crates.io/windows_i686_msvc/0.48.5 \
-    crate://crates.io/windows_i686_msvc/0.52.6 \
-    crate://crates.io/windows_x86_64_gnu/0.48.5 \
-    crate://crates.io/windows_x86_64_gnu/0.52.6 \
-    crate://crates.io/windows_x86_64_gnullvm/0.48.5 \
-    crate://crates.io/windows_x86_64_gnullvm/0.52.6 \
-    crate://crates.io/windows_x86_64_msvc/0.48.5 \
-    crate://crates.io/windows_x86_64_msvc/0.52.6 \
-    crate://crates.io/winnow/0.5.40 \
-    crate://crates.io/winnow/0.6.13 \
-    crate://crates.io/winsafe/0.0.19 \
-    crate://crates.io/write16/1.0.0 \
-    crate://crates.io/writeable/0.5.5 \
-    crate://crates.io/xattr/1.3.1 \
-    crate://crates.io/xwin/0.6.5 \
-    crate://crates.io/xz2/0.1.7 \
-    crate://crates.io/yansi/1.0.1 \
-    crate://crates.io/yoke/0.7.4 \
-    crate://crates.io/yoke-derive/0.7.5 \
-    crate://crates.io/zerocopy/0.7.34 \
-    crate://crates.io/zerocopy-derive/0.7.34 \
-    crate://crates.io/zerofrom/0.1.4 \
-    crate://crates.io/zerofrom-derive/0.1.5 \
-    crate://crates.io/zeroize/1.8.1 \
-    crate://crates.io/zerovec/0.10.4 \
-    crate://crates.io/zerovec-derive/0.10.3 \
-    crate://crates.io/zip/2.1.6 \
-    crate://crates.io/zopfli/0.8.1 \
-"
-
-SRC_URI[adler2-2.0.0.sha256sum] = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
-SRC_URI[ahash-0.8.11.sha256sum] = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
-SRC_URI[aho-corasick-1.1.3.sha256sum] = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-SRC_URI[allocator-api2-0.2.18.sha256sum] = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
-SRC_URI[anstream-0.6.14.sha256sum] = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
-SRC_URI[anstyle-1.0.7.sha256sum] = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
-SRC_URI[anstyle-parse-0.2.4.sha256sum] = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
-SRC_URI[anstyle-query-1.1.0.sha256sum] = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
-SRC_URI[anstyle-wincon-3.0.3.sha256sum] = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
-SRC_URI[anyhow-1.0.89.sha256sum] = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
-SRC_URI[arbitrary-1.4.1.sha256sum] = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
-SRC_URI[autocfg-1.3.0.sha256sum] = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
-SRC_URI[automod-1.0.14.sha256sum] = "edf3ee19dbc0a46d740f6f0926bde8c50f02bdbc7b536842da28f6ac56513a8b"
-SRC_URI[base64-0.21.7.sha256sum] = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
-SRC_URI[base64-0.22.1.sha256sum] = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
-SRC_URI[bitflags-1.3.2.sha256sum] = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-SRC_URI[bitflags-2.5.0.sha256sum] = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
-SRC_URI[block-buffer-0.10.4.sha256sum] = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
-SRC_URI[bstr-1.10.0.sha256sum] = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
-SRC_URI[bumpalo-3.16.0.sha256sum] = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
-SRC_URI[byteorder-1.5.0.sha256sum] = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
-SRC_URI[bytes-1.7.1.sha256sum] = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
-SRC_URI[bytesize-1.3.0.sha256sum] = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc"
-SRC_URI[bzip2-0.4.4.sha256sum] = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
-SRC_URI[bzip2-sys-0.1.11+1.0.8.sha256sum] = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
-SRC_URI[cab-0.6.0.sha256sum] = "171228650e6721d5acc0868a462cd864f49ac5f64e4a42cde270406e64e404d2"
-SRC_URI[camino-1.1.9.sha256sum] = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
-SRC_URI[cargo-config2-0.1.30.sha256sum] = "163a7be36509388c7bf7eb492a05431df28a2ee519087e287566c11e40d35e33"
-SRC_URI[cargo-options-0.7.4.sha256sum] = "f3540247c0a37a76eb324acc238dc617786ea22c43b95da560c82a8f2714321f"
-SRC_URI[cargo-platform-0.1.8.sha256sum] = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
-SRC_URI[cargo-xwin-0.18.3.sha256sum] = "76ddeb44d5109bca38ed11f0400b0385b5ba3fc03e737d188d9b86d784daeb49"
-SRC_URI[cargo-zigbuild-0.19.7.sha256sum] = "04cc649328f39bbf1ef92ef753406e1785ff1074941c398e5214b6c74d318a9e"
-SRC_URI[cargo_metadata-0.19.0.sha256sum] = "afc309ed89476c8957c50fb818f56fe894db857866c3e163335faa91dc34eb85"
-SRC_URI[cbindgen-0.27.0.sha256sum] = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb"
-SRC_URI[cc-1.1.21.sha256sum] = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
-SRC_URI[cfb-0.10.0.sha256sum] = "d8a4f8e55be323b378facfcf1f06aa97f6ec17cf4ac84fb17325093aaf62da41"
-SRC_URI[cfg-if-1.0.0.sha256sum] = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-SRC_URI[charset-0.1.5.sha256sum] = "f1f927b07c74ba84c7e5fe4db2baeb3e996ab2688992e39ac68ce3220a677c7e"
-SRC_URI[chumsky-0.9.3.sha256sum] = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9"
-SRC_URI[clap-4.5.7.sha256sum] = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
-SRC_URI[clap_builder-4.5.7.sha256sum] = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
-SRC_URI[clap_complete-4.5.5.sha256sum] = "d2020fa13af48afc65a9a87335bda648309ab3d154cd03c7ff95b378c7ed39c4"
-SRC_URI[clap_complete_command-0.6.1.sha256sum] = "da8e198c052315686d36371e8a3c5778b7852fc75cc313e4e11eeb7a644a1b62"
-SRC_URI[clap_complete_nushell-4.5.2.sha256sum] = "1accf1b463dee0d3ab2be72591dccdab8bef314958340447c882c4c72acfe2a3"
-SRC_URI[clap_derive-4.5.5.sha256sum] = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
-SRC_URI[clap_lex-0.7.1.sha256sum] = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
-SRC_URI[cli-table-0.4.7.sha256sum] = "adfbb116d9e2c4be7011360d0c0bee565712c11e969c9609b25b619366dc379d"
-SRC_URI[colorchoice-1.0.1.sha256sum] = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
-SRC_URI[configparser-3.1.0.sha256sum] = "e57e3272f0190c3f1584272d613719ba5fc7df7f4942fe542e63d949cf3a649b"
-SRC_URI[console-0.15.8.sha256sum] = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
-SRC_URI[content_inspector-0.2.4.sha256sum] = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38"
-SRC_URI[core-foundation-0.9.4.sha256sum] = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-SRC_URI[core-foundation-sys-0.8.6.sha256sum] = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
-SRC_URI[cpufeatures-0.2.12.sha256sum] = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
-SRC_URI[crc-3.2.1.sha256sum] = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
-SRC_URI[crc-catalog-2.4.0.sha256sum] = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
-SRC_URI[crc32fast-1.4.2.sha256sum] = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
-SRC_URI[crossbeam-channel-0.5.13.sha256sum] = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
-SRC_URI[crossbeam-deque-0.8.5.sha256sum] = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
-SRC_URI[crossbeam-epoch-0.9.18.sha256sum] = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
-SRC_URI[crossbeam-utils-0.8.20.sha256sum] = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
-SRC_URI[crypto-common-0.1.6.sha256sum] = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
-SRC_URI[data-encoding-2.6.0.sha256sum] = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
-SRC_URI[deranged-0.3.11.sha256sum] = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
-SRC_URI[derivative-2.2.0.sha256sum] = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
-SRC_URI[derive_arbitrary-1.4.1.sha256sum] = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
-SRC_URI[dialoguer-0.11.0.sha256sum] = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de"
-SRC_URI[diff-0.1.13.sha256sum] = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
-SRC_URI[digest-0.10.7.sha256sum] = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
-SRC_URI[dirs-5.0.1.sha256sum] = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
-SRC_URI[dirs-sys-0.4.1.sha256sum] = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
-SRC_URI[displaydoc-0.2.5.sha256sum] = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
-SRC_URI[dissimilar-1.0.9.sha256sum] = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
-SRC_URI[dunce-1.0.5.sha256sum] = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
-SRC_URI[dyn-clone-1.0.17.sha256sum] = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
-SRC_URI[either-1.13.0.sha256sum] = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
-SRC_URI[encode_unicode-0.3.6.sha256sum] = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
-SRC_URI[encoding_rs-0.8.34.sha256sum] = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
-SRC_URI[equivalent-1.0.1.sha256sum] = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
-SRC_URI[errno-0.3.9.sha256sum] = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
-SRC_URI[expect-test-1.5.0.sha256sum] = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0"
-SRC_URI[fastrand-2.1.0.sha256sum] = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
-SRC_URI[fat-macho-0.4.9.sha256sum] = "4c9c45caa6c6edfaee4cb3bd84ea9686e115df7f0efb530e15fb466eccb0b345"
-SRC_URI[filetime-0.2.23.sha256sum] = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
-SRC_URI[flate2-1.0.33.sha256sum] = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
-SRC_URI[fnv-1.0.7.sha256sum] = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-SRC_URI[foreign-types-0.3.2.sha256sum] = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
-SRC_URI[foreign-types-shared-0.1.1.sha256sum] = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
-SRC_URI[form_urlencoded-1.2.1.sha256sum] = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
-SRC_URI[fs-err-3.0.0.sha256sum] = "8bb60e7409f34ef959985bc9d9c5ee8f5db24ee46ed9775850548021710f807f"
-SRC_URI[fs4-0.12.0.sha256sum] = "c29c30684418547d476f0b48e84f4821639119c483b1eccd566c8cd0cd05f521"
-SRC_URI[futures-0.3.30.sha256sum] = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
-SRC_URI[futures-channel-0.3.31.sha256sum] = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
-SRC_URI[futures-core-0.3.31.sha256sum] = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
-SRC_URI[futures-executor-0.3.30.sha256sum] = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
-SRC_URI[futures-io-0.3.31.sha256sum] = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
-SRC_URI[futures-macro-0.3.31.sha256sum] = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
-SRC_URI[futures-sink-0.3.31.sha256sum] = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
-SRC_URI[futures-task-0.3.31.sha256sum] = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
-SRC_URI[futures-timer-3.0.3.sha256sum] = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
-SRC_URI[futures-util-0.3.31.sha256sum] = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
-SRC_URI[generic-array-0.14.7.sha256sum] = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-SRC_URI[getrandom-0.2.15.sha256sum] = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
-SRC_URI[glob-0.3.1.sha256sum] = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
-SRC_URI[globset-0.4.15.sha256sum] = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
-SRC_URI[goblin-0.9.2.sha256sum] = "53ab3f32d1d77146981dea5d6b1e8fe31eedcb7013e5e00d6ccd1259a4b4d923"
-SRC_URI[hashbrown-0.14.5.sha256sum] = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
-SRC_URI[heck-0.4.1.sha256sum] = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-SRC_URI[heck-0.5.0.sha256sum] = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-SRC_URI[home-0.5.9.sha256sum] = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
-SRC_URI[humantime-2.1.0.sha256sum] = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-SRC_URI[humantime-serde-1.1.1.sha256sum] = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c"
-SRC_URI[icu_collections-1.5.0.sha256sum] = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
-SRC_URI[icu_locid-1.5.0.sha256sum] = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
-SRC_URI[icu_locid_transform-1.5.0.sha256sum] = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
-SRC_URI[icu_locid_transform_data-1.5.0.sha256sum] = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
-SRC_URI[icu_normalizer-1.5.0.sha256sum] = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
-SRC_URI[icu_normalizer_data-1.5.0.sha256sum] = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
-SRC_URI[icu_properties-1.5.1.sha256sum] = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
-SRC_URI[icu_properties_data-1.5.0.sha256sum] = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
-SRC_URI[icu_provider-1.5.0.sha256sum] = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
-SRC_URI[icu_provider_macros-1.5.0.sha256sum] = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
-SRC_URI[idna-1.0.3.sha256sum] = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
-SRC_URI[idna_adapter-1.2.0.sha256sum] = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
-SRC_URI[ignore-0.4.23.sha256sum] = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
-SRC_URI[indexmap-2.5.0.sha256sum] = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
-SRC_URI[indicatif-0.17.8.sha256sum] = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3"
-SRC_URI[indoc-2.0.5.sha256sum] = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
-SRC_URI[instant-0.1.13.sha256sum] = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
-SRC_URI[is_terminal_polyfill-1.70.0.sha256sum] = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
-SRC_URI[itertools-0.12.1.sha256sum] = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
-SRC_URI[itoa-1.0.11.sha256sum] = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
-SRC_URI[keyring-2.3.3.sha256sum] = "363387f0019d714aa60cc30ab4fe501a747f4c08fc58f069dd14be971bd495a0"
-SRC_URI[lazy_static-1.4.0.sha256sum] = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-SRC_URI[lddtree-0.3.7.sha256sum] = "e0779ac94bd7b6ab781fa12388dbf79ac45ec1fa433e7d25521753be8227b08e"
-SRC_URI[libc-0.2.158.sha256sum] = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
-SRC_URI[libmimalloc-sys-0.1.38.sha256sum] = "0e7bb23d733dfcc8af652a78b7bf232f0e967710d044732185e561e47c0336b6"
-SRC_URI[libredox-0.1.3.sha256sum] = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
-SRC_URI[linux-keyutils-0.2.4.sha256sum] = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e"
-SRC_URI[linux-raw-sys-0.4.14.sha256sum] = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
-SRC_URI[litemap-0.7.3.sha256sum] = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704"
-SRC_URI[lock_api-0.4.12.sha256sum] = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
-SRC_URI[lockfree-object-pool-0.1.6.sha256sum] = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
-SRC_URI[log-0.4.21.sha256sum] = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
-SRC_URI[lzma-sys-0.1.20.sha256sum] = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
-SRC_URI[lzxd-0.2.5.sha256sum] = "5de7336a183103429ad66d11d56d8bdc9c4a2916f6b85a8f11e5b127bde12001"
-SRC_URI[mailparse-0.15.0.sha256sum] = "3da03d5980411a724e8aaf7b61a7b5e386ec55a7fb49ee3d0ff79efc7e5e7c7e"
-SRC_URI[matchers-0.1.0.sha256sum] = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
-SRC_URI[memchr-2.7.2.sha256sum] = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
-SRC_URI[mimalloc-0.1.42.sha256sum] = "e9186d86b79b52f4a77af65604b51225e8db1d6ee7e3f41aec1e40829c71a176"
-SRC_URI[mime-0.3.17.sha256sum] = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
-SRC_URI[mime_guess-2.0.4.sha256sum] = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
-SRC_URI[minijinja-2.5.0.sha256sum] = "2c37e1b517d1dcd0e51dc36c4567b9d5a29262b3ec8da6cb5d35e27a8fb529b5"
-SRC_URI[minimal-lexical-0.2.1.sha256sum] = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-SRC_URI[miniz_oxide-0.8.0.sha256sum] = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
-SRC_URI[msi-0.8.0.sha256sum] = "4a2332f87a064dea9cce571408c879e0da8dc193b3af06a2b3b2604ee4182a32"
-SRC_URI[multipart-0.18.0.sha256sum] = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182"
-SRC_URI[native-tls-0.2.12.sha256sum] = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
-SRC_URI[nom-7.1.3.sha256sum] = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-SRC_URI[normalize-line-endings-0.3.0.sha256sum] = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
-SRC_URI[normpath-1.2.0.sha256sum] = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804"
-SRC_URI[nu-ansi-term-0.46.0.sha256sum] = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
-SRC_URI[num-conv-0.1.0.sha256sum] = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
-SRC_URI[number_prefix-0.4.0.sha256sum] = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
-SRC_URI[once_cell-1.19.0.sha256sum] = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-SRC_URI[openssl-0.10.66.sha256sum] = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
-SRC_URI[openssl-macros-0.1.1.sha256sum] = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
-SRC_URI[openssl-probe-0.1.5.sha256sum] = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
-SRC_URI[openssl-sys-0.9.103.sha256sum] = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
-SRC_URI[option-ext-0.2.0.sha256sum] = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
-SRC_URI[os_pipe-1.2.0.sha256sum] = "29d73ba8daf8fac13b0501d1abeddcfe21ba7401ada61a819144b6c2a4f32209"
-SRC_URI[overload-0.1.1.sha256sum] = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
-SRC_URI[parking_lot-0.12.3.sha256sum] = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
-SRC_URI[parking_lot_core-0.9.10.sha256sum] = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
-SRC_URI[paste-1.0.15.sha256sum] = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
-SRC_URI[path-slash-0.2.1.sha256sum] = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42"
-SRC_URI[pep440_rs-0.6.6.sha256sum] = "466eada3179c2e069ca897b99006cbb33f816290eaeec62464eea907e22ae385"
-SRC_URI[pep508_rs-0.6.1.sha256sum] = "3f8877489a99ccc80012333123e434f84e645fe1ede3b30e9d3b815887a12979"
-SRC_URI[percent-encoding-2.3.1.sha256sum] = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
-SRC_URI[pin-project-lite-0.2.14.sha256sum] = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
-SRC_URI[pin-utils-0.1.0.sha256sum] = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
-SRC_URI[pkg-config-0.3.30.sha256sum] = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
-SRC_URI[plain-0.2.3.sha256sum] = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
-SRC_URI[platform-info-2.0.3.sha256sum] = "d5ff316b9c4642feda973c18f0decd6c8b0919d4722566f6e4337cce0dd88217"
-SRC_URI[portable-atomic-1.6.0.sha256sum] = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
-SRC_URI[powerfmt-0.2.0.sha256sum] = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-SRC_URI[ppv-lite86-0.2.17.sha256sum] = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-SRC_URI[pretty_assertions-1.4.1.sha256sum] = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
-SRC_URI[proc-macro-crate-3.1.0.sha256sum] = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
-SRC_URI[proc-macro2-1.0.85.sha256sum] = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
-SRC_URI[psm-0.1.21.sha256sum] = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
-SRC_URI[pyproject-toml-0.11.0.sha256sum] = "ef7061023bcb58a0fc4a4bbe9819c13b0dca7c2abc14da14f5ecc1532ab3a36a"
-SRC_URI[python-pkginfo-0.6.5.sha256sum] = "c21f58880fc45e91d29b2f639ab4051aaa6a2b054534c2d343a953347d0dd600"
-SRC_URI[quote-1.0.36.sha256sum] = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-SRC_URI[quoted_printable-0.5.0.sha256sum] = "79ec282e887b434b68c18fe5c121d38e72a5cf35119b59e54ec5b992ea9c8eb0"
-SRC_URI[rand-0.8.5.sha256sum] = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-SRC_URI[rand_chacha-0.3.1.sha256sum] = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-SRC_URI[rand_core-0.6.4.sha256sum] = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-SRC_URI[rayon-1.10.0.sha256sum] = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
-SRC_URI[rayon-core-1.12.1.sha256sum] = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
-SRC_URI[redox_syscall-0.4.1.sha256sum] = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
-SRC_URI[redox_syscall-0.5.1.sha256sum] = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
-SRC_URI[redox_users-0.4.5.sha256sum] = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
-SRC_URI[regex-1.10.6.sha256sum] = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
-SRC_URI[regex-automata-0.1.10.sha256sum] = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
-SRC_URI[regex-automata-0.4.7.sha256sum] = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
-SRC_URI[regex-syntax-0.6.29.sha256sum] = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
-SRC_URI[regex-syntax-0.8.4.sha256sum] = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
-SRC_URI[relative-path-1.9.3.sha256sum] = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
-SRC_URI[rfc2047-decoder-1.0.6.sha256sum] = "bc36545d1021456a751b573517cb52e8c339b2f662e6b2778ef629282678de29"
-SRC_URI[ring-0.17.8.sha256sum] = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
-SRC_URI[rstest-0.22.0.sha256sum] = "7b423f0e62bdd61734b67cd21ff50871dfaeb9cc74f869dcd6af974fbcb19936"
-SRC_URI[rstest_macros-0.22.0.sha256sum] = "c5e1711e7d14f74b12a58411c542185ef7fb7f2e7f8ee6e2940a883628522b42"
-SRC_URI[rustc_version-0.4.1.sha256sum] = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
-SRC_URI[rustflags-0.1.6.sha256sum] = "d7fc92159fb50a431c5da366f7627751fe7263cf867f8a30f27fa6063ba02ac0"
-SRC_URI[rustix-0.38.34.sha256sum] = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
-SRC_URI[rustls-0.23.19.sha256sum] = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
-SRC_URI[rustls-pemfile-2.1.3.sha256sum] = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
-SRC_URI[rustls-pki-types-1.10.0.sha256sum] = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
-SRC_URI[rustls-webpki-0.102.8.sha256sum] = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
-SRC_URI[rustversion-1.0.17.sha256sum] = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
-SRC_URI[ryu-1.0.18.sha256sum] = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
-SRC_URI[same-file-1.0.6.sha256sum] = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
-SRC_URI[schannel-0.1.23.sha256sum] = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
-SRC_URI[schemars-0.8.21.sha256sum] = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92"
-SRC_URI[schemars_derive-0.8.21.sha256sum] = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e"
-SRC_URI[scopeguard-1.2.0.sha256sum] = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
-SRC_URI[scroll-0.12.0.sha256sum] = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
-SRC_URI[scroll_derive-0.12.0.sha256sum] = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932"
-SRC_URI[security-framework-2.11.0.sha256sum] = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
-SRC_URI[security-framework-sys-2.11.0.sha256sum] = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7"
-SRC_URI[semver-1.0.23.sha256sum] = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
-SRC_URI[serde-1.0.216.sha256sum] = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
-SRC_URI[serde_derive-1.0.216.sha256sum] = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
-SRC_URI[serde_derive_internals-0.29.1.sha256sum] = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
-SRC_URI[serde_json-1.0.133.sha256sum] = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
-SRC_URI[serde_spanned-0.6.6.sha256sum] = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
-SRC_URI[sha2-0.10.8.sha256sum] = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
-SRC_URI[sharded-slab-0.1.7.sha256sum] = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
-SRC_URI[shell-words-1.1.0.sha256sum] = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
-SRC_URI[shlex-1.3.0.sha256sum] = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-SRC_URI[simd-adler32-0.3.7.sha256sum] = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
-SRC_URI[similar-2.5.0.sha256sum] = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
-SRC_URI[slab-0.4.9.sha256sum] = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
-SRC_URI[smallvec-1.13.2.sha256sum] = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
-SRC_URI[smawk-0.3.2.sha256sum] = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
-SRC_URI[snapbox-0.6.16.sha256sum] = "027c936207f85d10d015e21faf5c676c7e08c453ed371adf55c0874c443ca77a"
-SRC_URI[snapbox-macros-0.3.10.sha256sum] = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af"
-SRC_URI[socks-0.3.4.sha256sum] = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b"
-SRC_URI[spin-0.9.8.sha256sum] = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
-SRC_URI[stable_deref_trait-1.2.0.sha256sum] = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
-SRC_URI[stacker-0.1.15.sha256sum] = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
-SRC_URI[static_assertions-1.1.0.sha256sum] = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
-SRC_URI[strsim-0.11.1.sha256sum] = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
-SRC_URI[subtle-2.5.0.sha256sum] = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
-SRC_URI[syn-1.0.109.sha256sum] = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-SRC_URI[syn-2.0.87.sha256sum] = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
-SRC_URI[synstructure-0.13.1.sha256sum] = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
-SRC_URI[tar-0.4.43.sha256sum] = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6"
-SRC_URI[target-lexicon-0.13.0.sha256sum] = "4ff4a4048091358129767b8a200d6927f58876c8b5ea16fb7b0222d43b79bfa8"
-SRC_URI[tempfile-3.11.0.sha256sum] = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
-SRC_URI[termcolor-1.4.1.sha256sum] = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
-SRC_URI[terminal_size-0.3.0.sha256sum] = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
-SRC_URI[textwrap-0.16.1.sha256sum] = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
-SRC_URI[thiserror-1.0.64.sha256sum] = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
-SRC_URI[thiserror-2.0.3.sha256sum] = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
-SRC_URI[thiserror-impl-1.0.64.sha256sum] = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
-SRC_URI[thiserror-impl-2.0.3.sha256sum] = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
-SRC_URI[thread_local-1.1.8.sha256sum] = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
-SRC_URI[time-0.3.36.sha256sum] = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
-SRC_URI[time-core-0.1.2.sha256sum] = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
-SRC_URI[time-macros-0.2.18.sha256sum] = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
-SRC_URI[tinystr-0.7.6.sha256sum] = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
-SRC_URI[toml-0.8.15.sha256sum] = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28"
-SRC_URI[toml_datetime-0.6.6.sha256sum] = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
-SRC_URI[toml_edit-0.21.1.sha256sum] = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
-SRC_URI[toml_edit-0.22.16.sha256sum] = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
-SRC_URI[tracing-0.1.40.sha256sum] = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
-SRC_URI[tracing-attributes-0.1.27.sha256sum] = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
-SRC_URI[tracing-core-0.1.32.sha256sum] = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
-SRC_URI[tracing-log-0.2.0.sha256sum] = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
-SRC_URI[tracing-serde-0.1.3.sha256sum] = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1"
-SRC_URI[tracing-subscriber-0.3.18.sha256sum] = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
-SRC_URI[trycmd-0.15.6.sha256sum] = "3e8673f1dc45acdff8e25a06cc62f8e529563e8acd84237ce83d5a28e2befa12"
-SRC_URI[twox-hash-1.6.3.sha256sum] = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
-SRC_URI[typenum-1.17.0.sha256sum] = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
-SRC_URI[unicase-2.7.0.sha256sum] = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
-SRC_URI[unicode-ident-1.0.12.sha256sum] = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-SRC_URI[unicode-linebreak-0.1.5.sha256sum] = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
-SRC_URI[unicode-width-0.1.13.sha256sum] = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
-SRC_URI[unicode-xid-0.2.6.sha256sum] = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
-SRC_URI[unscanny-0.1.0.sha256sum] = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47"
-SRC_URI[untrusted-0.9.0.sha256sum] = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
-SRC_URI[ureq-2.11.0.sha256sum] = "b30e6f97efe1fa43535ee241ee76967d3ff6ff3953ebb430d8d55c5393029e7b"
-SRC_URI[url-2.5.4.sha256sum] = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
-SRC_URI[urlencoding-2.1.3.sha256sum] = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
-SRC_URI[utf16_iter-1.0.5.sha256sum] = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
-SRC_URI[utf8_iter-1.0.4.sha256sum] = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
-SRC_URI[utf8parse-0.2.2.sha256sum] = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
-SRC_URI[uuid-1.8.0.sha256sum] = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
-SRC_URI[valuable-0.1.0.sha256sum] = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
-SRC_URI[vcpkg-0.2.15.sha256sum] = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
-SRC_URI[version_check-0.9.4.sha256sum] = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-SRC_URI[versions-6.2.0.sha256sum] = "38a8931f8d167b6448076020e70b9de46dcf5ea1731212481a092d0071c4ac5b"
-SRC_URI[wait-timeout-0.2.0.sha256sum] = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
-SRC_URI[walkdir-2.5.0.sha256sum] = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
-SRC_URI[wasi-0.11.0+wasi-snapshot-preview1.sha256sum] = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-SRC_URI[webpki-roots-0.26.2.sha256sum] = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3"
-SRC_URI[which-7.0.0.sha256sum] = "c9cad3279ade7346b96e38731a641d7343dd6a53d55083dd54eadfa5a1b38c6b"
-SRC_URI[wild-2.2.1.sha256sum] = "a3131afc8c575281e1e80f36ed6a092aa502c08b18ed7524e86fbbb12bb410e1"
-SRC_URI[winapi-0.3.9.sha256sum] = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-SRC_URI[winapi-i686-pc-windows-gnu-0.4.0.sha256sum] = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-SRC_URI[winapi-util-0.1.8.sha256sum] = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
-SRC_URI[winapi-x86_64-pc-windows-gnu-0.4.0.sha256sum] = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-SRC_URI[windows-sys-0.48.0.sha256sum] = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-SRC_URI[windows-sys-0.52.0.sha256sum] = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-SRC_URI[windows-targets-0.48.5.sha256sum] = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-SRC_URI[windows-targets-0.52.6.sha256sum] = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-SRC_URI[windows_aarch64_gnullvm-0.48.5.sha256sum] = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-SRC_URI[windows_aarch64_gnullvm-0.52.6.sha256sum] = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-SRC_URI[windows_aarch64_msvc-0.48.5.sha256sum] = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-SRC_URI[windows_aarch64_msvc-0.52.6.sha256sum] = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-SRC_URI[windows_i686_gnu-0.48.5.sha256sum] = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-SRC_URI[windows_i686_gnu-0.52.6.sha256sum] = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-SRC_URI[windows_i686_gnullvm-0.52.6.sha256sum] = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-SRC_URI[windows_i686_msvc-0.48.5.sha256sum] = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-SRC_URI[windows_i686_msvc-0.52.6.sha256sum] = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-SRC_URI[windows_x86_64_gnu-0.48.5.sha256sum] = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-SRC_URI[windows_x86_64_gnu-0.52.6.sha256sum] = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-SRC_URI[windows_x86_64_gnullvm-0.48.5.sha256sum] = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-SRC_URI[windows_x86_64_gnullvm-0.52.6.sha256sum] = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-SRC_URI[windows_x86_64_msvc-0.48.5.sha256sum] = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
-SRC_URI[windows_x86_64_msvc-0.52.6.sha256sum] = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-SRC_URI[winnow-0.5.40.sha256sum] = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
-SRC_URI[winnow-0.6.13.sha256sum] = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
-SRC_URI[winsafe-0.0.19.sha256sum] = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
-SRC_URI[write16-1.0.0.sha256sum] = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
-SRC_URI[writeable-0.5.5.sha256sum] = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
-SRC_URI[xattr-1.3.1.sha256sum] = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
-SRC_URI[xwin-0.6.5.sha256sum] = "ca7e4546db1514c186778f0a257d89732ed9ed75587d0953ac25be7519d9f0d1"
-SRC_URI[xz2-0.1.7.sha256sum] = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
-SRC_URI[yansi-1.0.1.sha256sum] = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
-SRC_URI[yoke-0.7.4.sha256sum] = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5"
-SRC_URI[yoke-derive-0.7.5.sha256sum] = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
-SRC_URI[zerocopy-0.7.34.sha256sum] = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
-SRC_URI[zerocopy-derive-0.7.34.sha256sum] = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
-SRC_URI[zerofrom-0.1.4.sha256sum] = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55"
-SRC_URI[zerofrom-derive-0.1.5.sha256sum] = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
-SRC_URI[zeroize-1.8.1.sha256sum] = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
-SRC_URI[zerovec-0.10.4.sha256sum] = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
-SRC_URI[zerovec-derive-0.10.3.sha256sum] = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
-SRC_URI[zip-2.1.6.sha256sum] = "40dd8c92efc296286ce1fbd16657c5dbefff44f1b4ca01cc5f517d8b7b3d3e2e"
-SRC_URI[zopfli-0.8.1.sha256sum] = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
diff --git a/meta/recipes-devtools/python/python3-maturin_1.8.1.bb b/meta/recipes-devtools/python/python3-maturin_1.8.1.bb
index d0f0b381a5..a6b65e5e7b 100644
--- a/meta/recipes-devtools/python/python3-maturin_1.8.1.bb
+++ b/meta/recipes-devtools/python/python3-maturin_1.8.1.bb
@@ -17,9 +17,7 @@ DEPENDS += "\
     python3-setuptools-rust \
 "
 
-require ${BPN}-crates.inc
-
-inherit pypi cargo-update-recipe-crates python_pyo3 python_setuptools_build_meta
+inherit pypi python_pyo3 python_setuptools_build_meta vendor_cargo
 
 do_configure() {
     python_pyo3_do_configure
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 24/30] python3-rpds-py: mirgrate to vendor cargo class
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (22 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 23/30] python3-maturin: " Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 25/30] librsvg: " Stefan Herbrechtsmeier
                   ` (6 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 .../python/python3-rpds-py-crates.inc         | 54 -------------------
 .../python/python3-rpds-py_0.22.3.bb          |  4 +-
 2 files changed, 1 insertion(+), 57 deletions(-)
 delete mode 100644 meta/recipes-devtools/python/python3-rpds-py-crates.inc

diff --git a/meta/recipes-devtools/python/python3-rpds-py-crates.inc b/meta/recipes-devtools/python/python3-rpds-py-crates.inc
deleted file mode 100644
index 7022cbdcc8..0000000000
--- a/meta/recipes-devtools/python/python3-rpds-py-crates.inc
+++ /dev/null
@@ -1,54 +0,0 @@
-# Autogenerated with 'bitbake -c update_crates python3-rpds-py'
-
-# from Cargo.lock
-SRC_URI += " \
-    crate://crates.io/archery/1.2.1 \
-    crate://crates.io/autocfg/1.3.0 \
-    crate://crates.io/cc/1.0.90 \
-    crate://crates.io/cfg-if/1.0.0 \
-    crate://crates.io/heck/0.5.0 \
-    crate://crates.io/indoc/2.0.5 \
-    crate://crates.io/libc/0.2.155 \
-    crate://crates.io/memoffset/0.9.1 \
-    crate://crates.io/once_cell/1.19.0 \
-    crate://crates.io/portable-atomic/1.6.0 \
-    crate://crates.io/proc-macro2/1.0.86 \
-    crate://crates.io/pyo3/0.23.3 \
-    crate://crates.io/pyo3-build-config/0.23.3 \
-    crate://crates.io/pyo3-ffi/0.23.3 \
-    crate://crates.io/pyo3-macros/0.23.3 \
-    crate://crates.io/pyo3-macros-backend/0.23.3 \
-    crate://crates.io/python3-dll-a/0.2.11 \
-    crate://crates.io/quote/1.0.36 \
-    crate://crates.io/rpds/1.1.0 \
-    crate://crates.io/syn/2.0.69 \
-    crate://crates.io/target-lexicon/0.12.14 \
-    crate://crates.io/triomphe/0.1.13 \
-    crate://crates.io/unicode-ident/1.0.12 \
-    crate://crates.io/unindent/0.2.3 \
-"
-
-SRC_URI[archery-1.2.1.sha256sum] = "eae2ed21cd55021f05707a807a5fc85695dafb98832921f6cfa06db67ca5b869"
-SRC_URI[autocfg-1.3.0.sha256sum] = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
-SRC_URI[cc-1.0.90.sha256sum] = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
-SRC_URI[cfg-if-1.0.0.sha256sum] = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-SRC_URI[heck-0.5.0.sha256sum] = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-SRC_URI[indoc-2.0.5.sha256sum] = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
-SRC_URI[libc-0.2.155.sha256sum] = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
-SRC_URI[memoffset-0.9.1.sha256sum] = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
-SRC_URI[once_cell-1.19.0.sha256sum] = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-SRC_URI[portable-atomic-1.6.0.sha256sum] = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
-SRC_URI[proc-macro2-1.0.86.sha256sum] = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
-SRC_URI[pyo3-0.23.3.sha256sum] = "e484fd2c8b4cb67ab05a318f1fd6fa8f199fcc30819f08f07d200809dba26c15"
-SRC_URI[pyo3-build-config-0.23.3.sha256sum] = "dc0e0469a84f208e20044b98965e1561028180219e35352a2afaf2b942beff3b"
-SRC_URI[pyo3-ffi-0.23.3.sha256sum] = "eb1547a7f9966f6f1a0f0227564a9945fe36b90da5a93b3933fc3dc03fae372d"
-SRC_URI[pyo3-macros-0.23.3.sha256sum] = "fdb6da8ec6fa5cedd1626c886fc8749bdcbb09424a86461eb8cdf096b7c33257"
-SRC_URI[pyo3-macros-backend-0.23.3.sha256sum] = "38a385202ff5a92791168b1136afae5059d3ac118457bb7bc304c197c2d33e7d"
-SRC_URI[python3-dll-a-0.2.11.sha256sum] = "9b9e268ee1be609e93a13eb06839f68f67e5fe0fb4049834d261c2d5091c1b6d"
-SRC_URI[quote-1.0.36.sha256sum] = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-SRC_URI[rpds-1.1.0.sha256sum] = "a0e15515d3ce3313324d842629ea4905c25a13f81953eadb88f85516f59290a4"
-SRC_URI[syn-2.0.69.sha256sum] = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6"
-SRC_URI[target-lexicon-0.12.14.sha256sum] = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
-SRC_URI[triomphe-0.1.13.sha256sum] = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369"
-SRC_URI[unicode-ident-1.0.12.sha256sum] = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-SRC_URI[unindent-0.2.3.sha256sum] = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
diff --git a/meta/recipes-devtools/python/python3-rpds-py_0.22.3.bb b/meta/recipes-devtools/python/python3-rpds-py_0.22.3.bb
index 8eeb954c89..33a4cb5e54 100644
--- a/meta/recipes-devtools/python/python3-rpds-py_0.22.3.bb
+++ b/meta/recipes-devtools/python/python3-rpds-py_0.22.3.bb
@@ -6,9 +6,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=7767fa537c4596c54141f32882c4a984"
 
 SRC_URI[sha256sum] = "e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"
 
-require ${BPN}-crates.inc
-
-inherit pypi cargo-update-recipe-crates python_maturin ptest-python-pytest
+inherit pypi python_maturin ptest-python-pytest vendor_cargo
 
 PYPI_PACKAGE = "rpds_py"
 UPSTREAM_CHECK_PYPI_PACKAGE = "${PYPI_PACKAGE}"
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 25/30] librsvg: mirgrate to vendor cargo class
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (23 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 24/30] python3-rpds-py: " Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 26/30] librsvg: update dependecies to fix RUSTSEC-2024-0421 Stefan Herbrechtsmeier
                   ` (5 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/recipes-gnome/librsvg/librsvg-crates.inc | 590 ------------------
 meta/recipes-gnome/librsvg/librsvg_2.59.2.bb  |   4 +-
 2 files changed, 1 insertion(+), 593 deletions(-)
 delete mode 100644 meta/recipes-gnome/librsvg/librsvg-crates.inc

diff --git a/meta/recipes-gnome/librsvg/librsvg-crates.inc b/meta/recipes-gnome/librsvg/librsvg-crates.inc
deleted file mode 100644
index 54cd1c66c9..0000000000
--- a/meta/recipes-gnome/librsvg/librsvg-crates.inc
+++ /dev/null
@@ -1,590 +0,0 @@
-# Autogenerated with 'bitbake -c update_crates librsvg'
-
-# from Cargo.lock
-SRC_URI += " \
-    crate://crates.io/adler/1.0.2 \
-    crate://crates.io/ahash/0.8.11 \
-    crate://crates.io/aho-corasick/1.1.3 \
-    crate://crates.io/android-tzdata/0.1.1 \
-    crate://crates.io/android_system_properties/0.1.5 \
-    crate://crates.io/anes/0.1.6 \
-    crate://crates.io/anstream/0.6.15 \
-    crate://crates.io/anstyle/1.0.8 \
-    crate://crates.io/anstyle-parse/0.2.5 \
-    crate://crates.io/anstyle-query/1.1.1 \
-    crate://crates.io/anstyle-wincon/3.0.4 \
-    crate://crates.io/anyhow/1.0.86 \
-    crate://crates.io/approx/0.5.1 \
-    crate://crates.io/assert_cmd/2.0.15 \
-    crate://crates.io/autocfg/1.3.0 \
-    crate://crates.io/av-data/0.4.2 \
-    crate://crates.io/bit-set/0.5.3 \
-    crate://crates.io/bit-vec/0.6.3 \
-    crate://crates.io/bitflags/1.3.2 \
-    crate://crates.io/bitflags/2.6.0 \
-    crate://crates.io/bitreader/0.3.8 \
-    crate://crates.io/block/0.1.6 \
-    crate://crates.io/block-buffer/0.10.4 \
-    crate://crates.io/bstr/1.10.0 \
-    crate://crates.io/bumpalo/3.16.0 \
-    crate://crates.io/byte-slice-cast/1.2.2 \
-    crate://crates.io/bytemuck/1.16.3 \
-    crate://crates.io/byteorder/1.5.0 \
-    crate://crates.io/byteorder-lite/0.1.0 \
-    crate://crates.io/bytes/1.7.1 \
-    crate://crates.io/cairo-rs/0.20.0 \
-    crate://crates.io/cairo-sys-rs/0.20.0 \
-    crate://crates.io/cast/0.3.0 \
-    crate://crates.io/cc/1.1.8 \
-    crate://crates.io/cfg-expr/0.15.8 \
-    crate://crates.io/cfg-if/1.0.0 \
-    crate://crates.io/chrono/0.4.38 \
-    crate://crates.io/ciborium/0.2.2 \
-    crate://crates.io/ciborium-io/0.2.2 \
-    crate://crates.io/ciborium-ll/0.2.2 \
-    crate://crates.io/clap/4.5.13 \
-    crate://crates.io/clap_builder/4.5.13 \
-    crate://crates.io/clap_complete/4.5.12 \
-    crate://crates.io/clap_derive/4.5.13 \
-    crate://crates.io/clap_lex/0.7.2 \
-    crate://crates.io/color_quant/1.1.0 \
-    crate://crates.io/colorchoice/1.0.2 \
-    crate://crates.io/core-foundation-sys/0.8.6 \
-    crate://crates.io/crc32fast/1.4.2 \
-    crate://crates.io/criterion/0.5.1 \
-    crate://crates.io/criterion-plot/0.5.0 \
-    crate://crates.io/crossbeam-deque/0.8.5 \
-    crate://crates.io/crossbeam-epoch/0.9.18 \
-    crate://crates.io/crossbeam-utils/0.8.20 \
-    crate://crates.io/crunchy/0.2.2 \
-    crate://crates.io/crypto-common/0.1.6 \
-    crate://crates.io/cssparser/0.31.2 \
-    crate://crates.io/cssparser-macros/0.6.1 \
-    crate://crates.io/data-url/0.3.1 \
-    crate://crates.io/dav1d/0.10.3 \
-    crate://crates.io/dav1d-sys/0.8.2 \
-    crate://crates.io/dcv-color-primitives/0.6.1 \
-    crate://crates.io/deranged/0.3.11 \
-    crate://crates.io/derive_more/0.99.18 \
-    crate://crates.io/difflib/0.4.0 \
-    crate://crates.io/digest/0.10.7 \
-    crate://crates.io/dlib/0.5.2 \
-    crate://crates.io/doc-comment/0.3.3 \
-    crate://crates.io/dtoa/1.0.9 \
-    crate://crates.io/dtoa-short/0.3.5 \
-    crate://crates.io/either/1.13.0 \
-    crate://crates.io/encoding_rs/0.8.34 \
-    crate://crates.io/equivalent/1.0.1 \
-    crate://crates.io/errno/0.3.9 \
-    crate://crates.io/fallible_collections/0.4.9 \
-    crate://crates.io/fastrand/2.1.0 \
-    crate://crates.io/fdeflate/0.3.4 \
-    crate://crates.io/flate2/1.0.31 \
-    crate://crates.io/float-cmp/0.9.0 \
-    crate://crates.io/fnv/1.0.7 \
-    crate://crates.io/form_urlencoded/1.2.1 \
-    crate://crates.io/futf/0.1.5 \
-    crate://crates.io/futures-channel/0.3.30 \
-    crate://crates.io/futures-core/0.3.30 \
-    crate://crates.io/futures-executor/0.3.30 \
-    crate://crates.io/futures-io/0.3.30 \
-    crate://crates.io/futures-macro/0.3.30 \
-    crate://crates.io/futures-task/0.3.30 \
-    crate://crates.io/futures-util/0.3.30 \
-    crate://crates.io/fxhash/0.2.1 \
-    crate://crates.io/gdk-pixbuf/0.20.0 \
-    crate://crates.io/gdk-pixbuf-sys/0.20.0 \
-    crate://crates.io/generic-array/0.14.7 \
-    crate://crates.io/getrandom/0.2.15 \
-    crate://crates.io/gif/0.13.1 \
-    crate://crates.io/gio/0.20.0 \
-    crate://crates.io/gio-sys/0.20.0 \
-    crate://crates.io/glib/0.20.0 \
-    crate://crates.io/glib-macros/0.20.0 \
-    crate://crates.io/glib-sys/0.20.0 \
-    crate://crates.io/gobject-sys/0.20.0 \
-    crate://crates.io/half/2.4.1 \
-    crate://crates.io/hashbrown/0.13.2 \
-    crate://crates.io/hashbrown/0.14.5 \
-    crate://crates.io/heck/0.5.0 \
-    crate://crates.io/hermit-abi/0.3.9 \
-    crate://crates.io/iana-time-zone/0.1.60 \
-    crate://crates.io/iana-time-zone-haiku/0.1.2 \
-    crate://crates.io/idna/0.5.0 \
-    crate://crates.io/image/0.25.2 \
-    crate://crates.io/image-webp/0.1.3 \
-    crate://crates.io/indexmap/2.3.0 \
-    crate://crates.io/is-terminal/0.4.12 \
-    crate://crates.io/is_terminal_polyfill/1.70.1 \
-    crate://crates.io/itertools/0.10.5 \
-    crate://crates.io/itertools/0.13.0 \
-    crate://crates.io/itoa/1.0.11 \
-    crate://crates.io/js-sys/0.3.69 \
-    crate://crates.io/language-tags/0.3.2 \
-    crate://crates.io/lazy_static/1.5.0 \
-    crate://crates.io/libc/0.2.155 \
-    crate://crates.io/libloading/0.8.5 \
-    crate://crates.io/libm/0.2.8 \
-    crate://crates.io/linked-hash-map/0.5.6 \
-    crate://crates.io/linux-raw-sys/0.4.14 \
-    crate://crates.io/locale_config/0.3.0 \
-    crate://crates.io/lock_api/0.4.12 \
-    crate://crates.io/log/0.4.22 \
-    crate://crates.io/lopdf/0.33.0 \
-    crate://crates.io/mac/0.1.1 \
-    crate://crates.io/malloc_buf/0.0.6 \
-    crate://crates.io/markup5ever/0.12.1 \
-    crate://crates.io/matches/0.1.10 \
-    crate://crates.io/matrixmultiply/0.3.9 \
-    crate://crates.io/md-5/0.10.6 \
-    crate://crates.io/memchr/2.7.4 \
-    crate://crates.io/minimal-lexical/0.2.1 \
-    crate://crates.io/miniz_oxide/0.7.4 \
-    crate://crates.io/mp4parse/0.17.0 \
-    crate://crates.io/nalgebra/0.33.0 \
-    crate://crates.io/nalgebra-macros/0.2.2 \
-    crate://crates.io/new_debug_unreachable/1.0.6 \
-    crate://crates.io/nom/7.1.3 \
-    crate://crates.io/normalize-line-endings/0.3.0 \
-    crate://crates.io/num-bigint/0.4.6 \
-    crate://crates.io/num-complex/0.4.6 \
-    crate://crates.io/num-conv/0.1.0 \
-    crate://crates.io/num-derive/0.4.2 \
-    crate://crates.io/num-integer/0.1.46 \
-    crate://crates.io/num-rational/0.4.2 \
-    crate://crates.io/num-traits/0.2.19 \
-    crate://crates.io/objc/0.2.7 \
-    crate://crates.io/objc-foundation/0.1.1 \
-    crate://crates.io/objc_id/0.1.1 \
-    crate://crates.io/once_cell/1.19.0 \
-    crate://crates.io/oorandom/11.1.4 \
-    crate://crates.io/pango/0.20.0 \
-    crate://crates.io/pango-sys/0.20.0 \
-    crate://crates.io/pangocairo/0.20.0 \
-    crate://crates.io/pangocairo-sys/0.20.0 \
-    crate://crates.io/parking_lot/0.12.3 \
-    crate://crates.io/parking_lot_core/0.9.10 \
-    crate://crates.io/paste/1.0.15 \
-    crate://crates.io/percent-encoding/2.3.1 \
-    crate://crates.io/phf/0.10.1 \
-    crate://crates.io/phf/0.11.2 \
-    crate://crates.io/phf_codegen/0.10.0 \
-    crate://crates.io/phf_codegen/0.11.2 \
-    crate://crates.io/phf_generator/0.10.0 \
-    crate://crates.io/phf_generator/0.11.2 \
-    crate://crates.io/phf_macros/0.11.2 \
-    crate://crates.io/phf_shared/0.10.0 \
-    crate://crates.io/phf_shared/0.11.2 \
-    crate://crates.io/pin-project-lite/0.2.14 \
-    crate://crates.io/pin-utils/0.1.0 \
-    crate://crates.io/pkg-config/0.3.30 \
-    crate://crates.io/plotters/0.3.6 \
-    crate://crates.io/plotters-backend/0.3.6 \
-    crate://crates.io/plotters-svg/0.3.6 \
-    crate://crates.io/png/0.17.13 \
-    crate://crates.io/powerfmt/0.2.0 \
-    crate://crates.io/ppv-lite86/0.2.20 \
-    crate://crates.io/precomputed-hash/0.1.1 \
-    crate://crates.io/predicates/3.1.2 \
-    crate://crates.io/predicates-core/1.0.8 \
-    crate://crates.io/predicates-tree/1.0.11 \
-    crate://crates.io/proc-macro-crate/3.1.0 \
-    crate://crates.io/proc-macro2/1.0.86 \
-    crate://crates.io/proptest/1.5.0 \
-    crate://crates.io/quick-error/1.2.3 \
-    crate://crates.io/quick-error/2.0.1 \
-    crate://crates.io/quote/1.0.36 \
-    crate://crates.io/rand/0.8.5 \
-    crate://crates.io/rand_chacha/0.3.1 \
-    crate://crates.io/rand_core/0.6.4 \
-    crate://crates.io/rand_xorshift/0.3.0 \
-    crate://crates.io/rawpointer/0.2.1 \
-    crate://crates.io/rayon/1.10.0 \
-    crate://crates.io/rayon-core/1.12.1 \
-    crate://crates.io/rctree/0.6.0 \
-    crate://crates.io/redox_syscall/0.5.3 \
-    crate://crates.io/regex/1.10.6 \
-    crate://crates.io/regex-automata/0.4.7 \
-    crate://crates.io/regex-syntax/0.8.4 \
-    crate://crates.io/rgb/0.8.48 \
-    crate://crates.io/rustix/0.38.34 \
-    crate://crates.io/rusty-fork/0.3.0 \
-    crate://crates.io/ryu/1.0.18 \
-    crate://crates.io/safe_arch/0.7.2 \
-    crate://crates.io/same-file/1.0.6 \
-    crate://crates.io/scopeguard/1.2.0 \
-    crate://crates.io/selectors/0.25.0 \
-    crate://crates.io/serde/1.0.204 \
-    crate://crates.io/serde_derive/1.0.204 \
-    crate://crates.io/serde_json/1.0.122 \
-    crate://crates.io/serde_spanned/0.6.7 \
-    crate://crates.io/servo_arc/0.3.0 \
-    crate://crates.io/shell-words/1.1.0 \
-    crate://crates.io/simba/0.9.0 \
-    crate://crates.io/simd-adler32/0.3.7 \
-    crate://crates.io/siphasher/0.3.11 \
-    crate://crates.io/slab/0.4.9 \
-    crate://crates.io/smallvec/1.13.2 \
-    crate://crates.io/stable_deref_trait/1.2.0 \
-    crate://crates.io/static_assertions/1.1.0 \
-    crate://crates.io/string_cache/0.8.7 \
-    crate://crates.io/string_cache_codegen/0.5.2 \
-    crate://crates.io/strsim/0.11.1 \
-    crate://crates.io/syn/2.0.72 \
-    crate://crates.io/system-deps/6.2.2 \
-    crate://crates.io/system-deps/7.0.1 \
-    crate://crates.io/target-lexicon/0.12.16 \
-    crate://crates.io/tempfile/3.12.0 \
-    crate://crates.io/tendril/0.4.3 \
-    crate://crates.io/termtree/0.4.1 \
-    crate://crates.io/thiserror/1.0.63 \
-    crate://crates.io/thiserror-impl/1.0.63 \
-    crate://crates.io/time/0.3.36 \
-    crate://crates.io/time-core/0.1.2 \
-    crate://crates.io/time-macros/0.2.18 \
-    crate://crates.io/tinytemplate/1.2.1 \
-    crate://crates.io/tinyvec/1.8.0 \
-    crate://crates.io/tinyvec_macros/0.1.1 \
-    crate://crates.io/toml/0.8.19 \
-    crate://crates.io/toml_datetime/0.6.8 \
-    crate://crates.io/toml_edit/0.21.1 \
-    crate://crates.io/toml_edit/0.22.20 \
-    crate://crates.io/typenum/1.17.0 \
-    crate://crates.io/unarray/0.1.4 \
-    crate://crates.io/unicode-bidi/0.3.15 \
-    crate://crates.io/unicode-ident/1.0.12 \
-    crate://crates.io/unicode-normalization/0.1.23 \
-    crate://crates.io/url/2.5.2 \
-    crate://crates.io/utf-8/0.7.6 \
-    crate://crates.io/utf8parse/0.2.2 \
-    crate://crates.io/version-compare/0.2.0 \
-    crate://crates.io/version_check/0.9.5 \
-    crate://crates.io/wait-timeout/0.2.0 \
-    crate://crates.io/walkdir/2.5.0 \
-    crate://crates.io/wasi/0.11.0+wasi-snapshot-preview1 \
-    crate://crates.io/wasm-bindgen/0.2.92 \
-    crate://crates.io/wasm-bindgen-backend/0.2.92 \
-    crate://crates.io/wasm-bindgen-macro/0.2.92 \
-    crate://crates.io/wasm-bindgen-macro-support/0.2.92 \
-    crate://crates.io/wasm-bindgen-shared/0.2.92 \
-    crate://crates.io/web-sys/0.3.69 \
-    crate://crates.io/weezl/0.1.8 \
-    crate://crates.io/wide/0.7.26 \
-    crate://crates.io/winapi/0.3.9 \
-    crate://crates.io/winapi-i686-pc-windows-gnu/0.4.0 \
-    crate://crates.io/winapi-util/0.1.9 \
-    crate://crates.io/winapi-x86_64-pc-windows-gnu/0.4.0 \
-    crate://crates.io/windows-core/0.52.0 \
-    crate://crates.io/windows-sys/0.52.0 \
-    crate://crates.io/windows-sys/0.59.0 \
-    crate://crates.io/windows-targets/0.52.6 \
-    crate://crates.io/windows_aarch64_gnullvm/0.52.6 \
-    crate://crates.io/windows_aarch64_msvc/0.52.6 \
-    crate://crates.io/windows_i686_gnu/0.52.6 \
-    crate://crates.io/windows_i686_gnullvm/0.52.6 \
-    crate://crates.io/windows_i686_msvc/0.52.6 \
-    crate://crates.io/windows_x86_64_gnu/0.52.6 \
-    crate://crates.io/windows_x86_64_gnullvm/0.52.6 \
-    crate://crates.io/windows_x86_64_msvc/0.52.6 \
-    crate://crates.io/winnow/0.5.40 \
-    crate://crates.io/winnow/0.6.18 \
-    crate://crates.io/xml5ever/0.18.1 \
-    crate://crates.io/yeslogic-fontconfig-sys/6.0.0 \
-    crate://crates.io/zerocopy/0.7.35 \
-    crate://crates.io/zerocopy-derive/0.7.35 \
-    crate://crates.io/zune-core/0.4.12 \
-    crate://crates.io/zune-jpeg/0.4.13 \
-"
-
-SRC_URI[adler-1.0.2.sha256sum] = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-SRC_URI[ahash-0.8.11.sha256sum] = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
-SRC_URI[aho-corasick-1.1.3.sha256sum] = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-SRC_URI[android-tzdata-0.1.1.sha256sum] = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
-SRC_URI[android_system_properties-0.1.5.sha256sum] = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-SRC_URI[anes-0.1.6.sha256sum] = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
-SRC_URI[anstream-0.6.15.sha256sum] = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
-SRC_URI[anstyle-1.0.8.sha256sum] = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
-SRC_URI[anstyle-parse-0.2.5.sha256sum] = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
-SRC_URI[anstyle-query-1.1.1.sha256sum] = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
-SRC_URI[anstyle-wincon-3.0.4.sha256sum] = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
-SRC_URI[anyhow-1.0.86.sha256sum] = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
-SRC_URI[approx-0.5.1.sha256sum] = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
-SRC_URI[assert_cmd-2.0.15.sha256sum] = "bc65048dd435533bb1baf2ed9956b9a278fbfdcf90301b39ee117f06c0199d37"
-SRC_URI[autocfg-1.3.0.sha256sum] = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
-SRC_URI[av-data-0.4.2.sha256sum] = "d75b98a3525d00f920df9a2d44cc99b9cc5b7dc70d7fbb612cd755270dbe6552"
-SRC_URI[bit-set-0.5.3.sha256sum] = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
-SRC_URI[bit-vec-0.6.3.sha256sum] = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
-SRC_URI[bitflags-1.3.2.sha256sum] = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-SRC_URI[bitflags-2.6.0.sha256sum] = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
-SRC_URI[bitreader-0.3.8.sha256sum] = "bdd859c9d97f7c468252795b35aeccc412bdbb1e90ee6969c4fa6328272eaeff"
-SRC_URI[block-0.1.6.sha256sum] = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
-SRC_URI[block-buffer-0.10.4.sha256sum] = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
-SRC_URI[bstr-1.10.0.sha256sum] = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
-SRC_URI[bumpalo-3.16.0.sha256sum] = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
-SRC_URI[byte-slice-cast-1.2.2.sha256sum] = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
-SRC_URI[bytemuck-1.16.3.sha256sum] = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83"
-SRC_URI[byteorder-1.5.0.sha256sum] = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
-SRC_URI[byteorder-lite-0.1.0.sha256sum] = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
-SRC_URI[bytes-1.7.1.sha256sum] = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
-SRC_URI[cairo-rs-0.20.0.sha256sum] = "797fd5a634dcb0ad0d7d583df794deb0a236d88e759cd34b7da20198c6c9d145"
-SRC_URI[cairo-sys-rs-0.20.0.sha256sum] = "428290f914b9b86089f60f5d8a9f6e440508e1bcff23b25afd51502b0a2da88f"
-SRC_URI[cast-0.3.0.sha256sum] = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
-SRC_URI[cc-1.1.8.sha256sum] = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549"
-SRC_URI[cfg-expr-0.15.8.sha256sum] = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
-SRC_URI[cfg-if-1.0.0.sha256sum] = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-SRC_URI[chrono-0.4.38.sha256sum] = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
-SRC_URI[ciborium-0.2.2.sha256sum] = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
-SRC_URI[ciborium-io-0.2.2.sha256sum] = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
-SRC_URI[ciborium-ll-0.2.2.sha256sum] = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
-SRC_URI[clap-4.5.13.sha256sum] = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
-SRC_URI[clap_builder-4.5.13.sha256sum] = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
-SRC_URI[clap_complete-4.5.12.sha256sum] = "a8670053e87c316345e384ca1f3eba3006fc6355ed8b8a1140d104e109e3df34"
-SRC_URI[clap_derive-4.5.13.sha256sum] = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
-SRC_URI[clap_lex-0.7.2.sha256sum] = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
-SRC_URI[color_quant-1.1.0.sha256sum] = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
-SRC_URI[colorchoice-1.0.2.sha256sum] = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
-SRC_URI[core-foundation-sys-0.8.6.sha256sum] = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
-SRC_URI[crc32fast-1.4.2.sha256sum] = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
-SRC_URI[criterion-0.5.1.sha256sum] = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
-SRC_URI[criterion-plot-0.5.0.sha256sum] = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
-SRC_URI[crossbeam-deque-0.8.5.sha256sum] = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
-SRC_URI[crossbeam-epoch-0.9.18.sha256sum] = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
-SRC_URI[crossbeam-utils-0.8.20.sha256sum] = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
-SRC_URI[crunchy-0.2.2.sha256sum] = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
-SRC_URI[crypto-common-0.1.6.sha256sum] = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
-SRC_URI[cssparser-0.31.2.sha256sum] = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be"
-SRC_URI[cssparser-macros-0.6.1.sha256sum] = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
-SRC_URI[data-url-0.3.1.sha256sum] = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
-SRC_URI[dav1d-0.10.3.sha256sum] = "0d4b54a40baf633a71c6f0fb49494a7e4ee7bc26f3e727212b6cb915aa1ea1e1"
-SRC_URI[dav1d-sys-0.8.2.sha256sum] = "6ecb1c5e8f4dc438eedc1b534a54672fb0e0a56035dae6b50162787bd2c50e95"
-SRC_URI[dcv-color-primitives-0.6.1.sha256sum] = "07ad62edfed069700a5b33af6babd29c498d7e33eb01d96ffa8841ee1841634c"
-SRC_URI[deranged-0.3.11.sha256sum] = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
-SRC_URI[derive_more-0.99.18.sha256sum] = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce"
-SRC_URI[difflib-0.4.0.sha256sum] = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
-SRC_URI[digest-0.10.7.sha256sum] = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
-SRC_URI[dlib-0.5.2.sha256sum] = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
-SRC_URI[doc-comment-0.3.3.sha256sum] = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
-SRC_URI[dtoa-1.0.9.sha256sum] = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653"
-SRC_URI[dtoa-short-0.3.5.sha256sum] = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
-SRC_URI[either-1.13.0.sha256sum] = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
-SRC_URI[encoding_rs-0.8.34.sha256sum] = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
-SRC_URI[equivalent-1.0.1.sha256sum] = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
-SRC_URI[errno-0.3.9.sha256sum] = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
-SRC_URI[fallible_collections-0.4.9.sha256sum] = "a88c69768c0a15262df21899142bc6df9b9b823546d4b4b9a7bc2d6c448ec6fd"
-SRC_URI[fastrand-2.1.0.sha256sum] = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
-SRC_URI[fdeflate-0.3.4.sha256sum] = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645"
-SRC_URI[flate2-1.0.31.sha256sum] = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920"
-SRC_URI[float-cmp-0.9.0.sha256sum] = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
-SRC_URI[fnv-1.0.7.sha256sum] = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-SRC_URI[form_urlencoded-1.2.1.sha256sum] = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
-SRC_URI[futf-0.1.5.sha256sum] = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
-SRC_URI[futures-channel-0.3.30.sha256sum] = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
-SRC_URI[futures-core-0.3.30.sha256sum] = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
-SRC_URI[futures-executor-0.3.30.sha256sum] = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
-SRC_URI[futures-io-0.3.30.sha256sum] = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
-SRC_URI[futures-macro-0.3.30.sha256sum] = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
-SRC_URI[futures-task-0.3.30.sha256sum] = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
-SRC_URI[futures-util-0.3.30.sha256sum] = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
-SRC_URI[fxhash-0.2.1.sha256sum] = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
-SRC_URI[gdk-pixbuf-0.20.0.sha256sum] = "28bb53ecb56857c683c9ec859908e076dd3969c7d67598bd8b1ce095d211304a"
-SRC_URI[gdk-pixbuf-sys-0.20.0.sha256sum] = "9f6681a0c1330d1d3968bec1529f7172d62819ef0bdbb0d18022320654158b03"
-SRC_URI[generic-array-0.14.7.sha256sum] = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-SRC_URI[getrandom-0.2.15.sha256sum] = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
-SRC_URI[gif-0.13.1.sha256sum] = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2"
-SRC_URI[gio-0.20.0.sha256sum] = "398e3da68749fdc32783cbf7521ec3f65c9cf946db8c7774f8460af49e52c6e2"
-SRC_URI[gio-sys-0.20.0.sha256sum] = "e4feb96b31c32730ea3e1e89aecd2e4e37ecb1c473ad8f685e3430a159419f63"
-SRC_URI[glib-0.20.0.sha256sum] = "fee90a615ce05be7a32932cfb8adf2c4bbb4700e80d37713c981fb24c0c56238"
-SRC_URI[glib-macros-0.20.0.sha256sum] = "4da558d8177c0c8c54368818b508a4244e1286fce2858cef4e547023f0cfa5ef"
-SRC_URI[glib-sys-0.20.0.sha256sum] = "4958c26e5a01c9af00dea669a97369eccbec29a8e6d125c24ea2d85ee7467b60"
-SRC_URI[gobject-sys-0.20.0.sha256sum] = "c6908864f5ffff15b56df7e90346863904f49b949337ed0456b9287af61903b8"
-SRC_URI[half-2.4.1.sha256sum] = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
-SRC_URI[hashbrown-0.13.2.sha256sum] = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
-SRC_URI[hashbrown-0.14.5.sha256sum] = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
-SRC_URI[heck-0.5.0.sha256sum] = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-SRC_URI[hermit-abi-0.3.9.sha256sum] = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
-SRC_URI[iana-time-zone-0.1.60.sha256sum] = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
-SRC_URI[iana-time-zone-haiku-0.1.2.sha256sum] = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
-SRC_URI[idna-0.5.0.sha256sum] = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
-SRC_URI[image-0.25.2.sha256sum] = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10"
-SRC_URI[image-webp-0.1.3.sha256sum] = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904"
-SRC_URI[indexmap-2.3.0.sha256sum] = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
-SRC_URI[is-terminal-0.4.12.sha256sum] = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
-SRC_URI[is_terminal_polyfill-1.70.1.sha256sum] = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
-SRC_URI[itertools-0.10.5.sha256sum] = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
-SRC_URI[itertools-0.13.0.sha256sum] = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
-SRC_URI[itoa-1.0.11.sha256sum] = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
-SRC_URI[js-sys-0.3.69.sha256sum] = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
-SRC_URI[language-tags-0.3.2.sha256sum] = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
-SRC_URI[lazy_static-1.5.0.sha256sum] = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-SRC_URI[libc-0.2.155.sha256sum] = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
-SRC_URI[libloading-0.8.5.sha256sum] = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
-SRC_URI[libm-0.2.8.sha256sum] = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
-SRC_URI[linked-hash-map-0.5.6.sha256sum] = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
-SRC_URI[linux-raw-sys-0.4.14.sha256sum] = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
-SRC_URI[locale_config-0.3.0.sha256sum] = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934"
-SRC_URI[lock_api-0.4.12.sha256sum] = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
-SRC_URI[log-0.4.22.sha256sum] = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
-SRC_URI[lopdf-0.33.0.sha256sum] = "b5c14afa083a906d49e1bda105ddbf8175016e2658954e6d0c3e612f886df3db"
-SRC_URI[mac-0.1.1.sha256sum] = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
-SRC_URI[malloc_buf-0.0.6.sha256sum] = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
-SRC_URI[markup5ever-0.12.1.sha256sum] = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
-SRC_URI[matches-0.1.10.sha256sum] = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
-SRC_URI[matrixmultiply-0.3.9.sha256sum] = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a"
-SRC_URI[md-5-0.10.6.sha256sum] = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
-SRC_URI[memchr-2.7.4.sha256sum] = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
-SRC_URI[minimal-lexical-0.2.1.sha256sum] = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-SRC_URI[miniz_oxide-0.7.4.sha256sum] = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
-SRC_URI[mp4parse-0.17.0.sha256sum] = "63a35203d3c6ce92d5251c77520acb2e57108c88728695aa883f70023624c570"
-SRC_URI[nalgebra-0.33.0.sha256sum] = "3c4b5f057b303842cf3262c27e465f4c303572e7f6b0648f60e16248ac3397f4"
-SRC_URI[nalgebra-macros-0.2.2.sha256sum] = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc"
-SRC_URI[new_debug_unreachable-1.0.6.sha256sum] = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
-SRC_URI[nom-7.1.3.sha256sum] = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-SRC_URI[normalize-line-endings-0.3.0.sha256sum] = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
-SRC_URI[num-bigint-0.4.6.sha256sum] = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
-SRC_URI[num-complex-0.4.6.sha256sum] = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
-SRC_URI[num-conv-0.1.0.sha256sum] = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
-SRC_URI[num-derive-0.4.2.sha256sum] = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
-SRC_URI[num-integer-0.1.46.sha256sum] = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
-SRC_URI[num-rational-0.4.2.sha256sum] = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
-SRC_URI[num-traits-0.2.19.sha256sum] = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
-SRC_URI[objc-0.2.7.sha256sum] = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
-SRC_URI[objc-foundation-0.1.1.sha256sum] = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
-SRC_URI[objc_id-0.1.1.sha256sum] = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
-SRC_URI[once_cell-1.19.0.sha256sum] = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-SRC_URI[oorandom-11.1.4.sha256sum] = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
-SRC_URI[pango-0.20.0.sha256sum] = "54768854025df6903061d0084fd9702a253ddfd60db7d9b751d43b76689a7f0a"
-SRC_URI[pango-sys-0.20.0.sha256sum] = "b07cc57d10cee4ec661f718a6902cee18c2f4cfae08e87e5a390525946913390"
-SRC_URI[pangocairo-0.20.0.sha256sum] = "902cd6e53493a475f4524e7b3f4c09ef60ee87c7be16f08f1b41882fc74dac46"
-SRC_URI[pangocairo-sys-0.20.0.sha256sum] = "bc23a5ea756e709ab1598f8446a64c799b10c99ec59aa2310965218bc1915853"
-SRC_URI[parking_lot-0.12.3.sha256sum] = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
-SRC_URI[parking_lot_core-0.9.10.sha256sum] = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
-SRC_URI[paste-1.0.15.sha256sum] = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
-SRC_URI[percent-encoding-2.3.1.sha256sum] = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
-SRC_URI[phf-0.10.1.sha256sum] = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
-SRC_URI[phf-0.11.2.sha256sum] = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
-SRC_URI[phf_codegen-0.10.0.sha256sum] = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
-SRC_URI[phf_codegen-0.11.2.sha256sum] = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
-SRC_URI[phf_generator-0.10.0.sha256sum] = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
-SRC_URI[phf_generator-0.11.2.sha256sum] = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
-SRC_URI[phf_macros-0.11.2.sha256sum] = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
-SRC_URI[phf_shared-0.10.0.sha256sum] = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
-SRC_URI[phf_shared-0.11.2.sha256sum] = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
-SRC_URI[pin-project-lite-0.2.14.sha256sum] = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
-SRC_URI[pin-utils-0.1.0.sha256sum] = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
-SRC_URI[pkg-config-0.3.30.sha256sum] = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
-SRC_URI[plotters-0.3.6.sha256sum] = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3"
-SRC_URI[plotters-backend-0.3.6.sha256sum] = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7"
-SRC_URI[plotters-svg-0.3.6.sha256sum] = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705"
-SRC_URI[png-0.17.13.sha256sum] = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
-SRC_URI[powerfmt-0.2.0.sha256sum] = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-SRC_URI[ppv-lite86-0.2.20.sha256sum] = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
-SRC_URI[precomputed-hash-0.1.1.sha256sum] = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
-SRC_URI[predicates-3.1.2.sha256sum] = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97"
-SRC_URI[predicates-core-1.0.8.sha256sum] = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931"
-SRC_URI[predicates-tree-1.0.11.sha256sum] = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13"
-SRC_URI[proc-macro-crate-3.1.0.sha256sum] = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
-SRC_URI[proc-macro2-1.0.86.sha256sum] = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
-SRC_URI[proptest-1.5.0.sha256sum] = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d"
-SRC_URI[quick-error-1.2.3.sha256sum] = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
-SRC_URI[quick-error-2.0.1.sha256sum] = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
-SRC_URI[quote-1.0.36.sha256sum] = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-SRC_URI[rand-0.8.5.sha256sum] = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-SRC_URI[rand_chacha-0.3.1.sha256sum] = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-SRC_URI[rand_core-0.6.4.sha256sum] = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-SRC_URI[rand_xorshift-0.3.0.sha256sum] = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
-SRC_URI[rawpointer-0.2.1.sha256sum] = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
-SRC_URI[rayon-1.10.0.sha256sum] = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
-SRC_URI[rayon-core-1.12.1.sha256sum] = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
-SRC_URI[rctree-0.6.0.sha256sum] = "e03e7866abec1101869ffa8e2c8355c4c2419d0214ece0cc3e428e5b94dea6e9"
-SRC_URI[redox_syscall-0.5.3.sha256sum] = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
-SRC_URI[regex-1.10.6.sha256sum] = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
-SRC_URI[regex-automata-0.4.7.sha256sum] = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
-SRC_URI[regex-syntax-0.8.4.sha256sum] = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
-SRC_URI[rgb-0.8.48.sha256sum] = "0f86ae463694029097b846d8f99fd5536740602ae00022c0c50c5600720b2f71"
-SRC_URI[rustix-0.38.34.sha256sum] = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
-SRC_URI[rusty-fork-0.3.0.sha256sum] = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
-SRC_URI[ryu-1.0.18.sha256sum] = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
-SRC_URI[safe_arch-0.7.2.sha256sum] = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a"
-SRC_URI[same-file-1.0.6.sha256sum] = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
-SRC_URI[scopeguard-1.2.0.sha256sum] = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
-SRC_URI[selectors-0.25.0.sha256sum] = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06"
-SRC_URI[serde-1.0.204.sha256sum] = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
-SRC_URI[serde_derive-1.0.204.sha256sum] = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
-SRC_URI[serde_json-1.0.122.sha256sum] = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
-SRC_URI[serde_spanned-0.6.7.sha256sum] = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
-SRC_URI[servo_arc-0.3.0.sha256sum] = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44"
-SRC_URI[shell-words-1.1.0.sha256sum] = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
-SRC_URI[simba-0.9.0.sha256sum] = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa"
-SRC_URI[simd-adler32-0.3.7.sha256sum] = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
-SRC_URI[siphasher-0.3.11.sha256sum] = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
-SRC_URI[slab-0.4.9.sha256sum] = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
-SRC_URI[smallvec-1.13.2.sha256sum] = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
-SRC_URI[stable_deref_trait-1.2.0.sha256sum] = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
-SRC_URI[static_assertions-1.1.0.sha256sum] = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
-SRC_URI[string_cache-0.8.7.sha256sum] = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
-SRC_URI[string_cache_codegen-0.5.2.sha256sum] = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
-SRC_URI[strsim-0.11.1.sha256sum] = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
-SRC_URI[syn-2.0.72.sha256sum] = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
-SRC_URI[system-deps-6.2.2.sha256sum] = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
-SRC_URI[system-deps-7.0.1.sha256sum] = "6c81f13d9a334a6c242465140bd262fae382b752ff2011c4f7419919a9c97922"
-SRC_URI[target-lexicon-0.12.16.sha256sum] = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
-SRC_URI[tempfile-3.12.0.sha256sum] = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
-SRC_URI[tendril-0.4.3.sha256sum] = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
-SRC_URI[termtree-0.4.1.sha256sum] = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
-SRC_URI[thiserror-1.0.63.sha256sum] = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
-SRC_URI[thiserror-impl-1.0.63.sha256sum] = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
-SRC_URI[time-0.3.36.sha256sum] = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
-SRC_URI[time-core-0.1.2.sha256sum] = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
-SRC_URI[time-macros-0.2.18.sha256sum] = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
-SRC_URI[tinytemplate-1.2.1.sha256sum] = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
-SRC_URI[tinyvec-1.8.0.sha256sum] = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
-SRC_URI[tinyvec_macros-0.1.1.sha256sum] = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
-SRC_URI[toml-0.8.19.sha256sum] = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
-SRC_URI[toml_datetime-0.6.8.sha256sum] = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
-SRC_URI[toml_edit-0.21.1.sha256sum] = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
-SRC_URI[toml_edit-0.22.20.sha256sum] = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
-SRC_URI[typenum-1.17.0.sha256sum] = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
-SRC_URI[unarray-0.1.4.sha256sum] = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
-SRC_URI[unicode-bidi-0.3.15.sha256sum] = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
-SRC_URI[unicode-ident-1.0.12.sha256sum] = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-SRC_URI[unicode-normalization-0.1.23.sha256sum] = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
-SRC_URI[url-2.5.2.sha256sum] = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
-SRC_URI[utf-8-0.7.6.sha256sum] = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
-SRC_URI[utf8parse-0.2.2.sha256sum] = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
-SRC_URI[version-compare-0.2.0.sha256sum] = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
-SRC_URI[version_check-0.9.5.sha256sum] = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
-SRC_URI[wait-timeout-0.2.0.sha256sum] = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
-SRC_URI[walkdir-2.5.0.sha256sum] = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
-SRC_URI[wasi-0.11.0+wasi-snapshot-preview1.sha256sum] = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-SRC_URI[wasm-bindgen-0.2.92.sha256sum] = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
-SRC_URI[wasm-bindgen-backend-0.2.92.sha256sum] = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
-SRC_URI[wasm-bindgen-macro-0.2.92.sha256sum] = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
-SRC_URI[wasm-bindgen-macro-support-0.2.92.sha256sum] = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
-SRC_URI[wasm-bindgen-shared-0.2.92.sha256sum] = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
-SRC_URI[web-sys-0.3.69.sha256sum] = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
-SRC_URI[weezl-0.1.8.sha256sum] = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
-SRC_URI[wide-0.7.26.sha256sum] = "901e8597c777fa042e9e245bd56c0dc4418c5db3f845b6ff94fbac732c6a0692"
-SRC_URI[winapi-0.3.9.sha256sum] = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-SRC_URI[winapi-i686-pc-windows-gnu-0.4.0.sha256sum] = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-SRC_URI[winapi-util-0.1.9.sha256sum] = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
-SRC_URI[winapi-x86_64-pc-windows-gnu-0.4.0.sha256sum] = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-SRC_URI[windows-core-0.52.0.sha256sum] = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
-SRC_URI[windows-sys-0.52.0.sha256sum] = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-SRC_URI[windows-sys-0.59.0.sha256sum] = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-SRC_URI[windows-targets-0.52.6.sha256sum] = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-SRC_URI[windows_aarch64_gnullvm-0.52.6.sha256sum] = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-SRC_URI[windows_aarch64_msvc-0.52.6.sha256sum] = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-SRC_URI[windows_i686_gnu-0.52.6.sha256sum] = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-SRC_URI[windows_i686_gnullvm-0.52.6.sha256sum] = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-SRC_URI[windows_i686_msvc-0.52.6.sha256sum] = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-SRC_URI[windows_x86_64_gnu-0.52.6.sha256sum] = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-SRC_URI[windows_x86_64_gnullvm-0.52.6.sha256sum] = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-SRC_URI[windows_x86_64_msvc-0.52.6.sha256sum] = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-SRC_URI[winnow-0.5.40.sha256sum] = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
-SRC_URI[winnow-0.6.18.sha256sum] = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
-SRC_URI[xml5ever-0.18.1.sha256sum] = "9bbb26405d8e919bc1547a5aa9abc95cbfa438f04844f5fdd9dc7596b748bf69"
-SRC_URI[yeslogic-fontconfig-sys-6.0.0.sha256sum] = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd"
-SRC_URI[zerocopy-0.7.35.sha256sum] = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
-SRC_URI[zerocopy-derive-0.7.35.sha256sum] = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
-SRC_URI[zune-core-0.4.12.sha256sum] = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
-SRC_URI[zune-jpeg-0.4.13.sha256sum] = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768"
diff --git a/meta/recipes-gnome/librsvg/librsvg_2.59.2.bb b/meta/recipes-gnome/librsvg/librsvg_2.59.2.bb
index 7718f2bb48..2bd8f7bf2b 100644
--- a/meta/recipes-gnome/librsvg/librsvg_2.59.2.bb
+++ b/meta/recipes-gnome/librsvg/librsvg_2.59.2.bb
@@ -14,15 +14,13 @@ SECTION = "x11/utils"
 DEPENDS = "cairo gdk-pixbuf glib-2.0 libxml2 pango python3-docutils-native cargo-c-native"
 BBCLASSEXTEND = "native nativesdk"
 
-inherit cargo_common gnomebase pixbufcache gobject-introspection rust vala gi-docgen cargo-update-recipe-crates
+inherit cargo_common gnomebase pixbufcache gobject-introspection rust vala gi-docgen vendor_cargo
 GIR_MESON_ENABLE_FLAG = 'enabled'
 GIR_MESON_DISABLE_FLAG = 'disabled'
 GIDOCGEN_MESON_OPTION = 'docs'
 GIDOCGEN_MESON_ENABLE_FLAG = 'enabled'
 GIDOCGEN_MESON_DISABLE_FLAG = 'disabled'
 
-require ${BPN}-crates.inc
-
 SRC_URI += "file://0001-meson.build-do-not-force-disable-introspection-and-v.patch \
             file://0001-gdk-pixbuf-loader-meson.build-do-not-look-for-gdk-pi.patch"
 SRC_URI[archive.sha256sum] = "ecd293fb0cc338c170171bbc7bcfbea6725d041c95f31385dc935409933e4597"
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 26/30] librsvg: update dependecies to fix RUSTSEC-2024-0421
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (24 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 25/30] librsvg: " Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 27/30] [DO NOT MERGE] recipes: add crucible go demo Stefan Herbrechtsmeier
                   ` (4 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 ...-to-get-an-updated-idna-rustsec-2024.patch | 398 ++++++++++++++++++
 meta/recipes-gnome/librsvg/librsvg_2.59.2.bb  |   3 +-
 2 files changed, 400 insertions(+), 1 deletion(-)
 create mode 100644 meta/recipes-gnome/librsvg/librsvg/0001-update-url-crate-to-get-an-updated-idna-rustsec-2024.patch

diff --git a/meta/recipes-gnome/librsvg/librsvg/0001-update-url-crate-to-get-an-updated-idna-rustsec-2024.patch b/meta/recipes-gnome/librsvg/librsvg/0001-update-url-crate-to-get-an-updated-idna-rustsec-2024.patch
new file mode 100644
index 0000000000..4f9796d0b9
--- /dev/null
+++ b/meta/recipes-gnome/librsvg/librsvg/0001-update-url-crate-to-get-an-updated-idna-rustsec-2024.patch
@@ -0,0 +1,398 @@
+From aaaa6b68b024b2adbfdf5f8493dfce1f60e5e331 Mon Sep 17 00:00:00 2001
+From: Federico Mena Quintero <federico@gnome.org>
+Date: Mon, 9 Dec 2024 13:26:02 -0600
+Subject: [PATCH] Update url crate to get an updated idna, RUSTSEC-2024-0421
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+error[vulnerability]: `idna` accepts Punycode labels that do not produce any non-ASCII when decoded
+   ┌─ /builds/GNOME/librsvg/Cargo.lock:99:1
+   │
+99 │ idna 0.5.0 registry+https://github.com/rust-lang/crates.io-index
+   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
+   │
+   ├ ID: RUSTSEC-2024-0421
+   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2024-0421
+
+Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/1069>
+
+CVE: RUSTSEC-2024-0421
+
+Upstream-Status: Backport [https://github.com/GNOME/librsvg/commit/aaaa6b68b024b2adbfdf5f8493dfce1f60e5e331]
+---
+ Cargo.lock | 285 +++++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 264 insertions(+), 21 deletions(-)
+
+diff --git a/Cargo.lock b/Cargo.lock
+index 1ee688577..01c3bf550 100644
+--- a/Cargo.lock
++++ b/Cargo.lock
+@@ -588,6 +588,17 @@ dependencies = [
+  "crypto-common",
+ ]
+ 
++[[package]]
++name = "displaydoc"
++version = "0.2.5"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
++dependencies = [
++ "proc-macro2",
++ "quote",
++ "syn",
++]
++
+ [[package]]
+ name = "dlib"
+ version = "0.5.2"
+@@ -992,14 +1003,143 @@ dependencies = [
+  "cc",
+ ]
+ 
++[[package]]
++name = "icu_collections"
++version = "1.5.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
++dependencies = [
++ "displaydoc",
++ "yoke",
++ "zerofrom",
++ "zerovec",
++]
++
++[[package]]
++name = "icu_locid"
++version = "1.5.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
++dependencies = [
++ "displaydoc",
++ "litemap",
++ "tinystr",
++ "writeable",
++ "zerovec",
++]
++
++[[package]]
++name = "icu_locid_transform"
++version = "1.5.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
++dependencies = [
++ "displaydoc",
++ "icu_locid",
++ "icu_locid_transform_data",
++ "icu_provider",
++ "tinystr",
++ "zerovec",
++]
++
++[[package]]
++name = "icu_locid_transform_data"
++version = "1.5.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
++
++[[package]]
++name = "icu_normalizer"
++version = "1.5.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
++dependencies = [
++ "displaydoc",
++ "icu_collections",
++ "icu_normalizer_data",
++ "icu_properties",
++ "icu_provider",
++ "smallvec",
++ "utf16_iter",
++ "utf8_iter",
++ "write16",
++ "zerovec",
++]
++
++[[package]]
++name = "icu_normalizer_data"
++version = "1.5.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
++
++[[package]]
++name = "icu_properties"
++version = "1.5.1"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
++dependencies = [
++ "displaydoc",
++ "icu_collections",
++ "icu_locid_transform",
++ "icu_properties_data",
++ "icu_provider",
++ "tinystr",
++ "zerovec",
++]
++
++[[package]]
++name = "icu_properties_data"
++version = "1.5.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
++
++[[package]]
++name = "icu_provider"
++version = "1.5.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
++dependencies = [
++ "displaydoc",
++ "icu_locid",
++ "icu_provider_macros",
++ "stable_deref_trait",
++ "tinystr",
++ "writeable",
++ "yoke",
++ "zerofrom",
++ "zerovec",
++]
++
++[[package]]
++name = "icu_provider_macros"
++version = "1.5.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
++dependencies = [
++ "proc-macro2",
++ "quote",
++ "syn",
++]
++
+ [[package]]
+ name = "idna"
+-version = "0.5.0"
++version = "1.0.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
++dependencies = [
++ "idna_adapter",
++ "smallvec",
++ "utf8_iter",
++]
++
++[[package]]
++name = "idna_adapter"
++version = "1.2.0"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
++checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+ dependencies = [
+- "unicode-bidi",
+- "unicode-normalization",
++ "icu_normalizer",
++ "icu_properties",
+ ]
+ 
+ [[package]]
+@@ -1229,6 +1369,12 @@ version = "0.4.14"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+ 
++[[package]]
++name = "litemap"
++version = "0.7.4"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
++
+ [[package]]
+ name = "locale_config"
+ version = "0.3.0"
+@@ -2258,6 +2404,17 @@ dependencies = [
+  "unicode-ident",
+ ]
+ 
++[[package]]
++name = "synstructure"
++version = "0.13.1"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
++dependencies = [
++ "proc-macro2",
++ "quote",
++ "syn",
++]
++
+ [[package]]
+ name = "system-deps"
+ version = "6.2.2"
+@@ -2371,6 +2528,16 @@ dependencies = [
+  "time-core",
+ ]
+ 
++[[package]]
++name = "tinystr"
++version = "0.7.6"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
++dependencies = [
++ "displaydoc",
++ "zerovec",
++]
++
+ [[package]]
+ name = "tinytemplate"
+ version = "1.2.1"
+@@ -2453,32 +2620,17 @@ version = "0.1.4"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
+ 
+-[[package]]
+-name = "unicode-bidi"
+-version = "0.3.15"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+-
+ [[package]]
+ name = "unicode-ident"
+ version = "1.0.12"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+ 
+-[[package]]
+-name = "unicode-normalization"
+-version = "0.1.23"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+-dependencies = [
+- "tinyvec",
+-]
+-
+ [[package]]
+ name = "url"
+-version = "2.5.2"
++version = "2.5.4"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
++checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+ dependencies = [
+  "form_urlencoded",
+  "idna",
+@@ -2491,6 +2643,18 @@ version = "0.7.6"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+ 
++[[package]]
++name = "utf16_iter"
++version = "1.0.5"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
++
++[[package]]
++name = "utf8_iter"
++version = "1.0.4"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
++
+ [[package]]
+ name = "utf8parse"
+ version = "0.2.2"
+@@ -2754,6 +2918,18 @@ dependencies = [
+  "memchr",
+ ]
+ 
++[[package]]
++name = "write16"
++version = "1.0.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
++
++[[package]]
++name = "writeable"
++version = "0.5.5"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
++
+ [[package]]
+ name = "xml5ever"
+ version = "0.18.1"
+@@ -2776,6 +2952,30 @@ dependencies = [
+  "pkg-config",
+ ]
+ 
++[[package]]
++name = "yoke"
++version = "0.7.5"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
++dependencies = [
++ "serde",
++ "stable_deref_trait",
++ "yoke-derive",
++ "zerofrom",
++]
++
++[[package]]
++name = "yoke-derive"
++version = "0.7.5"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
++dependencies = [
++ "proc-macro2",
++ "quote",
++ "syn",
++ "synstructure",
++]
++
+ [[package]]
+ name = "zerocopy"
+ version = "0.7.35"
+@@ -2797,6 +2997,49 @@ dependencies = [
+  "syn",
+ ]
+ 
++[[package]]
++name = "zerofrom"
++version = "0.1.5"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
++dependencies = [
++ "zerofrom-derive",
++]
++
++[[package]]
++name = "zerofrom-derive"
++version = "0.1.5"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
++dependencies = [
++ "proc-macro2",
++ "quote",
++ "syn",
++ "synstructure",
++]
++
++[[package]]
++name = "zerovec"
++version = "0.10.4"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
++dependencies = [
++ "yoke",
++ "zerofrom",
++ "zerovec-derive",
++]
++
++[[package]]
++name = "zerovec-derive"
++version = "0.10.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
++dependencies = [
++ "proc-macro2",
++ "quote",
++ "syn",
++]
++
+ [[package]]
+ name = "zune-core"
+ version = "0.4.12"
diff --git a/meta/recipes-gnome/librsvg/librsvg_2.59.2.bb b/meta/recipes-gnome/librsvg/librsvg_2.59.2.bb
index 2bd8f7bf2b..36aaaf20e8 100644
--- a/meta/recipes-gnome/librsvg/librsvg_2.59.2.bb
+++ b/meta/recipes-gnome/librsvg/librsvg_2.59.2.bb
@@ -22,7 +22,8 @@ GIDOCGEN_MESON_ENABLE_FLAG = 'enabled'
 GIDOCGEN_MESON_DISABLE_FLAG = 'disabled'
 
 SRC_URI += "file://0001-meson.build-do-not-force-disable-introspection-and-v.patch \
-            file://0001-gdk-pixbuf-loader-meson.build-do-not-look-for-gdk-pi.patch"
+            file://0001-gdk-pixbuf-loader-meson.build-do-not-look-for-gdk-pi.patch \
+            file://0001-update-url-crate-to-get-an-updated-idna-rustsec-2024.patch;early=1"
 SRC_URI[archive.sha256sum] = "ecd293fb0cc338c170171bbc7bcfbea6725d041c95f31385dc935409933e4597"
 
 UPSTREAM_CHECK_REGEX = "librsvg-(?P<pver>\d+\.\d+\.(?!9\d+)\d+)"
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 27/30] [DO NOT MERGE] recipes: add crucible go demo
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (25 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 26/30] librsvg: update dependecies to fix RUSTSEC-2024-0421 Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 28/30] [DO NOT MERGE] recipes: add node-red npm demo Stefan Herbrechtsmeier
                   ` (3 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 .../crucible/crucible2_2023.11.02.bb           | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 meta-selftest/recipes-support/crucible/crucible2_2023.11.02.bb

diff --git a/meta-selftest/recipes-support/crucible/crucible2_2023.11.02.bb b/meta-selftest/recipes-support/crucible/crucible2_2023.11.02.bb
new file mode 100644
index 0000000000..353c5ad835
--- /dev/null
+++ b/meta-selftest/recipes-support/crucible/crucible2_2023.11.02.bb
@@ -0,0 +1,18 @@
+SUMMARY = "Utility that provides userspace support for reading and writing to the i.MX fuses"
+
+LICENSE = "BSD-3-Clause"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=201414b6610203caed355323b1ab3116"
+
+SRC_URI = "git://${GO_IMPORT}.git;protocol=https;branch=master"
+
+SRCREV = "dec27cd4e0e0db106c0a21d429c04ca8d36bbdd5"
+
+S = "${WORKDIR}/git"
+
+GO_IMPORT = "github.com/usbarmory/crucible"
+GO_INSTALL = "\
+    ./cmd/crucible \
+    ./cmd/habtool \
+"
+
+inherit vendor_go
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 28/30] [DO NOT MERGE] recipes: add node-red npm demo
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (26 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 27/30] [DO NOT MERGE] recipes: add crucible go demo Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 29/30] [DO NOT MERGE] recipes: add nucleoidai " Stefan Herbrechtsmeier
                   ` (2 subsequent siblings)
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 .../node-red/node-red/package-lock.json       | 6096 +++++++++++++++++
 .../node-red/node-red_4.0.8.bb                |   14 +
 2 files changed, 6110 insertions(+)
 create mode 100644 meta-selftest/recipes-support/node-red/node-red/package-lock.json
 create mode 100644 meta-selftest/recipes-support/node-red/node-red_4.0.8.bb

diff --git a/meta-selftest/recipes-support/node-red/node-red/package-lock.json b/meta-selftest/recipes-support/node-red/node-red/package-lock.json
new file mode 100644
index 0000000000..8da0cd6a8f
--- /dev/null
+++ b/meta-selftest/recipes-support/node-red/node-red/package-lock.json
@@ -0,0 +1,6096 @@
+{
+    "name": "node-red",
+    "version": "4.0.8",
+    "lockfileVersion": 2,
+    "requires": true,
+    "packages": {
+        "": {
+            "name": "node-red",
+            "version": "4.0.8",
+            "license": "Apache-2.0",
+            "dependencies": {
+                "@node-red/editor-api": "4.0.8",
+                "@node-red/nodes": "4.0.8",
+                "@node-red/runtime": "4.0.8",
+                "@node-red/util": "4.0.8",
+                "basic-auth": "2.0.1",
+                "bcryptjs": "2.4.3",
+                "cors": "2.8.5",
+                "express": "4.21.2",
+                "fs-extra": "11.2.0",
+                "node-red-admin": "^4.0.1",
+                "nopt": "5.0.0",
+                "semver": "7.6.3"
+            },
+            "bin": {
+                "node-red": "red.js",
+                "node-red-pi": "bin/node-red-pi"
+            },
+            "engines": {
+                "node": ">=18.5"
+            },
+            "optionalDependencies": {
+                "@node-rs/bcrypt": "1.10.4"
+            }
+        },
+        "node_modules/@babel/runtime": {
+            "version": "7.26.0",
+            "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
+            "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
+            "dependencies": {
+                "regenerator-runtime": "^0.14.0"
+            },
+            "engines": {
+                "node": ">=6.9.0"
+            }
+        },
+        "node_modules/@emnapi/core": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz",
+            "integrity": "sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==",
+            "optional": true,
+            "dependencies": {
+                "@emnapi/wasi-threads": "1.0.1",
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/@emnapi/runtime": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz",
+            "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==",
+            "optional": true,
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/@emnapi/wasi-threads": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz",
+            "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==",
+            "optional": true,
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "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==",
+            "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/ansi-regex": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+            "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+            }
+        },
+        "node_modules/@isaacs/cliui/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==",
+            "dependencies": {
+                "ansi-regex": "^6.0.1"
+            },
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/strip-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==",
+            "dependencies": {
+                "minipass": "^7.0.4"
+            },
+            "engines": {
+                "node": ">=18.0.0"
+            }
+        },
+        "node_modules/@napi-rs/wasm-runtime": {
+            "version": "0.2.6",
+            "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.6.tgz",
+            "integrity": "sha512-z8YVS3XszxFTO73iwvFDNpQIzdMmSDTP/mB3E/ucR37V3Sx57hSExcXyMoNwaucWxnsWf4xfbZv0iZ30jr0M4Q==",
+            "optional": true,
+            "dependencies": {
+                "@emnapi/core": "^1.3.1",
+                "@emnapi/runtime": "^1.3.1",
+                "@tybys/wasm-util": "^0.9.0"
+            }
+        },
+        "node_modules/@node-red/editor-api": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/editor-api/-/editor-api-4.0.8.tgz",
+            "integrity": "sha512-ngsyd/Ro5oyefE+jCJa43fU9WLIGWFkTvifTheU9fj+epSgCGHQLLMOoEvs4FKOaPJ8L4dAqHgD/kik9c73rdg==",
+            "dependencies": {
+                "@node-red/editor-client": "4.0.8",
+                "@node-red/util": "4.0.8",
+                "bcryptjs": "2.4.3",
+                "body-parser": "1.20.3",
+                "clone": "2.1.2",
+                "cors": "2.8.5",
+                "express": "4.21.2",
+                "express-session": "1.18.1",
+                "memorystore": "1.6.7",
+                "mime": "3.0.0",
+                "multer": "1.4.5-lts.1",
+                "mustache": "4.2.0",
+                "oauth2orize": "1.12.0",
+                "passport": "0.7.0",
+                "passport-http-bearer": "1.0.1",
+                "passport-oauth2-client-password": "0.1.2",
+                "ws": "7.5.10"
+            },
+            "optionalDependencies": {
+                "@node-rs/bcrypt": "1.10.4"
+            }
+        },
+        "node_modules/@node-red/editor-client": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/editor-client/-/editor-client-4.0.8.tgz",
+            "integrity": "sha512-LQI24xhXio4iftiiAvZ191Zjo9N1MsD0563aHGwsqGaLKxCTfOa+G1t5LslQoYGf0qMcYusf6Nftc2+5Q4nf/g=="
+        },
+        "node_modules/@node-red/nodes": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/nodes/-/nodes-4.0.8.tgz",
+            "integrity": "sha512-DAj0DyImWZ6lJo7D0LS/tFntkCEiUMAMMKBkyZjOudGLhxppaa99uzcDgQnSkM9vLSU1Uczxc9zHDY3RhxIpdA==",
+            "dependencies": {
+                "acorn": "8.12.1",
+                "acorn-walk": "8.3.4",
+                "ajv": "8.17.1",
+                "body-parser": "1.20.3",
+                "cheerio": "1.0.0-rc.10",
+                "content-type": "1.0.5",
+                "cookie": "0.7.2",
+                "cookie-parser": "1.4.7",
+                "cors": "2.8.5",
+                "cronosjs": "1.7.1",
+                "denque": "2.1.0",
+                "form-data": "4.0.0",
+                "fs-extra": "11.2.0",
+                "got": "12.6.1",
+                "hash-sum": "2.0.0",
+                "hpagent": "1.2.0",
+                "https-proxy-agent": "5.0.1",
+                "iconv-lite": "0.6.3",
+                "is-utf8": "0.2.1",
+                "js-yaml": "4.1.0",
+                "media-typer": "1.1.0",
+                "mqtt": "5.7.0",
+                "multer": "1.4.5-lts.1",
+                "mustache": "4.2.0",
+                "node-watch": "0.7.4",
+                "on-headers": "1.0.2",
+                "raw-body": "3.0.0",
+                "tough-cookie": "^5.0.0",
+                "uuid": "9.0.1",
+                "ws": "7.5.10",
+                "xml2js": "0.6.2"
+            }
+        },
+        "node_modules/@node-red/registry": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/registry/-/registry-4.0.8.tgz",
+            "integrity": "sha512-yZLeMi4crXehsU5VZ9l/TpU9gzVijFlxykDiUB//errA415sdtMMk02yKq+yZVlRyBPAhQRkL97t4/Y3wcWJog==",
+            "dependencies": {
+                "@node-red/util": "4.0.8",
+                "clone": "2.1.2",
+                "fs-extra": "11.2.0",
+                "semver": "7.6.3",
+                "tar": "7.4.3",
+                "uglify-js": "3.17.4"
+            }
+        },
+        "node_modules/@node-red/runtime": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/runtime/-/runtime-4.0.8.tgz",
+            "integrity": "sha512-TYYyDytZr4nYJgkAKwDduCUjOMrIorUnn28aSorHgWCVJEdlllJAbBQgrdDJm6GGqsDNx2iFwmVbgKC3PJbTKg==",
+            "dependencies": {
+                "@node-red/registry": "4.0.8",
+                "@node-red/util": "4.0.8",
+                "async-mutex": "0.5.0",
+                "clone": "2.1.2",
+                "express": "4.21.2",
+                "fs-extra": "11.2.0",
+                "json-stringify-safe": "5.0.1",
+                "rfdc": "^1.3.1"
+            }
+        },
+        "node_modules/@node-red/util": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/util/-/util-4.0.8.tgz",
+            "integrity": "sha512-Kl2e4i+Oryq5waTMYvY3ntrQtMfy4+hRTMmeXwpkdCa27DTnWfz0grJHIfy0k9F97K7S47gKFOpR6EjRCm0mWw==",
+            "dependencies": {
+                "fs-extra": "11.2.0",
+                "i18next": "21.10.0",
+                "json-stringify-safe": "5.0.1",
+                "jsonata": "2.0.5",
+                "lodash.clonedeep": "^4.5.0",
+                "moment": "2.30.1",
+                "moment-timezone": "0.5.46"
+            }
+        },
+        "node_modules/@node-rs/bcrypt": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt/-/bcrypt-1.10.4.tgz",
+            "integrity": "sha512-Kzs8HKt2eBeT5VnkeKgiz/QKTjOO3URcvSNEQZahNwZnL6dBeeJQTxxYisc/6969+5n6c3+gNwKvqJsZzmGe7g==",
+            "optional": true,
+            "engines": {
+                "node": ">= 10"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/Brooooooklyn"
+            },
+            "optionalDependencies": {
+                "@node-rs/bcrypt-android-arm-eabi": "1.10.4",
+                "@node-rs/bcrypt-android-arm64": "1.10.4",
+                "@node-rs/bcrypt-darwin-arm64": "1.10.4",
+                "@node-rs/bcrypt-darwin-x64": "1.10.4",
+                "@node-rs/bcrypt-freebsd-x64": "1.10.4",
+                "@node-rs/bcrypt-linux-arm-gnueabihf": "1.10.4",
+                "@node-rs/bcrypt-linux-arm64-gnu": "1.10.4",
+                "@node-rs/bcrypt-linux-arm64-musl": "1.10.4",
+                "@node-rs/bcrypt-linux-x64-gnu": "1.10.4",
+                "@node-rs/bcrypt-linux-x64-musl": "1.10.4",
+                "@node-rs/bcrypt-wasm32-wasi": "1.10.4",
+                "@node-rs/bcrypt-win32-arm64-msvc": "1.10.4",
+                "@node-rs/bcrypt-win32-ia32-msvc": "1.10.4",
+                "@node-rs/bcrypt-win32-x64-msvc": "1.10.4"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-android-arm-eabi": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm-eabi/-/bcrypt-android-arm-eabi-1.10.4.tgz",
+            "integrity": "sha512-55ajutuTdfK1hKseyliflnxzNtxszQQ/EoLtgJlgCe7rI24vGP9EEEZDznB/u9OaJ14/AYzZtIhkEOYdbIdw0A==",
+            "cpu": [
+                "arm"
+            ],
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-android-arm64": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm64/-/bcrypt-android-arm64-1.10.4.tgz",
+            "integrity": "sha512-dCgQT7nH65tORmJw2hQ6zQgFmmC+/JBYZUWtf7pPZI76AVAn5tc7cIUrxYoV4OT1+uD63b9Av+mS1fT2EPzWEg==",
+            "cpu": [
+                "arm64"
+            ],
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-darwin-arm64": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-arm64/-/bcrypt-darwin-arm64-1.10.4.tgz",
+            "integrity": "sha512-gmHdWikHL3YVZgqXAHT+X/PG+kqIyNlPeFAWKdby83RkDI8FUiPV4qqGilgNnBmVWKkobRae9/I1HDbc4Sbhyg==",
+            "cpu": [
+                "arm64"
+            ],
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-darwin-x64": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-x64/-/bcrypt-darwin-x64-1.10.4.tgz",
+            "integrity": "sha512-WDzL1WKRtoyTkH6IMPx95Mkd6XaeN0VWJbSDMqQY6AFBOk03yJEj7YYXshCcF+Ur6KBBVSwRf6sdFJ15NI1Z3g==",
+            "cpu": [
+                "x64"
+            ],
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-freebsd-x64": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-freebsd-x64/-/bcrypt-freebsd-x64-1.10.4.tgz",
+            "integrity": "sha512-seSPJi+4MIUd1faL/n/wmDdDwaynd/FTkvTnb7qzCk8LBT+/dxi7MTz+uaD8KYDREcB9Wmhv+lwr0S9/jBTcjg==",
+            "cpu": [
+                "x64"
+            ],
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-linux-arm-gnueabihf": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm-gnueabihf/-/bcrypt-linux-arm-gnueabihf-1.10.4.tgz",
+            "integrity": "sha512-YcMLUtN9cGNTWKnaXslxGO1M0S5b4QN9KYhuyG6Kju27RfqvU5UbmpKElCsEUO2EIjxGwzvPu59T+Fyh6sVbwg==",
+            "cpu": [
+                "arm"
+            ],
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-linux-arm64-gnu": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-gnu/-/bcrypt-linux-arm64-gnu-1.10.4.tgz",
+            "integrity": "sha512-uYGUK/mO8SiftqmVSAePWxgK82vg+X/gtrVRJi95yq2iwp1+fYJX3ndxCyYPmeplBbd3NJ/F5lPT3FC/IHTTGw==",
+            "cpu": [
+                "arm64"
+            ],
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-linux-arm64-musl": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-musl/-/bcrypt-linux-arm64-musl-1.10.4.tgz",
+            "integrity": "sha512-rLvSMW/gVUBd2k2gAqQfuOReHWd9+jvz58E3i1TbkRE3a5ChvjOFc9qKPEmXuXuD9Mdj7gUwcYwpq8MdB5MtNw==",
+            "cpu": [
+                "arm64"
+            ],
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-linux-x64-gnu": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-gnu/-/bcrypt-linux-x64-gnu-1.10.4.tgz",
+            "integrity": "sha512-I++6bh+BIp70X/D/crlSgCq8K0s9nGvzmvAGFkqSG4h3LBtjJx4RKbygnoWvcBV9ErK1rvcjfMyjwZt1ukueFA==",
+            "cpu": [
+                "x64"
+            ],
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-linux-x64-musl": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-musl/-/bcrypt-linux-x64-musl-1.10.4.tgz",
+            "integrity": "sha512-f9RPl/5n2NS0mMJXB4IYbodKnq5HzOK5x1b9eKbcjsY0rw3mJC3K0XRFc8iaw1a5chA+xV1TPXz5mkykmr2CQQ==",
+            "cpu": [
+                "x64"
+            ],
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-wasm32-wasi": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-wasm32-wasi/-/bcrypt-wasm32-wasi-1.10.4.tgz",
+            "integrity": "sha512-VaDOf+wic0yoHFimMkC5VMa/33BNqg6ieD+C/ibb7Av3NnVW4/W9YpDpqAWMR2w3fA40uTLWZ7FZSrcFck27oA==",
+            "cpu": [
+                "wasm32"
+            ],
+            "optional": true,
+            "dependencies": {
+                "@napi-rs/wasm-runtime": "^0.2.3"
+            },
+            "engines": {
+                "node": ">=14.0.0"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-win32-arm64-msvc": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-arm64-msvc/-/bcrypt-win32-arm64-msvc-1.10.4.tgz",
+            "integrity": "sha512-M7sGnbKPvhYJ5b76ywXiEwR4mIs/JSDHjRrhm9fshKAvltQrwc3Mou22TJggvDN3gKOF1W85uPiM2OgGX/jxMg==",
+            "cpu": [
+                "arm64"
+            ],
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-win32-ia32-msvc": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-ia32-msvc/-/bcrypt-win32-ia32-msvc-1.10.4.tgz",
+            "integrity": "sha512-zn/n4DYnuOfC2JgmVDa0JHP+5DUqAOTl2jmV3yrMrmN+StDT4Om5wtvWxvEmgv3CkeZAuAU3Y/fwjSXIpZ0Fhg==",
+            "cpu": [
+                "ia32"
+            ],
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "node_modules/@node-rs/bcrypt-win32-x64-msvc": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-x64-msvc/-/bcrypt-win32-x64-msvc-1.10.4.tgz",
+            "integrity": "sha512-ynQokTTGbuLu/cckaD8dNcE+Zsfam1zElE+teNol8AxcL7Jv+ghJItSnRthPRV/vLxuycDF2DIICgpXG/p9jrQ==",
+            "cpu": [
+                "x64"
+            ],
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10"
+            }
+        },
+        "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==",
+            "optional": true,
+            "engines": {
+                "node": ">=14"
+            }
+        },
+        "node_modules/@sindresorhus/is": {
+            "version": "5.6.0",
+            "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz",
+            "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==",
+            "engines": {
+                "node": ">=14.16"
+            },
+            "funding": {
+                "url": "https://github.com/sindresorhus/is?sponsor=1"
+            }
+        },
+        "node_modules/@szmarczak/http-timer": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
+            "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
+            "dependencies": {
+                "defer-to-connect": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=14.16"
+            }
+        },
+        "node_modules/@tybys/wasm-util": {
+            "version": "0.9.0",
+            "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz",
+            "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==",
+            "optional": true,
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/@types/http-cache-semantics": {
+            "version": "4.0.4",
+            "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
+            "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="
+        },
+        "node_modules/@types/node": {
+            "version": "22.10.7",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz",
+            "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==",
+            "dependencies": {
+                "undici-types": "~6.20.0"
+            }
+        },
+        "node_modules/@types/readable-stream": {
+            "version": "4.0.18",
+            "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.18.tgz",
+            "integrity": "sha512-21jK/1j+Wg+7jVw1xnSwy/2Q1VgVjWuFssbYGTREPUBeZ+rqVFl2udq0IkxzPC0ZhOzVceUbyIACFZKLqKEBlA==",
+            "dependencies": {
+                "@types/node": "*",
+                "safe-buffer": "~5.1.1"
+            }
+        },
+        "node_modules/@types/ws": {
+            "version": "8.5.13",
+            "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz",
+            "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==",
+            "dependencies": {
+                "@types/node": "*"
+            }
+        },
+        "node_modules/abbrev": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+            "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+        },
+        "node_modules/abort-controller": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+            "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+            "dependencies": {
+                "event-target-shim": "^5.0.0"
+            },
+            "engines": {
+                "node": ">=6.5"
+            }
+        },
+        "node_modules/accepts": {
+            "version": "1.3.8",
+            "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+            "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+            "dependencies": {
+                "mime-types": "~2.1.34",
+                "negotiator": "0.6.3"
+            },
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/acorn": {
+            "version": "8.12.1",
+            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+            "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
+            "bin": {
+                "acorn": "bin/acorn"
+            },
+            "engines": {
+                "node": ">=0.4.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==",
+            "dependencies": {
+                "acorn": "^8.11.0"
+            },
+            "engines": {
+                "node": ">=0.4.0"
+            }
+        },
+        "node_modules/agent-base": {
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+            "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+            "dependencies": {
+                "debug": "4"
+            },
+            "engines": {
+                "node": ">= 6.0.0"
+            }
+        },
+        "node_modules/agent-base/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==",
+            "dependencies": {
+                "ms": "^2.1.3"
+            },
+            "engines": {
+                "node": ">=6.0"
+            },
+            "peerDependenciesMeta": {
+                "supports-color": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/agent-base/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=="
+        },
+        "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==",
+            "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/ansi-colors": {
+            "version": "4.1.3",
+            "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+            "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+            "engines": {
+                "node": ">=6"
+            }
+        },
+        "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==",
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "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==",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+            }
+        },
+        "node_modules/append-field": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
+            "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
+        },
+        "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=="
+        },
+        "node_modules/array-flatten": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+            "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+        },
+        "node_modules/async-mutex": {
+            "version": "0.5.0",
+            "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz",
+            "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==",
+            "dependencies": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "node_modules/asynckit": {
+            "version": "0.4.0",
+            "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+            "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+        },
+        "node_modules/axios": {
+            "version": "1.7.9",
+            "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
+            "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
+            "dependencies": {
+                "follow-redirects": "^1.15.6",
+                "form-data": "^4.0.0",
+                "proxy-from-env": "^1.1.0"
+            }
+        },
+        "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=="
+        },
+        "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"
+                }
+            ]
+        },
+        "node_modules/basic-auth": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+            "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+            "dependencies": {
+                "safe-buffer": "5.1.2"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/bcryptjs": {
+            "version": "2.4.3",
+            "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
+            "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="
+        },
+        "node_modules/bl": {
+            "version": "6.0.18",
+            "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.18.tgz",
+            "integrity": "sha512-2k76XmWCuvu9HTvu3tFOl5HDdCH0wLZ/jHYva/LBVJmc9oX8yUtNQjxrFmbTdXsCSmIxwVTANZPNDfMQrvHFUw==",
+            "dependencies": {
+                "@types/readable-stream": "^4.0.0",
+                "buffer": "^6.0.3",
+                "inherits": "^2.0.4",
+                "readable-stream": "^4.2.0"
+            }
+        },
+        "node_modules/body-parser": {
+            "version": "1.20.3",
+            "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+            "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+            "dependencies": {
+                "bytes": "3.1.2",
+                "content-type": "~1.0.5",
+                "debug": "2.6.9",
+                "depd": "2.0.0",
+                "destroy": "1.2.0",
+                "http-errors": "2.0.0",
+                "iconv-lite": "0.4.24",
+                "on-finished": "2.4.1",
+                "qs": "6.13.0",
+                "raw-body": "2.5.2",
+                "type-is": "~1.6.18",
+                "unpipe": "1.0.0"
+            },
+            "engines": {
+                "node": ">= 0.8",
+                "npm": "1.2.8000 || >= 1.4.16"
+            }
+        },
+        "node_modules/body-parser/node_modules/iconv-lite": {
+            "version": "0.4.24",
+            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+            "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+            "dependencies": {
+                "safer-buffer": ">= 2.1.2 < 3"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/body-parser/node_modules/raw-body": {
+            "version": "2.5.2",
+            "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+            "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+            "dependencies": {
+                "bytes": "3.1.2",
+                "http-errors": "2.0.0",
+                "iconv-lite": "0.4.24",
+                "unpipe": "1.0.0"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/boolbase": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+            "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
+        },
+        "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==",
+            "dependencies": {
+                "balanced-match": "^1.0.0"
+            }
+        },
+        "node_modules/buffer": {
+            "version": "6.0.3",
+            "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+            "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/feross"
+                },
+                {
+                    "type": "patreon",
+                    "url": "https://www.patreon.com/feross"
+                },
+                {
+                    "type": "consulting",
+                    "url": "https://feross.org/support"
+                }
+            ],
+            "dependencies": {
+                "base64-js": "^1.3.1",
+                "ieee754": "^1.2.1"
+            }
+        },
+        "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=="
+        },
+        "node_modules/busboy": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+            "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+            "dependencies": {
+                "streamsearch": "^1.1.0"
+            },
+            "engines": {
+                "node": ">=10.16.0"
+            }
+        },
+        "node_modules/bytes": {
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+            "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/cacheable-lookup": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
+            "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==",
+            "engines": {
+                "node": ">=14.16"
+            }
+        },
+        "node_modules/cacheable-request": {
+            "version": "10.2.14",
+            "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz",
+            "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==",
+            "dependencies": {
+                "@types/http-cache-semantics": "^4.0.2",
+                "get-stream": "^6.0.1",
+                "http-cache-semantics": "^4.1.1",
+                "keyv": "^4.5.3",
+                "mimic-response": "^4.0.0",
+                "normalize-url": "^8.0.0",
+                "responselike": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=14.16"
+            }
+        },
+        "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==",
+            "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==",
+            "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/cheerio": {
+            "version": "1.0.0-rc.10",
+            "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
+            "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==",
+            "dependencies": {
+                "cheerio-select": "^1.5.0",
+                "dom-serializer": "^1.3.2",
+                "domhandler": "^4.2.0",
+                "htmlparser2": "^6.1.0",
+                "parse5": "^6.0.1",
+                "parse5-htmlparser2-tree-adapter": "^6.0.1",
+                "tslib": "^2.2.0"
+            },
+            "engines": {
+                "node": ">= 6"
+            },
+            "funding": {
+                "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+            }
+        },
+        "node_modules/cheerio-select": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz",
+            "integrity": "sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==",
+            "dependencies": {
+                "css-select": "^4.3.0",
+                "css-what": "^6.0.1",
+                "domelementtype": "^2.2.0",
+                "domhandler": "^4.3.1",
+                "domutils": "^2.8.0"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/fb55"
+            }
+        },
+        "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==",
+            "engines": {
+                "node": ">=18"
+            }
+        },
+        "node_modules/cli-table": {
+            "version": "0.3.11",
+            "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz",
+            "integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==",
+            "dependencies": {
+                "colors": "1.0.3"
+            },
+            "engines": {
+                "node": ">= 0.2.0"
+            }
+        },
+        "node_modules/clone": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+            "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+            "engines": {
+                "node": ">=0.8"
+            }
+        },
+        "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==",
+            "dependencies": {
+                "color-name": "~1.1.4"
+            },
+            "engines": {
+                "node": ">=7.0.0"
+            }
+        },
+        "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=="
+        },
+        "node_modules/colors": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+            "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==",
+            "engines": {
+                "node": ">=0.1.90"
+            }
+        },
+        "node_modules/combined-stream": {
+            "version": "1.0.8",
+            "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+            "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+            "dependencies": {
+                "delayed-stream": "~1.0.0"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/commist": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
+            "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw=="
+        },
+        "node_modules/concat-stream": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+            "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+            "engines": [
+                "node >= 6.0"
+            ],
+            "dependencies": {
+                "buffer-from": "^1.0.0",
+                "inherits": "^2.0.3",
+                "readable-stream": "^3.0.2",
+                "typedarray": "^0.0.6"
+            }
+        },
+        "node_modules/concat-stream/node_modules/readable-stream": {
+            "version": "3.6.2",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+            "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+            "dependencies": {
+                "inherits": "^2.0.3",
+                "string_decoder": "^1.1.1",
+                "util-deprecate": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 6"
+            }
+        },
+        "node_modules/content-disposition": {
+            "version": "0.5.4",
+            "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+            "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+            "dependencies": {
+                "safe-buffer": "5.2.1"
+            },
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/content-disposition/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==",
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/feross"
+                },
+                {
+                    "type": "patreon",
+                    "url": "https://www.patreon.com/feross"
+                },
+                {
+                    "type": "consulting",
+                    "url": "https://feross.org/support"
+                }
+            ]
+        },
+        "node_modules/content-type": {
+            "version": "1.0.5",
+            "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+            "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/cookie": {
+            "version": "0.7.2",
+            "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+            "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/cookie-parser": {
+            "version": "1.4.7",
+            "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+            "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
+            "dependencies": {
+                "cookie": "0.7.2",
+                "cookie-signature": "1.0.6"
+            },
+            "engines": {
+                "node": ">= 0.8.0"
+            }
+        },
+        "node_modules/cookie-signature": {
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+            "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+        },
+        "node_modules/core-util-is": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+            "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+        },
+        "node_modules/cors": {
+            "version": "2.8.5",
+            "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+            "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+            "dependencies": {
+                "object-assign": "^4",
+                "vary": "^1"
+            },
+            "engines": {
+                "node": ">= 0.10"
+            }
+        },
+        "node_modules/cronosjs": {
+            "version": "1.7.1",
+            "resolved": "https://registry.npmjs.org/cronosjs/-/cronosjs-1.7.1.tgz",
+            "integrity": "sha512-d6S6+ep7dJxsAG8OQQCdKuByI/S/AV64d9OF5mtmcykOyPu92cAkAnF3Tbc9s5oOaLQBYYQmTNvjqYRkPJ/u5Q==",
+            "engines": {
+                "node": ">=8.0.0"
+            }
+        },
+        "node_modules/cross-spawn": {
+            "version": "7.0.6",
+            "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+            "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+            "dependencies": {
+                "path-key": "^3.1.0",
+                "shebang-command": "^2.0.0",
+                "which": "^2.0.1"
+            },
+            "engines": {
+                "node": ">= 8"
+            }
+        },
+        "node_modules/css-select": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+            "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
+            "dependencies": {
+                "boolbase": "^1.0.0",
+                "css-what": "^6.0.1",
+                "domhandler": "^4.3.1",
+                "domutils": "^2.8.0",
+                "nth-check": "^2.0.1"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/fb55"
+            }
+        },
+        "node_modules/css-what": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+            "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+            "engines": {
+                "node": ">= 6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/fb55"
+            }
+        },
+        "node_modules/debug": {
+            "version": "2.6.9",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+            "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+            "dependencies": {
+                "ms": "2.0.0"
+            }
+        },
+        "node_modules/decompress-response": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+            "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+            "dependencies": {
+                "mimic-response": "^3.1.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/decompress-response/node_modules/mimic-response": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+            "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/defer-to-connect": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+            "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/delayed-stream": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+            "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+            "engines": {
+                "node": ">=0.4.0"
+            }
+        },
+        "node_modules/denque": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+            "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
+            "engines": {
+                "node": ">=0.10"
+            }
+        },
+        "node_modules/depd": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+            "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/destroy": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+            "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+            "engines": {
+                "node": ">= 0.8",
+                "npm": "1.2.8000 || >= 1.4.16"
+            }
+        },
+        "node_modules/dom-serializer": {
+            "version": "1.4.1",
+            "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+            "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+            "dependencies": {
+                "domelementtype": "^2.0.1",
+                "domhandler": "^4.2.0",
+                "entities": "^2.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+            }
+        },
+        "node_modules/domelementtype": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+            "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/fb55"
+                }
+            ]
+        },
+        "node_modules/domhandler": {
+            "version": "4.3.1",
+            "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+            "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+            "dependencies": {
+                "domelementtype": "^2.2.0"
+            },
+            "engines": {
+                "node": ">= 4"
+            },
+            "funding": {
+                "url": "https://github.com/fb55/domhandler?sponsor=1"
+            }
+        },
+        "node_modules/domutils": {
+            "version": "2.8.0",
+            "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+            "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+            "dependencies": {
+                "dom-serializer": "^1.0.1",
+                "domelementtype": "^2.2.0",
+                "domhandler": "^4.2.0"
+            },
+            "funding": {
+                "url": "https://github.com/fb55/domutils?sponsor=1"
+            }
+        },
+        "node_modules/dunder-proto": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+            "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+            "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=="
+        },
+        "node_modules/ee-first": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+            "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+        },
+        "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=="
+        },
+        "node_modules/encodeurl": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+            "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/enquirer": {
+            "version": "2.4.1",
+            "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
+            "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
+            "dependencies": {
+                "ansi-colors": "^4.1.1",
+                "strip-ansi": "^6.0.1"
+            },
+            "engines": {
+                "node": ">=8.6"
+            }
+        },
+        "node_modules/entities": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+            "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+            "funding": {
+                "url": "https://github.com/fb55/entities?sponsor=1"
+            }
+        },
+        "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==",
+            "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==",
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "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==",
+            "dependencies": {
+                "es-errors": "^1.3.0"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/escape-html": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+            "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+        },
+        "node_modules/etag": {
+            "version": "1.8.1",
+            "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+            "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/event-target-shim": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+            "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+            "engines": {
+                "node": ">=6"
+            }
+        },
+        "node_modules/events": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+            "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+            "engines": {
+                "node": ">=0.8.x"
+            }
+        },
+        "node_modules/express": {
+            "version": "4.21.2",
+            "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+            "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
+            "dependencies": {
+                "accepts": "~1.3.8",
+                "array-flatten": "1.1.1",
+                "body-parser": "1.20.3",
+                "content-disposition": "0.5.4",
+                "content-type": "~1.0.4",
+                "cookie": "0.7.1",
+                "cookie-signature": "1.0.6",
+                "debug": "2.6.9",
+                "depd": "2.0.0",
+                "encodeurl": "~2.0.0",
+                "escape-html": "~1.0.3",
+                "etag": "~1.8.1",
+                "finalhandler": "1.3.1",
+                "fresh": "0.5.2",
+                "http-errors": "2.0.0",
+                "merge-descriptors": "1.0.3",
+                "methods": "~1.1.2",
+                "on-finished": "2.4.1",
+                "parseurl": "~1.3.3",
+                "path-to-regexp": "0.1.12",
+                "proxy-addr": "~2.0.7",
+                "qs": "6.13.0",
+                "range-parser": "~1.2.1",
+                "safe-buffer": "5.2.1",
+                "send": "0.19.0",
+                "serve-static": "1.16.2",
+                "setprototypeof": "1.2.0",
+                "statuses": "2.0.1",
+                "type-is": "~1.6.18",
+                "utils-merge": "1.0.1",
+                "vary": "~1.1.2"
+            },
+            "engines": {
+                "node": ">= 0.10.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/express"
+            }
+        },
+        "node_modules/express-session": {
+            "version": "1.18.1",
+            "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz",
+            "integrity": "sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==",
+            "dependencies": {
+                "cookie": "0.7.2",
+                "cookie-signature": "1.0.7",
+                "debug": "2.6.9",
+                "depd": "~2.0.0",
+                "on-headers": "~1.0.2",
+                "parseurl": "~1.3.3",
+                "safe-buffer": "5.2.1",
+                "uid-safe": "~2.1.5"
+            },
+            "engines": {
+                "node": ">= 0.8.0"
+            }
+        },
+        "node_modules/express-session/node_modules/cookie-signature": {
+            "version": "1.0.7",
+            "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
+            "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="
+        },
+        "node_modules/express-session/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==",
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/feross"
+                },
+                {
+                    "type": "patreon",
+                    "url": "https://www.patreon.com/feross"
+                },
+                {
+                    "type": "consulting",
+                    "url": "https://feross.org/support"
+                }
+            ]
+        },
+        "node_modules/express/node_modules/cookie": {
+            "version": "0.7.1",
+            "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+            "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/express/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==",
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/feross"
+                },
+                {
+                    "type": "patreon",
+                    "url": "https://www.patreon.com/feross"
+                },
+                {
+                    "type": "consulting",
+                    "url": "https://feross.org/support"
+                }
+            ]
+        },
+        "node_modules/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=="
+        },
+        "node_modules/fast-unique-numbers": {
+            "version": "8.0.13",
+            "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz",
+            "integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==",
+            "dependencies": {
+                "@babel/runtime": "^7.23.8",
+                "tslib": "^2.6.2"
+            },
+            "engines": {
+                "node": ">=16.1.0"
+            }
+        },
+        "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==",
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/fastify"
+                },
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/fastify"
+                }
+            ]
+        },
+        "node_modules/finalhandler": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+            "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
+            "dependencies": {
+                "debug": "2.6.9",
+                "encodeurl": "~2.0.0",
+                "escape-html": "~1.0.3",
+                "on-finished": "2.4.1",
+                "parseurl": "~1.3.3",
+                "statuses": "2.0.1",
+                "unpipe": "~1.0.0"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/follow-redirects": {
+            "version": "1.15.9",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+            "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
+            "funding": [
+                {
+                    "type": "individual",
+                    "url": "https://github.com/sponsors/RubenVerborgh"
+                }
+            ],
+            "engines": {
+                "node": ">=4.0"
+            },
+            "peerDependenciesMeta": {
+                "debug": {
+                    "optional": true
+                }
+            }
+        },
+        "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==",
+            "dependencies": {
+                "cross-spawn": "^7.0.0",
+                "signal-exit": "^4.0.1"
+            },
+            "engines": {
+                "node": ">=14"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
+            }
+        },
+        "node_modules/form-data": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+            "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+            "dependencies": {
+                "asynckit": "^0.4.0",
+                "combined-stream": "^1.0.8",
+                "mime-types": "^2.1.12"
+            },
+            "engines": {
+                "node": ">= 6"
+            }
+        },
+        "node_modules/form-data-encoder": {
+            "version": "2.1.4",
+            "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
+            "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==",
+            "engines": {
+                "node": ">= 14.17"
+            }
+        },
+        "node_modules/forwarded": {
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+            "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/fresh": {
+            "version": "0.5.2",
+            "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+            "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/fs-extra": {
+            "version": "11.2.0",
+            "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
+            "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
+            "dependencies": {
+                "graceful-fs": "^4.2.0",
+                "jsonfile": "^6.0.1",
+                "universalify": "^2.0.0"
+            },
+            "engines": {
+                "node": ">=14.14"
+            }
+        },
+        "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==",
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "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==",
+            "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==",
+            "dependencies": {
+                "dunder-proto": "^1.0.1",
+                "es-object-atoms": "^1.0.0"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/get-stream": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+            "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "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==",
+            "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/gopd": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+            "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/got": {
+            "version": "12.6.1",
+            "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz",
+            "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==",
+            "dependencies": {
+                "@sindresorhus/is": "^5.2.0",
+                "@szmarczak/http-timer": "^5.0.1",
+                "cacheable-lookup": "^7.0.0",
+                "cacheable-request": "^10.2.8",
+                "decompress-response": "^6.0.0",
+                "form-data-encoder": "^2.1.2",
+                "get-stream": "^6.0.1",
+                "http2-wrapper": "^2.1.10",
+                "lowercase-keys": "^3.0.0",
+                "p-cancelable": "^3.0.0",
+                "responselike": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=14.16"
+            },
+            "funding": {
+                "url": "https://github.com/sindresorhus/got?sponsor=1"
+            }
+        },
+        "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=="
+        },
+        "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==",
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/hash-sum": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz",
+            "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg=="
+        },
+        "node_modules/hasown": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+            "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+            "dependencies": {
+                "function-bind": "^1.1.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/help-me": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
+            "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="
+        },
+        "node_modules/hpagent": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz",
+            "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==",
+            "engines": {
+                "node": ">=14"
+            }
+        },
+        "node_modules/htmlparser2": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
+            "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
+            "funding": [
+                "https://github.com/fb55/htmlparser2?sponsor=1",
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/fb55"
+                }
+            ],
+            "dependencies": {
+                "domelementtype": "^2.0.1",
+                "domhandler": "^4.0.0",
+                "domutils": "^2.5.2",
+                "entities": "^2.0.0"
+            }
+        },
+        "node_modules/http-cache-semantics": {
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+            "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
+        },
+        "node_modules/http-errors": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+            "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+            "dependencies": {
+                "depd": "2.0.0",
+                "inherits": "2.0.4",
+                "setprototypeof": "1.2.0",
+                "statuses": "2.0.1",
+                "toidentifier": "1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/http2-wrapper": {
+            "version": "2.2.1",
+            "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz",
+            "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==",
+            "dependencies": {
+                "quick-lru": "^5.1.1",
+                "resolve-alpn": "^1.2.0"
+            },
+            "engines": {
+                "node": ">=10.19.0"
+            }
+        },
+        "node_modules/https-proxy-agent": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+            "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+            "dependencies": {
+                "agent-base": "6",
+                "debug": "4"
+            },
+            "engines": {
+                "node": ">= 6"
+            }
+        },
+        "node_modules/https-proxy-agent/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==",
+            "dependencies": {
+                "ms": "^2.1.3"
+            },
+            "engines": {
+                "node": ">=6.0"
+            },
+            "peerDependenciesMeta": {
+                "supports-color": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/https-proxy-agent/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=="
+        },
+        "node_modules/i18next": {
+            "version": "21.10.0",
+            "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.10.0.tgz",
+            "integrity": "sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==",
+            "funding": [
+                {
+                    "type": "individual",
+                    "url": "https://locize.com"
+                },
+                {
+                    "type": "individual",
+                    "url": "https://locize.com/i18next.html"
+                },
+                {
+                    "type": "individual",
+                    "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+                }
+            ],
+            "dependencies": {
+                "@babel/runtime": "^7.17.2"
+            }
+        },
+        "node_modules/iconv-lite": {
+            "version": "0.6.3",
+            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+            "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+            "dependencies": {
+                "safer-buffer": ">= 2.1.2 < 3.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/ieee754": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+            "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/feross"
+                },
+                {
+                    "type": "patreon",
+                    "url": "https://www.patreon.com/feross"
+                },
+                {
+                    "type": "consulting",
+                    "url": "https://feross.org/support"
+                }
+            ]
+        },
+        "node_modules/inherits": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+        },
+        "node_modules/ipaddr.js": {
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+            "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+            "engines": {
+                "node": ">= 0.10"
+            }
+        },
+        "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==",
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/is-utf8": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+            "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q=="
+        },
+        "node_modules/isarray": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+            "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+        },
+        "node_modules/isexe": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+            "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+        },
+        "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==",
+            "dependencies": {
+                "@isaacs/cliui": "^8.0.2"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
+            },
+            "optionalDependencies": {
+                "@pkgjs/parseargs": "^0.11.0"
+            }
+        },
+        "node_modules/js-sdsl": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
+            "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/js-sdsl"
+            }
+        },
+        "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==",
+            "dependencies": {
+                "argparse": "^2.0.1"
+            },
+            "bin": {
+                "js-yaml": "bin/js-yaml.js"
+            }
+        },
+        "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=="
+        },
+        "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=="
+        },
+        "node_modules/json-stringify-safe": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+            "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
+        },
+        "node_modules/jsonata": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/jsonata/-/jsonata-2.0.5.tgz",
+            "integrity": "sha512-wEse9+QLIIU5IaCgtJCPsFi/H4F3qcikWzF4bAELZiRz08ohfx3Q6CjDRf4ZPF5P/92RI3KIHtb7u3jqPaHXdQ==",
+            "engines": {
+                "node": ">= 8"
+            }
+        },
+        "node_modules/jsonfile": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+            "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+            "dependencies": {
+                "universalify": "^2.0.0"
+            },
+            "optionalDependencies": {
+                "graceful-fs": "^4.1.6"
+            }
+        },
+        "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==",
+            "dependencies": {
+                "json-buffer": "3.0.1"
+            }
+        },
+        "node_modules/lodash.clonedeep": {
+            "version": "4.5.0",
+            "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+            "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
+        },
+        "node_modules/lowercase-keys": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
+            "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==",
+            "engines": {
+                "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "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==",
+            "dependencies": {
+                "pseudomap": "^1.0.2",
+                "yallist": "^2.1.2"
+            }
+        },
+        "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==",
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/media-typer": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+            "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/memorystore": {
+            "version": "1.6.7",
+            "resolved": "https://registry.npmjs.org/memorystore/-/memorystore-1.6.7.tgz",
+            "integrity": "sha512-OZnmNY/NDrKohPQ+hxp0muBcBKrzKNtHr55DbqSx9hLsYVNnomSAMRAtI7R64t3gf3ID7tHQA7mG4oL3Hu9hdw==",
+            "dependencies": {
+                "debug": "^4.3.0",
+                "lru-cache": "^4.0.3"
+            },
+            "engines": {
+                "node": ">=0.10"
+            }
+        },
+        "node_modules/memorystore/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==",
+            "dependencies": {
+                "ms": "^2.1.3"
+            },
+            "engines": {
+                "node": ">=6.0"
+            },
+            "peerDependenciesMeta": {
+                "supports-color": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/memorystore/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=="
+        },
+        "node_modules/merge-descriptors": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+            "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/methods": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+            "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/mime": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
+            "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
+            "bin": {
+                "mime": "cli.js"
+            },
+            "engines": {
+                "node": ">=10.0.0"
+            }
+        },
+        "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==",
+            "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==",
+            "dependencies": {
+                "mime-db": "1.52.0"
+            },
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/mimic-response": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
+            "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==",
+            "engines": {
+                "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/minimatch": {
+            "version": "9.0.5",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+            "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+            "dependencies": {
+                "brace-expansion": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=16 || 14 >=14.17"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
+            }
+        },
+        "node_modules/minimist": {
+            "version": "1.2.8",
+            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+            "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+            "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==",
+            "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==",
+            "dependencies": {
+                "minipass": "^7.0.4",
+                "rimraf": "^5.0.5"
+            },
+            "engines": {
+                "node": ">= 18"
+            }
+        },
+        "node_modules/mkdirp": {
+            "version": "0.5.6",
+            "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+            "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+            "dependencies": {
+                "minimist": "^1.2.6"
+            },
+            "bin": {
+                "mkdirp": "bin/cmd.js"
+            }
+        },
+        "node_modules/moment": {
+            "version": "2.30.1",
+            "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
+            "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
+            "engines": {
+                "node": "*"
+            }
+        },
+        "node_modules/moment-timezone": {
+            "version": "0.5.46",
+            "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.46.tgz",
+            "integrity": "sha512-ZXm9b36esbe7OmdABqIWJuBBiLLwAjrN7CE+7sYdCCx82Nabt1wHDj8TVseS59QIlfFPbOoiBPm6ca9BioG4hw==",
+            "dependencies": {
+                "moment": "^2.29.4"
+            },
+            "engines": {
+                "node": "*"
+            }
+        },
+        "node_modules/mqtt": {
+            "version": "5.7.0",
+            "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.7.0.tgz",
+            "integrity": "sha512-/o0CBYSjZzddmQDV2iglCafsA0xWKpqnS62tGbOLOliubBxszpXO1DAQPyfI7ZcPDG0b9ni7QITn+5FW1E2UTg==",
+            "dependencies": {
+                "@types/readable-stream": "^4.0.5",
+                "@types/ws": "^8.5.9",
+                "commist": "^3.2.0",
+                "concat-stream": "^2.0.0",
+                "debug": "^4.3.4",
+                "help-me": "^5.0.0",
+                "lru-cache": "^10.0.1",
+                "minimist": "^1.2.8",
+                "mqtt": "^5.2.0",
+                "mqtt-packet": "^9.0.0",
+                "number-allocator": "^1.0.14",
+                "readable-stream": "^4.4.2",
+                "reinterval": "^1.1.0",
+                "rfdc": "^1.3.0",
+                "split2": "^4.2.0",
+                "worker-timers": "^7.1.4",
+                "ws": "^8.14.2"
+            },
+            "bin": {
+                "mqtt": "build/bin/mqtt.js",
+                "mqtt_pub": "build/bin/pub.js",
+                "mqtt_sub": "build/bin/sub.js"
+            },
+            "engines": {
+                "node": ">=16.0.0"
+            }
+        },
+        "node_modules/mqtt-packet": {
+            "version": "9.0.1",
+            "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.1.tgz",
+            "integrity": "sha512-koZF1V/X2RZUI6uD9wN5OK1JxxcG1ofAR4H3LjCw1FkeKzruZQ26aAA6v2m1lZyWONZIR5wMMJFrZJDRNzbiQw==",
+            "dependencies": {
+                "bl": "^6.0.8",
+                "debug": "^4.3.4",
+                "process-nextick-args": "^2.0.1"
+            }
+        },
+        "node_modules/mqtt-packet/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==",
+            "dependencies": {
+                "ms": "^2.1.3"
+            },
+            "engines": {
+                "node": ">=6.0"
+            },
+            "peerDependenciesMeta": {
+                "supports-color": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/mqtt-packet/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=="
+        },
+        "node_modules/mqtt/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==",
+            "dependencies": {
+                "ms": "^2.1.3"
+            },
+            "engines": {
+                "node": ">=6.0"
+            },
+            "peerDependenciesMeta": {
+                "supports-color": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/mqtt/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=="
+        },
+        "node_modules/mqtt/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=="
+        },
+        "node_modules/mqtt/node_modules/ws": {
+            "version": "8.18.0",
+            "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+            "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+            "engines": {
+                "node": ">=10.0.0"
+            },
+            "peerDependencies": {
+                "bufferutil": "^4.0.1",
+                "utf-8-validate": ">=5.0.2"
+            },
+            "peerDependenciesMeta": {
+                "bufferutil": {
+                    "optional": true
+                },
+                "utf-8-validate": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/ms": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+            "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+        },
+        "node_modules/multer": {
+            "version": "1.4.5-lts.1",
+            "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
+            "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
+            "dependencies": {
+                "append-field": "^1.0.0",
+                "busboy": "^1.0.0",
+                "concat-stream": "^1.5.2",
+                "mkdirp": "^0.5.4",
+                "object-assign": "^4.1.1",
+                "type-is": "^1.6.4",
+                "xtend": "^4.0.0"
+            },
+            "engines": {
+                "node": ">= 6.0.0"
+            }
+        },
+        "node_modules/multer/node_modules/concat-stream": {
+            "version": "1.6.2",
+            "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+            "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+            "engines": [
+                "node >= 0.8"
+            ],
+            "dependencies": {
+                "buffer-from": "^1.0.0",
+                "inherits": "^2.0.3",
+                "readable-stream": "^2.2.2",
+                "typedarray": "^0.0.6"
+            }
+        },
+        "node_modules/multer/node_modules/readable-stream": {
+            "version": "2.3.8",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+            "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+            "dependencies": {
+                "core-util-is": "~1.0.0",
+                "inherits": "~2.0.3",
+                "isarray": "~1.0.0",
+                "process-nextick-args": "~2.0.0",
+                "safe-buffer": "~5.1.1",
+                "string_decoder": "~1.1.1",
+                "util-deprecate": "~1.0.1"
+            }
+        },
+        "node_modules/multer/node_modules/string_decoder": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+            "dependencies": {
+                "safe-buffer": "~5.1.0"
+            }
+        },
+        "node_modules/mustache": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+            "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
+            "bin": {
+                "mustache": "bin/mustache"
+            }
+        },
+        "node_modules/mute-stream": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz",
+            "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==",
+            "engines": {
+                "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+            }
+        },
+        "node_modules/negotiator": {
+            "version": "0.6.3",
+            "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+            "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/node-red-admin": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/node-red-admin/-/node-red-admin-4.0.1.tgz",
+            "integrity": "sha512-NLZgAM8JgFa/2/7Z4+nSSQrtkuBbfS9m+kxegadhHfuta5rErOx6zrrNhF+yAglMTPlVmdoqgso7VSt3nTRBGQ==",
+            "dependencies": {
+                "ansi-colors": "^4.1.3",
+                "axios": "^1.7.7",
+                "bcryptjs": "^2.4.3",
+                "cli-table": "^0.3.11",
+                "enquirer": "^2.3.6",
+                "minimist": "^1.2.8",
+                "mustache": "^4.2.0",
+                "read": "^3.0.1"
+            },
+            "bin": {
+                "node-red-admin": "node-red-admin.js"
+            },
+            "engines": {
+                "node": ">=18"
+            },
+            "optionalDependencies": {
+                "@node-rs/bcrypt": "1.10.4"
+            }
+        },
+        "node_modules/node-watch": {
+            "version": "0.7.4",
+            "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.4.tgz",
+            "integrity": "sha512-RinNxoz4W1cep1b928fuFhvAQ5ag/+1UlMDV7rbyGthBIgsiEouS4kvRayvvboxii4m8eolKOIBo3OjDqbc+uQ==",
+            "engines": {
+                "node": ">=6"
+            }
+        },
+        "node_modules/nopt": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+            "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+            "dependencies": {
+                "abbrev": "1"
+            },
+            "bin": {
+                "nopt": "bin/nopt.js"
+            },
+            "engines": {
+                "node": ">=6"
+            }
+        },
+        "node_modules/normalize-url": {
+            "version": "8.0.1",
+            "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz",
+            "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==",
+            "engines": {
+                "node": ">=14.16"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/nth-check": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+            "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+            "dependencies": {
+                "boolbase": "^1.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/fb55/nth-check?sponsor=1"
+            }
+        },
+        "node_modules/number-allocator": {
+            "version": "1.0.14",
+            "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
+            "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
+            "dependencies": {
+                "debug": "^4.3.1",
+                "js-sdsl": "4.3.0"
+            }
+        },
+        "node_modules/number-allocator/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==",
+            "dependencies": {
+                "ms": "^2.1.3"
+            },
+            "engines": {
+                "node": ">=6.0"
+            },
+            "peerDependenciesMeta": {
+                "supports-color": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/number-allocator/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=="
+        },
+        "node_modules/oauth2orize": {
+            "version": "1.12.0",
+            "resolved": "https://registry.npmjs.org/oauth2orize/-/oauth2orize-1.12.0.tgz",
+            "integrity": "sha512-j4XtFDQUBsvUHPjUmvmNDUDMYed2MphMIJBhyxVVe8hGCjkuYnjIsW+D9qk8c5ciXRdnk6x6tEbiO6PLeOZdCQ==",
+            "dependencies": {
+                "debug": "2.x.x",
+                "uid2": "0.0.x",
+                "utils-merge": "1.x.x"
+            },
+            "engines": {
+                "node": ">= 0.4.0"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/jaredhanson"
+            }
+        },
+        "node_modules/object-assign": {
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+            "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/object-inspect": {
+            "version": "1.13.3",
+            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
+            "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/on-finished": {
+            "version": "2.4.1",
+            "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+            "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+            "dependencies": {
+                "ee-first": "1.1.1"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/on-headers": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+            "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/p-cancelable": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
+            "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==",
+            "engines": {
+                "node": ">=12.20"
+            }
+        },
+        "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=="
+        },
+        "node_modules/parse5": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+            "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
+        },
+        "node_modules/parse5-htmlparser2-tree-adapter": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
+            "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
+            "dependencies": {
+                "parse5": "^6.0.1"
+            }
+        },
+        "node_modules/parseurl": {
+            "version": "1.3.3",
+            "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+            "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/passport": {
+            "version": "0.7.0",
+            "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz",
+            "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==",
+            "dependencies": {
+                "passport-strategy": "1.x.x",
+                "pause": "0.0.1",
+                "utils-merge": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 0.4.0"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/jaredhanson"
+            }
+        },
+        "node_modules/passport-http-bearer": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/passport-http-bearer/-/passport-http-bearer-1.0.1.tgz",
+            "integrity": "sha512-SELQM+dOTuMigr9yu8Wo4Fm3ciFfkMq5h/ZQ8ffi4ELgZrX1xh9PlglqZdcUZ1upzJD/whVyt+YWF62s3U6Ipw==",
+            "dependencies": {
+                "passport-strategy": "1.x.x"
+            },
+            "engines": {
+                "node": ">= 0.4.0"
+            }
+        },
+        "node_modules/passport-oauth2-client-password": {
+            "version": "0.1.2",
+            "resolved": "https://registry.npmjs.org/passport-oauth2-client-password/-/passport-oauth2-client-password-0.1.2.tgz",
+            "integrity": "sha512-GHQH4UtaEZvCLulAxGKHYoSsPRoPRmGsdmaZtMh5nmz80yMLQbdMA9Bg2sp4/UW3PIxJH/143hVjPTiXaNngTQ==",
+            "dependencies": {
+                "passport-strategy": "1.x.x"
+            },
+            "engines": {
+                "node": ">= 0.4.0"
+            }
+        },
+        "node_modules/passport-strategy": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
+            "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==",
+            "engines": {
+                "node": ">= 0.4.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==",
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "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==",
+            "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=="
+        },
+        "node_modules/path-to-regexp": {
+            "version": "0.1.12",
+            "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+            "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
+        },
+        "node_modules/pause": {
+            "version": "0.0.1",
+            "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
+            "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
+        },
+        "node_modules/process": {
+            "version": "0.11.10",
+            "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+            "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+            "engines": {
+                "node": ">= 0.6.0"
+            }
+        },
+        "node_modules/process-nextick-args": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+            "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+        },
+        "node_modules/proxy-addr": {
+            "version": "2.0.7",
+            "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+            "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+            "dependencies": {
+                "forwarded": "0.2.0",
+                "ipaddr.js": "1.9.1"
+            },
+            "engines": {
+                "node": ">= 0.10"
+            }
+        },
+        "node_modules/proxy-from-env": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+            "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+        },
+        "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=="
+        },
+        "node_modules/qs": {
+            "version": "6.13.0",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+            "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+            "dependencies": {
+                "side-channel": "^1.0.6"
+            },
+            "engines": {
+                "node": ">=0.6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/quick-lru": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+            "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/random-bytes": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+            "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/range-parser": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+            "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/raw-body": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
+            "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
+            "dependencies": {
+                "bytes": "3.1.2",
+                "http-errors": "2.0.0",
+                "iconv-lite": "0.6.3",
+                "unpipe": "1.0.0"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/read": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/read/-/read-3.0.1.tgz",
+            "integrity": "sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==",
+            "dependencies": {
+                "mute-stream": "^1.0.0"
+            },
+            "engines": {
+                "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+            }
+        },
+        "node_modules/readable-stream": {
+            "version": "4.7.0",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+            "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+            "dependencies": {
+                "abort-controller": "^3.0.0",
+                "buffer": "^6.0.3",
+                "events": "^3.3.0",
+                "process": "^0.11.10",
+                "string_decoder": "^1.3.0"
+            },
+            "engines": {
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+            }
+        },
+        "node_modules/regenerator-runtime": {
+            "version": "0.14.1",
+            "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+            "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
+        },
+        "node_modules/reinterval": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz",
+            "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ=="
+        },
+        "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==",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/resolve-alpn": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
+            "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
+        },
+        "node_modules/responselike": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
+            "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
+            "dependencies": {
+                "lowercase-keys": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=14.16"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/rfdc": {
+            "version": "1.4.1",
+            "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+            "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
+        },
+        "node_modules/rimraf": {
+            "version": "5.0.10",
+            "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
+            "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
+            "dependencies": {
+                "glob": "^10.3.7"
+            },
+            "bin": {
+                "rimraf": "dist/esm/bin.mjs"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
+            }
+        },
+        "node_modules/safe-buffer": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+            "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+        },
+        "node_modules/safer-buffer": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+        },
+        "node_modules/sax": {
+            "version": "1.4.1",
+            "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+            "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
+        },
+        "node_modules/semver": {
+            "version": "7.6.3",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+            "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+            "bin": {
+                "semver": "bin/semver.js"
+            },
+            "engines": {
+                "node": ">=10"
+            }
+        },
+        "node_modules/send": {
+            "version": "0.19.0",
+            "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+            "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
+            "dependencies": {
+                "debug": "2.6.9",
+                "depd": "2.0.0",
+                "destroy": "1.2.0",
+                "encodeurl": "~1.0.2",
+                "escape-html": "~1.0.3",
+                "etag": "~1.8.1",
+                "fresh": "0.5.2",
+                "http-errors": "2.0.0",
+                "mime": "1.6.0",
+                "ms": "2.1.3",
+                "on-finished": "2.4.1",
+                "range-parser": "~1.2.1",
+                "statuses": "2.0.1"
+            },
+            "engines": {
+                "node": ">= 0.8.0"
+            }
+        },
+        "node_modules/send/node_modules/encodeurl": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+            "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/send/node_modules/mime": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+            "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+            "bin": {
+                "mime": "cli.js"
+            },
+            "engines": {
+                "node": ">=4"
+            }
+        },
+        "node_modules/send/node_modules/ms": {
+            "version": "2.1.3",
+            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+            "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+        },
+        "node_modules/serve-static": {
+            "version": "1.16.2",
+            "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+            "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
+            "dependencies": {
+                "encodeurl": "~2.0.0",
+                "escape-html": "~1.0.3",
+                "parseurl": "~1.3.3",
+                "send": "0.19.0"
+            },
+            "engines": {
+                "node": ">= 0.8.0"
+            }
+        },
+        "node_modules/setprototypeof": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+            "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+        },
+        "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==",
+            "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==",
+            "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==",
+            "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==",
+            "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==",
+            "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==",
+            "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==",
+            "engines": {
+                "node": ">=14"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
+            }
+        },
+        "node_modules/split2": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+            "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+            "engines": {
+                "node": ">= 10.x"
+            }
+        },
+        "node_modules/statuses": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+            "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/streamsearch": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+            "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+            "engines": {
+                "node": ">=10.0.0"
+            }
+        },
+        "node_modules/string_decoder": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+            "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+            "dependencies": {
+                "safe-buffer": "~5.2.0"
+            }
+        },
+        "node_modules/string_decoder/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==",
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/feross"
+                },
+                {
+                    "type": "patreon",
+                    "url": "https://www.patreon.com/feross"
+                },
+                {
+                    "type": "consulting",
+                    "url": "https://feross.org/support"
+                }
+            ]
+        },
+        "node_modules/string-width": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+            "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+            "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/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==",
+            "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/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=="
+        },
+        "node_modules/string-width/node_modules/ansi-regex": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+            "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+            }
+        },
+        "node_modules/string-width/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==",
+            "dependencies": {
+                "ansi-regex": "^6.0.1"
+            },
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+            }
+        },
+        "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==",
+            "dependencies": {
+                "ansi-regex": "^5.0.1"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "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==",
+            "dependencies": {
+                "ansi-regex": "^5.0.1"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/tar": {
+            "version": "7.4.3",
+            "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
+            "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
+            "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/tar/node_modules/mkdirp": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+            "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+            "bin": {
+                "mkdirp": "dist/cjs/src/bin.js"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
+            }
+        },
+        "node_modules/tar/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==",
+            "engines": {
+                "node": ">=18"
+            }
+        },
+        "node_modules/tldts": {
+            "version": "6.1.73",
+            "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.73.tgz",
+            "integrity": "sha512-/h4bVmuEMm57c2uCiAf1Q9mlQk7cA22m+1Bu0K92vUUtTVT9D4mOFWD9r4WQuTULcG9eeZtNKhLl0Il1LdKGog==",
+            "dependencies": {
+                "tldts-core": "^6.1.73"
+            },
+            "bin": {
+                "tldts": "bin/cli.js"
+            }
+        },
+        "node_modules/tldts-core": {
+            "version": "6.1.73",
+            "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.73.tgz",
+            "integrity": "sha512-k1g5eX87vxu3g//6XMn62y4qjayu4cYby/PF7Ksnh4F4uUK1Z1ze/mJ4a+y5OjdJ+cXRp+YTInZhH+FGdUWy1w=="
+        },
+        "node_modules/toidentifier": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+            "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+            "engines": {
+                "node": ">=0.6"
+            }
+        },
+        "node_modules/tough-cookie": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.0.tgz",
+            "integrity": "sha512-rvZUv+7MoBYTiDmFPBrhL7Ujx9Sk+q9wwm22x8c8T5IJaR+Wsyc7TNxbVxo84kZoRJZZMazowFLqpankBEQrGg==",
+            "dependencies": {
+                "tldts": "^6.1.32"
+            },
+            "engines": {
+                "node": ">=16"
+            }
+        },
+        "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=="
+        },
+        "node_modules/type-is": {
+            "version": "1.6.18",
+            "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+            "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+            "dependencies": {
+                "media-typer": "0.3.0",
+                "mime-types": "~2.1.24"
+            },
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/type-is/node_modules/media-typer": {
+            "version": "0.3.0",
+            "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+            "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/typedarray": {
+            "version": "0.0.6",
+            "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+            "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
+        },
+        "node_modules/uglify-js": {
+            "version": "3.17.4",
+            "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
+            "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
+            "bin": {
+                "uglifyjs": "bin/uglifyjs"
+            },
+            "engines": {
+                "node": ">=0.8.0"
+            }
+        },
+        "node_modules/uid-safe": {
+            "version": "2.1.5",
+            "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
+            "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
+            "dependencies": {
+                "random-bytes": "~1.0.0"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/uid2": {
+            "version": "0.0.4",
+            "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz",
+            "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA=="
+        },
+        "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=="
+        },
+        "node_modules/universalify": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+            "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+            "engines": {
+                "node": ">= 10.0.0"
+            }
+        },
+        "node_modules/unpipe": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+            "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/util-deprecate": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+            "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+        },
+        "node_modules/utils-merge": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+            "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+            "engines": {
+                "node": ">= 0.4.0"
+            }
+        },
+        "node_modules/uuid": {
+            "version": "9.0.1",
+            "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+            "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+            "funding": [
+                "https://github.com/sponsors/broofa",
+                "https://github.com/sponsors/ctavan"
+            ],
+            "bin": {
+                "uuid": "dist/bin/uuid"
+            }
+        },
+        "node_modules/vary": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+            "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/which": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+            "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+            "dependencies": {
+                "isexe": "^2.0.0"
+            },
+            "bin": {
+                "node-which": "bin/node-which"
+            },
+            "engines": {
+                "node": ">= 8"
+            }
+        },
+        "node_modules/worker-timers": {
+            "version": "7.1.8",
+            "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz",
+            "integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==",
+            "dependencies": {
+                "@babel/runtime": "^7.24.5",
+                "tslib": "^2.6.2",
+                "worker-timers-broker": "^6.1.8",
+                "worker-timers-worker": "^7.0.71"
+            }
+        },
+        "node_modules/worker-timers-broker": {
+            "version": "6.1.8",
+            "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz",
+            "integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==",
+            "dependencies": {
+                "@babel/runtime": "^7.24.5",
+                "fast-unique-numbers": "^8.0.13",
+                "tslib": "^2.6.2",
+                "worker-timers-worker": "^7.0.71"
+            }
+        },
+        "node_modules/worker-timers-worker": {
+            "version": "7.0.71",
+            "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz",
+            "integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==",
+            "dependencies": {
+                "@babel/runtime": "^7.24.5",
+                "tslib": "^2.6.2"
+            }
+        },
+        "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==",
+            "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/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==",
+            "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-styles": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+            "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/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=="
+        },
+        "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==",
+            "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/ansi-regex": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+            "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+            }
+        },
+        "node_modules/wrap-ansi/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==",
+            "dependencies": {
+                "ansi-regex": "^6.0.1"
+            },
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+            }
+        },
+        "node_modules/ws": {
+            "version": "7.5.10",
+            "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+            "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
+            "engines": {
+                "node": ">=8.3.0"
+            },
+            "peerDependencies": {
+                "bufferutil": "^4.0.1",
+                "utf-8-validate": "^5.0.2"
+            },
+            "peerDependenciesMeta": {
+                "bufferutil": {
+                    "optional": true
+                },
+                "utf-8-validate": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/xml2js": {
+            "version": "0.6.2",
+            "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
+            "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
+            "dependencies": {
+                "sax": ">=0.6.0",
+                "xmlbuilder": "~11.0.0"
+            },
+            "engines": {
+                "node": ">=4.0.0"
+            }
+        },
+        "node_modules/xmlbuilder": {
+            "version": "11.0.1",
+            "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+            "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+            "engines": {
+                "node": ">=4.0"
+            }
+        },
+        "node_modules/xtend": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+            "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+            "engines": {
+                "node": ">=0.4"
+            }
+        },
+        "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=="
+        }
+    },
+    "dependencies": {
+        "@babel/runtime": {
+            "version": "7.26.0",
+            "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
+            "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
+            "requires": {
+                "regenerator-runtime": "^0.14.0"
+            }
+        },
+        "@emnapi/core": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz",
+            "integrity": "sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==",
+            "optional": true,
+            "requires": {
+                "@emnapi/wasi-threads": "1.0.1",
+                "tslib": "^2.4.0"
+            }
+        },
+        "@emnapi/runtime": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz",
+            "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==",
+            "optional": true,
+            "requires": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "@emnapi/wasi-threads": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz",
+            "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==",
+            "optional": true,
+            "requires": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "@isaacs/cliui": {
+            "version": "8.0.2",
+            "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+            "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+            "requires": {
+                "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"
+            },
+            "dependencies": {
+                "ansi-regex": {
+                    "version": "6.1.0",
+                    "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+                    "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="
+                },
+                "strip-ansi": {
+                    "version": "7.1.0",
+                    "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+                    "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+                    "requires": {
+                        "ansi-regex": "^6.0.1"
+                    }
+                }
+            }
+        },
+        "@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==",
+            "requires": {
+                "minipass": "^7.0.4"
+            }
+        },
+        "@napi-rs/wasm-runtime": {
+            "version": "0.2.6",
+            "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.6.tgz",
+            "integrity": "sha512-z8YVS3XszxFTO73iwvFDNpQIzdMmSDTP/mB3E/ucR37V3Sx57hSExcXyMoNwaucWxnsWf4xfbZv0iZ30jr0M4Q==",
+            "optional": true,
+            "requires": {
+                "@emnapi/core": "^1.3.1",
+                "@emnapi/runtime": "^1.3.1",
+                "@tybys/wasm-util": "^0.9.0"
+            }
+        },
+        "@node-red/editor-api": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/editor-api/-/editor-api-4.0.8.tgz",
+            "integrity": "sha512-ngsyd/Ro5oyefE+jCJa43fU9WLIGWFkTvifTheU9fj+epSgCGHQLLMOoEvs4FKOaPJ8L4dAqHgD/kik9c73rdg==",
+            "requires": {
+                "@node-red/editor-client": "4.0.8",
+                "@node-red/util": "4.0.8",
+                "@node-rs/bcrypt": "1.10.4",
+                "bcryptjs": "2.4.3",
+                "body-parser": "1.20.3",
+                "clone": "2.1.2",
+                "cors": "2.8.5",
+                "express": "4.21.2",
+                "express-session": "1.18.1",
+                "memorystore": "1.6.7",
+                "mime": "3.0.0",
+                "multer": "1.4.5-lts.1",
+                "mustache": "4.2.0",
+                "oauth2orize": "1.12.0",
+                "passport": "0.7.0",
+                "passport-http-bearer": "1.0.1",
+                "passport-oauth2-client-password": "0.1.2",
+                "ws": "7.5.10"
+            }
+        },
+        "@node-red/editor-client": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/editor-client/-/editor-client-4.0.8.tgz",
+            "integrity": "sha512-LQI24xhXio4iftiiAvZ191Zjo9N1MsD0563aHGwsqGaLKxCTfOa+G1t5LslQoYGf0qMcYusf6Nftc2+5Q4nf/g=="
+        },
+        "@node-red/nodes": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/nodes/-/nodes-4.0.8.tgz",
+            "integrity": "sha512-DAj0DyImWZ6lJo7D0LS/tFntkCEiUMAMMKBkyZjOudGLhxppaa99uzcDgQnSkM9vLSU1Uczxc9zHDY3RhxIpdA==",
+            "requires": {
+                "acorn": "8.12.1",
+                "acorn-walk": "8.3.4",
+                "ajv": "8.17.1",
+                "body-parser": "1.20.3",
+                "cheerio": "1.0.0-rc.10",
+                "content-type": "1.0.5",
+                "cookie": "0.7.2",
+                "cookie-parser": "1.4.7",
+                "cors": "2.8.5",
+                "cronosjs": "1.7.1",
+                "denque": "2.1.0",
+                "form-data": "4.0.0",
+                "fs-extra": "11.2.0",
+                "got": "12.6.1",
+                "hash-sum": "2.0.0",
+                "hpagent": "1.2.0",
+                "https-proxy-agent": "5.0.1",
+                "iconv-lite": "0.6.3",
+                "is-utf8": "0.2.1",
+                "js-yaml": "4.1.0",
+                "media-typer": "1.1.0",
+                "mqtt": "5.7.0",
+                "multer": "1.4.5-lts.1",
+                "mustache": "4.2.0",
+                "node-watch": "0.7.4",
+                "on-headers": "1.0.2",
+                "raw-body": "3.0.0",
+                "tough-cookie": "^5.0.0",
+                "uuid": "9.0.1",
+                "ws": "7.5.10",
+                "xml2js": "0.6.2"
+            }
+        },
+        "@node-red/registry": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/registry/-/registry-4.0.8.tgz",
+            "integrity": "sha512-yZLeMi4crXehsU5VZ9l/TpU9gzVijFlxykDiUB//errA415sdtMMk02yKq+yZVlRyBPAhQRkL97t4/Y3wcWJog==",
+            "requires": {
+                "@node-red/util": "4.0.8",
+                "clone": "2.1.2",
+                "fs-extra": "11.2.0",
+                "semver": "7.6.3",
+                "tar": "7.4.3",
+                "uglify-js": "3.17.4"
+            }
+        },
+        "@node-red/runtime": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/runtime/-/runtime-4.0.8.tgz",
+            "integrity": "sha512-TYYyDytZr4nYJgkAKwDduCUjOMrIorUnn28aSorHgWCVJEdlllJAbBQgrdDJm6GGqsDNx2iFwmVbgKC3PJbTKg==",
+            "requires": {
+                "@node-red/registry": "4.0.8",
+                "@node-red/util": "4.0.8",
+                "async-mutex": "0.5.0",
+                "clone": "2.1.2",
+                "express": "4.21.2",
+                "fs-extra": "11.2.0",
+                "json-stringify-safe": "5.0.1",
+                "rfdc": "^1.3.1"
+            }
+        },
+        "@node-red/util": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/@node-red/util/-/util-4.0.8.tgz",
+            "integrity": "sha512-Kl2e4i+Oryq5waTMYvY3ntrQtMfy4+hRTMmeXwpkdCa27DTnWfz0grJHIfy0k9F97K7S47gKFOpR6EjRCm0mWw==",
+            "requires": {
+                "fs-extra": "11.2.0",
+                "i18next": "21.10.0",
+                "json-stringify-safe": "5.0.1",
+                "jsonata": "2.0.5",
+                "lodash.clonedeep": "^4.5.0",
+                "moment": "2.30.1",
+                "moment-timezone": "0.5.46"
+            }
+        },
+        "@node-rs/bcrypt": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt/-/bcrypt-1.10.4.tgz",
+            "integrity": "sha512-Kzs8HKt2eBeT5VnkeKgiz/QKTjOO3URcvSNEQZahNwZnL6dBeeJQTxxYisc/6969+5n6c3+gNwKvqJsZzmGe7g==",
+            "optional": true,
+            "requires": {
+                "@node-rs/bcrypt-android-arm-eabi": "1.10.4",
+                "@node-rs/bcrypt-android-arm64": "1.10.4",
+                "@node-rs/bcrypt-darwin-arm64": "1.10.4",
+                "@node-rs/bcrypt-darwin-x64": "1.10.4",
+                "@node-rs/bcrypt-freebsd-x64": "1.10.4",
+                "@node-rs/bcrypt-linux-arm-gnueabihf": "1.10.4",
+                "@node-rs/bcrypt-linux-arm64-gnu": "1.10.4",
+                "@node-rs/bcrypt-linux-arm64-musl": "1.10.4",
+                "@node-rs/bcrypt-linux-x64-gnu": "1.10.4",
+                "@node-rs/bcrypt-linux-x64-musl": "1.10.4",
+                "@node-rs/bcrypt-wasm32-wasi": "1.10.4",
+                "@node-rs/bcrypt-win32-arm64-msvc": "1.10.4",
+                "@node-rs/bcrypt-win32-ia32-msvc": "1.10.4",
+                "@node-rs/bcrypt-win32-x64-msvc": "1.10.4"
+            }
+        },
+        "@node-rs/bcrypt-android-arm-eabi": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm-eabi/-/bcrypt-android-arm-eabi-1.10.4.tgz",
+            "integrity": "sha512-55ajutuTdfK1hKseyliflnxzNtxszQQ/EoLtgJlgCe7rI24vGP9EEEZDznB/u9OaJ14/AYzZtIhkEOYdbIdw0A==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-android-arm64": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-android-arm64/-/bcrypt-android-arm64-1.10.4.tgz",
+            "integrity": "sha512-dCgQT7nH65tORmJw2hQ6zQgFmmC+/JBYZUWtf7pPZI76AVAn5tc7cIUrxYoV4OT1+uD63b9Av+mS1fT2EPzWEg==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-darwin-arm64": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-arm64/-/bcrypt-darwin-arm64-1.10.4.tgz",
+            "integrity": "sha512-gmHdWikHL3YVZgqXAHT+X/PG+kqIyNlPeFAWKdby83RkDI8FUiPV4qqGilgNnBmVWKkobRae9/I1HDbc4Sbhyg==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-darwin-x64": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-darwin-x64/-/bcrypt-darwin-x64-1.10.4.tgz",
+            "integrity": "sha512-WDzL1WKRtoyTkH6IMPx95Mkd6XaeN0VWJbSDMqQY6AFBOk03yJEj7YYXshCcF+Ur6KBBVSwRf6sdFJ15NI1Z3g==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-freebsd-x64": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-freebsd-x64/-/bcrypt-freebsd-x64-1.10.4.tgz",
+            "integrity": "sha512-seSPJi+4MIUd1faL/n/wmDdDwaynd/FTkvTnb7qzCk8LBT+/dxi7MTz+uaD8KYDREcB9Wmhv+lwr0S9/jBTcjg==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-linux-arm-gnueabihf": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm-gnueabihf/-/bcrypt-linux-arm-gnueabihf-1.10.4.tgz",
+            "integrity": "sha512-YcMLUtN9cGNTWKnaXslxGO1M0S5b4QN9KYhuyG6Kju27RfqvU5UbmpKElCsEUO2EIjxGwzvPu59T+Fyh6sVbwg==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-linux-arm64-gnu": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-gnu/-/bcrypt-linux-arm64-gnu-1.10.4.tgz",
+            "integrity": "sha512-uYGUK/mO8SiftqmVSAePWxgK82vg+X/gtrVRJi95yq2iwp1+fYJX3ndxCyYPmeplBbd3NJ/F5lPT3FC/IHTTGw==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-linux-arm64-musl": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-arm64-musl/-/bcrypt-linux-arm64-musl-1.10.4.tgz",
+            "integrity": "sha512-rLvSMW/gVUBd2k2gAqQfuOReHWd9+jvz58E3i1TbkRE3a5ChvjOFc9qKPEmXuXuD9Mdj7gUwcYwpq8MdB5MtNw==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-linux-x64-gnu": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-gnu/-/bcrypt-linux-x64-gnu-1.10.4.tgz",
+            "integrity": "sha512-I++6bh+BIp70X/D/crlSgCq8K0s9nGvzmvAGFkqSG4h3LBtjJx4RKbygnoWvcBV9ErK1rvcjfMyjwZt1ukueFA==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-linux-x64-musl": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-linux-x64-musl/-/bcrypt-linux-x64-musl-1.10.4.tgz",
+            "integrity": "sha512-f9RPl/5n2NS0mMJXB4IYbodKnq5HzOK5x1b9eKbcjsY0rw3mJC3K0XRFc8iaw1a5chA+xV1TPXz5mkykmr2CQQ==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-wasm32-wasi": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-wasm32-wasi/-/bcrypt-wasm32-wasi-1.10.4.tgz",
+            "integrity": "sha512-VaDOf+wic0yoHFimMkC5VMa/33BNqg6ieD+C/ibb7Av3NnVW4/W9YpDpqAWMR2w3fA40uTLWZ7FZSrcFck27oA==",
+            "optional": true,
+            "requires": {
+                "@napi-rs/wasm-runtime": "^0.2.3"
+            }
+        },
+        "@node-rs/bcrypt-win32-arm64-msvc": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-arm64-msvc/-/bcrypt-win32-arm64-msvc-1.10.4.tgz",
+            "integrity": "sha512-M7sGnbKPvhYJ5b76ywXiEwR4mIs/JSDHjRrhm9fshKAvltQrwc3Mou22TJggvDN3gKOF1W85uPiM2OgGX/jxMg==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-win32-ia32-msvc": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-ia32-msvc/-/bcrypt-win32-ia32-msvc-1.10.4.tgz",
+            "integrity": "sha512-zn/n4DYnuOfC2JgmVDa0JHP+5DUqAOTl2jmV3yrMrmN+StDT4Om5wtvWxvEmgv3CkeZAuAU3Y/fwjSXIpZ0Fhg==",
+            "optional": true
+        },
+        "@node-rs/bcrypt-win32-x64-msvc": {
+            "version": "1.10.4",
+            "resolved": "https://registry.npmjs.org/@node-rs/bcrypt-win32-x64-msvc/-/bcrypt-win32-x64-msvc-1.10.4.tgz",
+            "integrity": "sha512-ynQokTTGbuLu/cckaD8dNcE+Zsfam1zElE+teNol8AxcL7Jv+ghJItSnRthPRV/vLxuycDF2DIICgpXG/p9jrQ==",
+            "optional": true
+        },
+        "@pkgjs/parseargs": {
+            "version": "0.11.0",
+            "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+            "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+            "optional": true
+        },
+        "@sindresorhus/is": {
+            "version": "5.6.0",
+            "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz",
+            "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g=="
+        },
+        "@szmarczak/http-timer": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
+            "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
+            "requires": {
+                "defer-to-connect": "^2.0.1"
+            }
+        },
+        "@tybys/wasm-util": {
+            "version": "0.9.0",
+            "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz",
+            "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==",
+            "optional": true,
+            "requires": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "@types/http-cache-semantics": {
+            "version": "4.0.4",
+            "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
+            "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="
+        },
+        "@types/node": {
+            "version": "22.10.7",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz",
+            "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==",
+            "requires": {
+                "undici-types": "~6.20.0"
+            }
+        },
+        "@types/readable-stream": {
+            "version": "4.0.18",
+            "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.18.tgz",
+            "integrity": "sha512-21jK/1j+Wg+7jVw1xnSwy/2Q1VgVjWuFssbYGTREPUBeZ+rqVFl2udq0IkxzPC0ZhOzVceUbyIACFZKLqKEBlA==",
+            "requires": {
+                "@types/node": "*",
+                "safe-buffer": "~5.1.1"
+            }
+        },
+        "@types/ws": {
+            "version": "8.5.13",
+            "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz",
+            "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==",
+            "requires": {
+                "@types/node": "*"
+            }
+        },
+        "abbrev": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+            "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+        },
+        "abort-controller": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+            "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+            "requires": {
+                "event-target-shim": "^5.0.0"
+            }
+        },
+        "accepts": {
+            "version": "1.3.8",
+            "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+            "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+            "requires": {
+                "mime-types": "~2.1.34",
+                "negotiator": "0.6.3"
+            }
+        },
+        "acorn": {
+            "version": "8.12.1",
+            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+            "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg=="
+        },
+        "acorn-walk": {
+            "version": "8.3.4",
+            "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
+            "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
+            "requires": {
+                "acorn": "^8.11.0"
+            }
+        },
+        "agent-base": {
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+            "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+            "requires": {
+                "debug": "4"
+            },
+            "dependencies": {
+                "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==",
+                    "requires": {
+                        "ms": "^2.1.3"
+                    }
+                },
+                "ms": {
+                    "version": "2.1.3",
+                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+                    "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+                }
+            }
+        },
+        "ajv": {
+            "version": "8.17.1",
+            "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+            "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+            "requires": {
+                "fast-deep-equal": "^3.1.3",
+                "fast-uri": "^3.0.1",
+                "json-schema-traverse": "^1.0.0",
+                "require-from-string": "^2.0.2"
+            }
+        },
+        "ansi-colors": {
+            "version": "4.1.3",
+            "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+            "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="
+        },
+        "ansi-regex": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+        },
+        "ansi-styles": {
+            "version": "6.2.1",
+            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+            "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="
+        },
+        "append-field": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
+            "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
+        },
+        "argparse": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+            "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+        },
+        "array-flatten": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+            "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+        },
+        "async-mutex": {
+            "version": "0.5.0",
+            "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz",
+            "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==",
+            "requires": {
+                "tslib": "^2.4.0"
+            }
+        },
+        "asynckit": {
+            "version": "0.4.0",
+            "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+            "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+        },
+        "axios": {
+            "version": "1.7.9",
+            "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
+            "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
+            "requires": {
+                "follow-redirects": "^1.15.6",
+                "form-data": "^4.0.0",
+                "proxy-from-env": "^1.1.0"
+            }
+        },
+        "balanced-match": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+            "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+        },
+        "base64-js": {
+            "version": "1.5.1",
+            "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+            "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+        },
+        "basic-auth": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+            "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+            "requires": {
+                "safe-buffer": "5.1.2"
+            }
+        },
+        "bcryptjs": {
+            "version": "2.4.3",
+            "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
+            "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="
+        },
+        "bl": {
+            "version": "6.0.18",
+            "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.18.tgz",
+            "integrity": "sha512-2k76XmWCuvu9HTvu3tFOl5HDdCH0wLZ/jHYva/LBVJmc9oX8yUtNQjxrFmbTdXsCSmIxwVTANZPNDfMQrvHFUw==",
+            "requires": {
+                "@types/readable-stream": "^4.0.0",
+                "buffer": "^6.0.3",
+                "inherits": "^2.0.4",
+                "readable-stream": "^4.2.0"
+            }
+        },
+        "body-parser": {
+            "version": "1.20.3",
+            "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+            "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+            "requires": {
+                "bytes": "3.1.2",
+                "content-type": "~1.0.5",
+                "debug": "2.6.9",
+                "depd": "2.0.0",
+                "destroy": "1.2.0",
+                "http-errors": "2.0.0",
+                "iconv-lite": "0.4.24",
+                "on-finished": "2.4.1",
+                "qs": "6.13.0",
+                "raw-body": "2.5.2",
+                "type-is": "~1.6.18",
+                "unpipe": "1.0.0"
+            },
+            "dependencies": {
+                "iconv-lite": {
+                    "version": "0.4.24",
+                    "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+                    "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+                    "requires": {
+                        "safer-buffer": ">= 2.1.2 < 3"
+                    }
+                },
+                "raw-body": {
+                    "version": "2.5.2",
+                    "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+                    "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+                    "requires": {
+                        "bytes": "3.1.2",
+                        "http-errors": "2.0.0",
+                        "iconv-lite": "0.4.24",
+                        "unpipe": "1.0.0"
+                    }
+                }
+            }
+        },
+        "boolbase": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+            "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
+        },
+        "brace-expansion": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+            "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+            "requires": {
+                "balanced-match": "^1.0.0"
+            }
+        },
+        "buffer": {
+            "version": "6.0.3",
+            "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+            "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+            "requires": {
+                "base64-js": "^1.3.1",
+                "ieee754": "^1.2.1"
+            }
+        },
+        "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=="
+        },
+        "busboy": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+            "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+            "requires": {
+                "streamsearch": "^1.1.0"
+            }
+        },
+        "bytes": {
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+            "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+        },
+        "cacheable-lookup": {
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
+            "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w=="
+        },
+        "cacheable-request": {
+            "version": "10.2.14",
+            "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz",
+            "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==",
+            "requires": {
+                "@types/http-cache-semantics": "^4.0.2",
+                "get-stream": "^6.0.1",
+                "http-cache-semantics": "^4.1.1",
+                "keyv": "^4.5.3",
+                "mimic-response": "^4.0.0",
+                "normalize-url": "^8.0.0",
+                "responselike": "^3.0.0"
+            }
+        },
+        "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==",
+            "requires": {
+                "es-errors": "^1.3.0",
+                "function-bind": "^1.1.2"
+            }
+        },
+        "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==",
+            "requires": {
+                "call-bind-apply-helpers": "^1.0.1",
+                "get-intrinsic": "^1.2.6"
+            }
+        },
+        "cheerio": {
+            "version": "1.0.0-rc.10",
+            "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
+            "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==",
+            "requires": {
+                "cheerio-select": "^1.5.0",
+                "dom-serializer": "^1.3.2",
+                "domhandler": "^4.2.0",
+                "htmlparser2": "^6.1.0",
+                "parse5": "^6.0.1",
+                "parse5-htmlparser2-tree-adapter": "^6.0.1",
+                "tslib": "^2.2.0"
+            }
+        },
+        "cheerio-select": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz",
+            "integrity": "sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==",
+            "requires": {
+                "css-select": "^4.3.0",
+                "css-what": "^6.0.1",
+                "domelementtype": "^2.2.0",
+                "domhandler": "^4.3.1",
+                "domutils": "^2.8.0"
+            }
+        },
+        "chownr": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+            "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="
+        },
+        "cli-table": {
+            "version": "0.3.11",
+            "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz",
+            "integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==",
+            "requires": {
+                "colors": "1.0.3"
+            }
+        },
+        "clone": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+            "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="
+        },
+        "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==",
+            "requires": {
+                "color-name": "~1.1.4"
+            }
+        },
+        "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=="
+        },
+        "colors": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+            "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw=="
+        },
+        "combined-stream": {
+            "version": "1.0.8",
+            "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+            "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+            "requires": {
+                "delayed-stream": "~1.0.0"
+            }
+        },
+        "commist": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
+            "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw=="
+        },
+        "concat-stream": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+            "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+            "requires": {
+                "buffer-from": "^1.0.0",
+                "inherits": "^2.0.3",
+                "readable-stream": "^3.0.2",
+                "typedarray": "^0.0.6"
+            },
+            "dependencies": {
+                "readable-stream": {
+                    "version": "3.6.2",
+                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+                    "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+                    "requires": {
+                        "inherits": "^2.0.3",
+                        "string_decoder": "^1.1.1",
+                        "util-deprecate": "^1.0.1"
+                    }
+                }
+            }
+        },
+        "content-disposition": {
+            "version": "0.5.4",
+            "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+            "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+            "requires": {
+                "safe-buffer": "5.2.1"
+            },
+            "dependencies": {
+                "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=="
+                }
+            }
+        },
+        "content-type": {
+            "version": "1.0.5",
+            "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+            "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
+        },
+        "cookie": {
+            "version": "0.7.2",
+            "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+            "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="
+        },
+        "cookie-parser": {
+            "version": "1.4.7",
+            "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+            "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
+            "requires": {
+                "cookie": "0.7.2",
+                "cookie-signature": "1.0.6"
+            }
+        },
+        "cookie-signature": {
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+            "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+        },
+        "core-util-is": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+            "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+        },
+        "cors": {
+            "version": "2.8.5",
+            "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+            "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+            "requires": {
+                "object-assign": "^4",
+                "vary": "^1"
+            }
+        },
+        "cronosjs": {
+            "version": "1.7.1",
+            "resolved": "https://registry.npmjs.org/cronosjs/-/cronosjs-1.7.1.tgz",
+            "integrity": "sha512-d6S6+ep7dJxsAG8OQQCdKuByI/S/AV64d9OF5mtmcykOyPu92cAkAnF3Tbc9s5oOaLQBYYQmTNvjqYRkPJ/u5Q=="
+        },
+        "cross-spawn": {
+            "version": "7.0.6",
+            "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+            "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+            "requires": {
+                "path-key": "^3.1.0",
+                "shebang-command": "^2.0.0",
+                "which": "^2.0.1"
+            }
+        },
+        "css-select": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+            "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
+            "requires": {
+                "boolbase": "^1.0.0",
+                "css-what": "^6.0.1",
+                "domhandler": "^4.3.1",
+                "domutils": "^2.8.0",
+                "nth-check": "^2.0.1"
+            }
+        },
+        "css-what": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+            "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="
+        },
+        "debug": {
+            "version": "2.6.9",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+            "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+            "requires": {
+                "ms": "2.0.0"
+            }
+        },
+        "decompress-response": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+            "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+            "requires": {
+                "mimic-response": "^3.1.0"
+            },
+            "dependencies": {
+                "mimic-response": {
+                    "version": "3.1.0",
+                    "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+                    "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
+                }
+            }
+        },
+        "defer-to-connect": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+            "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="
+        },
+        "delayed-stream": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+            "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
+        },
+        "denque": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+            "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="
+        },
+        "depd": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+            "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+        },
+        "destroy": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+            "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
+        },
+        "dom-serializer": {
+            "version": "1.4.1",
+            "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+            "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+            "requires": {
+                "domelementtype": "^2.0.1",
+                "domhandler": "^4.2.0",
+                "entities": "^2.0.0"
+            }
+        },
+        "domelementtype": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+            "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
+        },
+        "domhandler": {
+            "version": "4.3.1",
+            "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+            "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+            "requires": {
+                "domelementtype": "^2.2.0"
+            }
+        },
+        "domutils": {
+            "version": "2.8.0",
+            "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+            "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+            "requires": {
+                "dom-serializer": "^1.0.1",
+                "domelementtype": "^2.2.0",
+                "domhandler": "^4.2.0"
+            }
+        },
+        "dunder-proto": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+            "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+            "requires": {
+                "call-bind-apply-helpers": "^1.0.1",
+                "es-errors": "^1.3.0",
+                "gopd": "^1.2.0"
+            }
+        },
+        "eastasianwidth": {
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+            "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
+        },
+        "ee-first": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+            "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+        },
+        "emoji-regex": {
+            "version": "9.2.2",
+            "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+            "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
+        },
+        "encodeurl": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+            "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="
+        },
+        "enquirer": {
+            "version": "2.4.1",
+            "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
+            "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
+            "requires": {
+                "ansi-colors": "^4.1.1",
+                "strip-ansi": "^6.0.1"
+            }
+        },
+        "entities": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+            "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
+        },
+        "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=="
+        },
+        "es-errors": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+            "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
+        },
+        "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==",
+            "requires": {
+                "es-errors": "^1.3.0"
+            }
+        },
+        "escape-html": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+            "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+        },
+        "etag": {
+            "version": "1.8.1",
+            "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+            "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
+        },
+        "event-target-shim": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+            "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
+        },
+        "events": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+            "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="
+        },
+        "express": {
+            "version": "4.21.2",
+            "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+            "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
+            "requires": {
+                "accepts": "~1.3.8",
+                "array-flatten": "1.1.1",
+                "body-parser": "1.20.3",
+                "content-disposition": "0.5.4",
+                "content-type": "~1.0.4",
+                "cookie": "0.7.1",
+                "cookie-signature": "1.0.6",
+                "debug": "2.6.9",
+                "depd": "2.0.0",
+                "encodeurl": "~2.0.0",
+                "escape-html": "~1.0.3",
+                "etag": "~1.8.1",
+                "finalhandler": "1.3.1",
+                "fresh": "0.5.2",
+                "http-errors": "2.0.0",
+                "merge-descriptors": "1.0.3",
+                "methods": "~1.1.2",
+                "on-finished": "2.4.1",
+                "parseurl": "~1.3.3",
+                "path-to-regexp": "0.1.12",
+                "proxy-addr": "~2.0.7",
+                "qs": "6.13.0",
+                "range-parser": "~1.2.1",
+                "safe-buffer": "5.2.1",
+                "send": "0.19.0",
+                "serve-static": "1.16.2",
+                "setprototypeof": "1.2.0",
+                "statuses": "2.0.1",
+                "type-is": "~1.6.18",
+                "utils-merge": "1.0.1",
+                "vary": "~1.1.2"
+            },
+            "dependencies": {
+                "cookie": {
+                    "version": "0.7.1",
+                    "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+                    "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="
+                },
+                "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=="
+                }
+            }
+        },
+        "express-session": {
+            "version": "1.18.1",
+            "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz",
+            "integrity": "sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==",
+            "requires": {
+                "cookie": "0.7.2",
+                "cookie-signature": "1.0.7",
+                "debug": "2.6.9",
+                "depd": "~2.0.0",
+                "on-headers": "~1.0.2",
+                "parseurl": "~1.3.3",
+                "safe-buffer": "5.2.1",
+                "uid-safe": "~2.1.5"
+            },
+            "dependencies": {
+                "cookie-signature": {
+                    "version": "1.0.7",
+                    "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
+                    "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="
+                },
+                "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=="
+                }
+            }
+        },
+        "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=="
+        },
+        "fast-unique-numbers": {
+            "version": "8.0.13",
+            "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz",
+            "integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==",
+            "requires": {
+                "@babel/runtime": "^7.23.8",
+                "tslib": "^2.6.2"
+            }
+        },
+        "fast-uri": {
+            "version": "3.0.6",
+            "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
+            "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="
+        },
+        "finalhandler": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+            "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
+            "requires": {
+                "debug": "2.6.9",
+                "encodeurl": "~2.0.0",
+                "escape-html": "~1.0.3",
+                "on-finished": "2.4.1",
+                "parseurl": "~1.3.3",
+                "statuses": "2.0.1",
+                "unpipe": "~1.0.0"
+            }
+        },
+        "follow-redirects": {
+            "version": "1.15.9",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+            "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="
+        },
+        "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==",
+            "requires": {
+                "cross-spawn": "^7.0.0",
+                "signal-exit": "^4.0.1"
+            }
+        },
+        "form-data": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+            "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+            "requires": {
+                "asynckit": "^0.4.0",
+                "combined-stream": "^1.0.8",
+                "mime-types": "^2.1.12"
+            }
+        },
+        "form-data-encoder": {
+            "version": "2.1.4",
+            "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
+            "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw=="
+        },
+        "forwarded": {
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+            "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+        },
+        "fresh": {
+            "version": "0.5.2",
+            "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+            "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
+        },
+        "fs-extra": {
+            "version": "11.2.0",
+            "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
+            "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
+            "requires": {
+                "graceful-fs": "^4.2.0",
+                "jsonfile": "^6.0.1",
+                "universalify": "^2.0.0"
+            }
+        },
+        "function-bind": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+            "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
+        },
+        "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==",
+            "requires": {
+                "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"
+            }
+        },
+        "get-proto": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+            "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+            "requires": {
+                "dunder-proto": "^1.0.1",
+                "es-object-atoms": "^1.0.0"
+            }
+        },
+        "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=="
+        },
+        "glob": {
+            "version": "10.4.5",
+            "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+            "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+            "requires": {
+                "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"
+            }
+        },
+        "gopd": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+            "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
+        },
+        "got": {
+            "version": "12.6.1",
+            "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz",
+            "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==",
+            "requires": {
+                "@sindresorhus/is": "^5.2.0",
+                "@szmarczak/http-timer": "^5.0.1",
+                "cacheable-lookup": "^7.0.0",
+                "cacheable-request": "^10.2.8",
+                "decompress-response": "^6.0.0",
+                "form-data-encoder": "^2.1.2",
+                "get-stream": "^6.0.1",
+                "http2-wrapper": "^2.1.10",
+                "lowercase-keys": "^3.0.0",
+                "p-cancelable": "^3.0.0",
+                "responselike": "^3.0.0"
+            }
+        },
+        "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=="
+        },
+        "has-symbols": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+            "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="
+        },
+        "hash-sum": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz",
+            "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg=="
+        },
+        "hasown": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+            "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+            "requires": {
+                "function-bind": "^1.1.2"
+            }
+        },
+        "help-me": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
+            "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="
+        },
+        "hpagent": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz",
+            "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA=="
+        },
+        "htmlparser2": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
+            "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
+            "requires": {
+                "domelementtype": "^2.0.1",
+                "domhandler": "^4.0.0",
+                "domutils": "^2.5.2",
+                "entities": "^2.0.0"
+            }
+        },
+        "http-cache-semantics": {
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+            "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
+        },
+        "http-errors": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+            "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+            "requires": {
+                "depd": "2.0.0",
+                "inherits": "2.0.4",
+                "setprototypeof": "1.2.0",
+                "statuses": "2.0.1",
+                "toidentifier": "1.0.1"
+            }
+        },
+        "http2-wrapper": {
+            "version": "2.2.1",
+            "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz",
+            "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==",
+            "requires": {
+                "quick-lru": "^5.1.1",
+                "resolve-alpn": "^1.2.0"
+            }
+        },
+        "https-proxy-agent": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+            "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+            "requires": {
+                "agent-base": "6",
+                "debug": "4"
+            },
+            "dependencies": {
+                "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==",
+                    "requires": {
+                        "ms": "^2.1.3"
+                    }
+                },
+                "ms": {
+                    "version": "2.1.3",
+                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+                    "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+                }
+            }
+        },
+        "i18next": {
+            "version": "21.10.0",
+            "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.10.0.tgz",
+            "integrity": "sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==",
+            "requires": {
+                "@babel/runtime": "^7.17.2"
+            }
+        },
+        "iconv-lite": {
+            "version": "0.6.3",
+            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+            "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+            "requires": {
+                "safer-buffer": ">= 2.1.2 < 3.0.0"
+            }
+        },
+        "ieee754": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+            "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+        },
+        "inherits": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+        },
+        "ipaddr.js": {
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+            "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+        },
+        "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=="
+        },
+        "is-utf8": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+            "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q=="
+        },
+        "isarray": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+            "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+        },
+        "isexe": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+            "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+        },
+        "jackspeak": {
+            "version": "3.4.3",
+            "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+            "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+            "requires": {
+                "@isaacs/cliui": "^8.0.2",
+                "@pkgjs/parseargs": "^0.11.0"
+            }
+        },
+        "js-sdsl": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
+            "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ=="
+        },
+        "js-yaml": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+            "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+            "requires": {
+                "argparse": "^2.0.1"
+            }
+        },
+        "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=="
+        },
+        "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=="
+        },
+        "json-stringify-safe": {
+            "version": "5.0.1",
+            "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+            "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
+        },
+        "jsonata": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/jsonata/-/jsonata-2.0.5.tgz",
+            "integrity": "sha512-wEse9+QLIIU5IaCgtJCPsFi/H4F3qcikWzF4bAELZiRz08ohfx3Q6CjDRf4ZPF5P/92RI3KIHtb7u3jqPaHXdQ=="
+        },
+        "jsonfile": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+            "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+            "requires": {
+                "graceful-fs": "^4.1.6",
+                "universalify": "^2.0.0"
+            }
+        },
+        "keyv": {
+            "version": "4.5.4",
+            "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+            "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+            "requires": {
+                "json-buffer": "3.0.1"
+            }
+        },
+        "lodash.clonedeep": {
+            "version": "4.5.0",
+            "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+            "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
+        },
+        "lowercase-keys": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
+            "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ=="
+        },
+        "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==",
+            "requires": {
+                "pseudomap": "^1.0.2",
+                "yallist": "^2.1.2"
+            }
+        },
+        "math-intrinsics": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+            "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="
+        },
+        "media-typer": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+            "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="
+        },
+        "memorystore": {
+            "version": "1.6.7",
+            "resolved": "https://registry.npmjs.org/memorystore/-/memorystore-1.6.7.tgz",
+            "integrity": "sha512-OZnmNY/NDrKohPQ+hxp0muBcBKrzKNtHr55DbqSx9hLsYVNnomSAMRAtI7R64t3gf3ID7tHQA7mG4oL3Hu9hdw==",
+            "requires": {
+                "debug": "^4.3.0",
+                "lru-cache": "^4.0.3"
+            },
+            "dependencies": {
+                "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==",
+                    "requires": {
+                        "ms": "^2.1.3"
+                    }
+                },
+                "ms": {
+                    "version": "2.1.3",
+                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+                    "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+                }
+            }
+        },
+        "merge-descriptors": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+            "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="
+        },
+        "methods": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+            "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
+        },
+        "mime": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
+            "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="
+        },
+        "mime-db": {
+            "version": "1.52.0",
+            "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+            "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+        },
+        "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==",
+            "requires": {
+                "mime-db": "1.52.0"
+            }
+        },
+        "mimic-response": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
+            "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg=="
+        },
+        "minimatch": {
+            "version": "9.0.5",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+            "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+            "requires": {
+                "brace-expansion": "^2.0.1"
+            }
+        },
+        "minimist": {
+            "version": "1.2.8",
+            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+            "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
+        },
+        "minipass": {
+            "version": "7.1.2",
+            "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+            "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
+        },
+        "minizlib": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz",
+            "integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==",
+            "requires": {
+                "minipass": "^7.0.4",
+                "rimraf": "^5.0.5"
+            }
+        },
+        "mkdirp": {
+            "version": "0.5.6",
+            "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+            "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+            "requires": {
+                "minimist": "^1.2.6"
+            }
+        },
+        "moment": {
+            "version": "2.30.1",
+            "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
+            "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="
+        },
+        "moment-timezone": {
+            "version": "0.5.46",
+            "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.46.tgz",
+            "integrity": "sha512-ZXm9b36esbe7OmdABqIWJuBBiLLwAjrN7CE+7sYdCCx82Nabt1wHDj8TVseS59QIlfFPbOoiBPm6ca9BioG4hw==",
+            "requires": {
+                "moment": "^2.29.4"
+            }
+        },
+        "mqtt": {
+            "version": "5.7.0",
+            "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.7.0.tgz",
+            "integrity": "sha512-/o0CBYSjZzddmQDV2iglCafsA0xWKpqnS62tGbOLOliubBxszpXO1DAQPyfI7ZcPDG0b9ni7QITn+5FW1E2UTg==",
+            "requires": {
+                "@types/readable-stream": "^4.0.5",
+                "@types/ws": "^8.5.9",
+                "commist": "^3.2.0",
+                "concat-stream": "^2.0.0",
+                "debug": "^4.3.4",
+                "help-me": "^5.0.0",
+                "lru-cache": "^10.0.1",
+                "minimist": "^1.2.8",
+                "mqtt": "^5.2.0",
+                "mqtt-packet": "^9.0.0",
+                "number-allocator": "^1.0.14",
+                "readable-stream": "^4.4.2",
+                "reinterval": "^1.1.0",
+                "rfdc": "^1.3.0",
+                "split2": "^4.2.0",
+                "worker-timers": "^7.1.4",
+                "ws": "^8.14.2"
+            },
+            "dependencies": {
+                "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==",
+                    "requires": {
+                        "ms": "^2.1.3"
+                    }
+                },
+                "lru-cache": {
+                    "version": "10.4.3",
+                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+                    "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
+                },
+                "ms": {
+                    "version": "2.1.3",
+                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+                    "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+                },
+                "ws": {
+                    "version": "8.18.0",
+                    "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+                    "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+                    "requires": {}
+                }
+            }
+        },
+        "mqtt-packet": {
+            "version": "9.0.1",
+            "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.1.tgz",
+            "integrity": "sha512-koZF1V/X2RZUI6uD9wN5OK1JxxcG1ofAR4H3LjCw1FkeKzruZQ26aAA6v2m1lZyWONZIR5wMMJFrZJDRNzbiQw==",
+            "requires": {
+                "bl": "^6.0.8",
+                "debug": "^4.3.4",
+                "process-nextick-args": "^2.0.1"
+            },
+            "dependencies": {
+                "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==",
+                    "requires": {
+                        "ms": "^2.1.3"
+                    }
+                },
+                "ms": {
+                    "version": "2.1.3",
+                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+                    "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+                }
+            }
+        },
+        "ms": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+            "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+        },
+        "multer": {
+            "version": "1.4.5-lts.1",
+            "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
+            "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
+            "requires": {
+                "append-field": "^1.0.0",
+                "busboy": "^1.0.0",
+                "concat-stream": "^1.5.2",
+                "mkdirp": "^0.5.4",
+                "object-assign": "^4.1.1",
+                "type-is": "^1.6.4",
+                "xtend": "^4.0.0"
+            },
+            "dependencies": {
+                "concat-stream": {
+                    "version": "1.6.2",
+                    "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+                    "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+                    "requires": {
+                        "buffer-from": "^1.0.0",
+                        "inherits": "^2.0.3",
+                        "readable-stream": "^2.2.2",
+                        "typedarray": "^0.0.6"
+                    }
+                },
+                "readable-stream": {
+                    "version": "2.3.8",
+                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+                    "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+                    "requires": {
+                        "core-util-is": "~1.0.0",
+                        "inherits": "~2.0.3",
+                        "isarray": "~1.0.0",
+                        "process-nextick-args": "~2.0.0",
+                        "safe-buffer": "~5.1.1",
+                        "string_decoder": "~1.1.1",
+                        "util-deprecate": "~1.0.1"
+                    }
+                },
+                "string_decoder": {
+                    "version": "1.1.1",
+                    "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+                    "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+                    "requires": {
+                        "safe-buffer": "~5.1.0"
+                    }
+                }
+            }
+        },
+        "mustache": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+            "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="
+        },
+        "mute-stream": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz",
+            "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="
+        },
+        "negotiator": {
+            "version": "0.6.3",
+            "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+            "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+        },
+        "node-red-admin": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/node-red-admin/-/node-red-admin-4.0.1.tgz",
+            "integrity": "sha512-NLZgAM8JgFa/2/7Z4+nSSQrtkuBbfS9m+kxegadhHfuta5rErOx6zrrNhF+yAglMTPlVmdoqgso7VSt3nTRBGQ==",
+            "requires": {
+                "@node-rs/bcrypt": "1.10.4",
+                "ansi-colors": "^4.1.3",
+                "axios": "^1.7.7",
+                "bcryptjs": "^2.4.3",
+                "cli-table": "^0.3.11",
+                "enquirer": "^2.3.6",
+                "minimist": "^1.2.8",
+                "mustache": "^4.2.0",
+                "read": "^3.0.1"
+            }
+        },
+        "node-watch": {
+            "version": "0.7.4",
+            "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.4.tgz",
+            "integrity": "sha512-RinNxoz4W1cep1b928fuFhvAQ5ag/+1UlMDV7rbyGthBIgsiEouS4kvRayvvboxii4m8eolKOIBo3OjDqbc+uQ=="
+        },
+        "nopt": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+            "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+            "requires": {
+                "abbrev": "1"
+            }
+        },
+        "normalize-url": {
+            "version": "8.0.1",
+            "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz",
+            "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w=="
+        },
+        "nth-check": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+            "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+            "requires": {
+                "boolbase": "^1.0.0"
+            }
+        },
+        "number-allocator": {
+            "version": "1.0.14",
+            "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
+            "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
+            "requires": {
+                "debug": "^4.3.1",
+                "js-sdsl": "4.3.0"
+            },
+            "dependencies": {
+                "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==",
+                    "requires": {
+                        "ms": "^2.1.3"
+                    }
+                },
+                "ms": {
+                    "version": "2.1.3",
+                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+                    "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+                }
+            }
+        },
+        "oauth2orize": {
+            "version": "1.12.0",
+            "resolved": "https://registry.npmjs.org/oauth2orize/-/oauth2orize-1.12.0.tgz",
+            "integrity": "sha512-j4XtFDQUBsvUHPjUmvmNDUDMYed2MphMIJBhyxVVe8hGCjkuYnjIsW+D9qk8c5ciXRdnk6x6tEbiO6PLeOZdCQ==",
+            "requires": {
+                "debug": "2.x.x",
+                "uid2": "0.0.x",
+                "utils-merge": "1.x.x"
+            }
+        },
+        "object-assign": {
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+            "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
+        },
+        "object-inspect": {
+            "version": "1.13.3",
+            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
+            "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA=="
+        },
+        "on-finished": {
+            "version": "2.4.1",
+            "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+            "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+            "requires": {
+                "ee-first": "1.1.1"
+            }
+        },
+        "on-headers": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+            "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
+        },
+        "p-cancelable": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
+            "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw=="
+        },
+        "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=="
+        },
+        "parse5": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+            "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
+        },
+        "parse5-htmlparser2-tree-adapter": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
+            "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
+            "requires": {
+                "parse5": "^6.0.1"
+            }
+        },
+        "parseurl": {
+            "version": "1.3.3",
+            "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+            "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+        },
+        "passport": {
+            "version": "0.7.0",
+            "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz",
+            "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==",
+            "requires": {
+                "passport-strategy": "1.x.x",
+                "pause": "0.0.1",
+                "utils-merge": "^1.0.1"
+            }
+        },
+        "passport-http-bearer": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/passport-http-bearer/-/passport-http-bearer-1.0.1.tgz",
+            "integrity": "sha512-SELQM+dOTuMigr9yu8Wo4Fm3ciFfkMq5h/ZQ8ffi4ELgZrX1xh9PlglqZdcUZ1upzJD/whVyt+YWF62s3U6Ipw==",
+            "requires": {
+                "passport-strategy": "1.x.x"
+            }
+        },
+        "passport-oauth2-client-password": {
+            "version": "0.1.2",
+            "resolved": "https://registry.npmjs.org/passport-oauth2-client-password/-/passport-oauth2-client-password-0.1.2.tgz",
+            "integrity": "sha512-GHQH4UtaEZvCLulAxGKHYoSsPRoPRmGsdmaZtMh5nmz80yMLQbdMA9Bg2sp4/UW3PIxJH/143hVjPTiXaNngTQ==",
+            "requires": {
+                "passport-strategy": "1.x.x"
+            }
+        },
+        "passport-strategy": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
+            "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA=="
+        },
+        "path-key": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+            "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
+        },
+        "path-scurry": {
+            "version": "1.11.1",
+            "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+            "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+            "requires": {
+                "lru-cache": "^10.2.0",
+                "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+            },
+            "dependencies": {
+                "lru-cache": {
+                    "version": "10.4.3",
+                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+                    "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
+                }
+            }
+        },
+        "path-to-regexp": {
+            "version": "0.1.12",
+            "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+            "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
+        },
+        "pause": {
+            "version": "0.0.1",
+            "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
+            "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
+        },
+        "process": {
+            "version": "0.11.10",
+            "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+            "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="
+        },
+        "process-nextick-args": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+            "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+        },
+        "proxy-addr": {
+            "version": "2.0.7",
+            "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+            "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+            "requires": {
+                "forwarded": "0.2.0",
+                "ipaddr.js": "1.9.1"
+            }
+        },
+        "proxy-from-env": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+            "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+        },
+        "pseudomap": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+            "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="
+        },
+        "qs": {
+            "version": "6.13.0",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+            "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+            "requires": {
+                "side-channel": "^1.0.6"
+            }
+        },
+        "quick-lru": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+            "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
+        },
+        "random-bytes": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+            "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ=="
+        },
+        "range-parser": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+            "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+        },
+        "raw-body": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
+            "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
+            "requires": {
+                "bytes": "3.1.2",
+                "http-errors": "2.0.0",
+                "iconv-lite": "0.6.3",
+                "unpipe": "1.0.0"
+            }
+        },
+        "read": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/read/-/read-3.0.1.tgz",
+            "integrity": "sha512-SLBrDU/Srs/9EoWhU5GdbAoxG1GzpQHo/6qiGItaoLJ1thmYpcNIM1qISEUvyHBzfGlWIyd6p2DNi1oV1VmAuw==",
+            "requires": {
+                "mute-stream": "^1.0.0"
+            }
+        },
+        "readable-stream": {
+            "version": "4.7.0",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+            "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+            "requires": {
+                "abort-controller": "^3.0.0",
+                "buffer": "^6.0.3",
+                "events": "^3.3.0",
+                "process": "^0.11.10",
+                "string_decoder": "^1.3.0"
+            }
+        },
+        "regenerator-runtime": {
+            "version": "0.14.1",
+            "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+            "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
+        },
+        "reinterval": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz",
+            "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ=="
+        },
+        "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=="
+        },
+        "resolve-alpn": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
+            "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
+        },
+        "responselike": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
+            "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
+            "requires": {
+                "lowercase-keys": "^3.0.0"
+            }
+        },
+        "rfdc": {
+            "version": "1.4.1",
+            "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+            "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
+        },
+        "rimraf": {
+            "version": "5.0.10",
+            "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
+            "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
+            "requires": {
+                "glob": "^10.3.7"
+            }
+        },
+        "safe-buffer": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+            "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+        },
+        "safer-buffer": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+        },
+        "sax": {
+            "version": "1.4.1",
+            "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+            "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
+        },
+        "semver": {
+            "version": "7.6.3",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+            "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="
+        },
+        "send": {
+            "version": "0.19.0",
+            "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+            "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
+            "requires": {
+                "debug": "2.6.9",
+                "depd": "2.0.0",
+                "destroy": "1.2.0",
+                "encodeurl": "~1.0.2",
+                "escape-html": "~1.0.3",
+                "etag": "~1.8.1",
+                "fresh": "0.5.2",
+                "http-errors": "2.0.0",
+                "mime": "1.6.0",
+                "ms": "2.1.3",
+                "on-finished": "2.4.1",
+                "range-parser": "~1.2.1",
+                "statuses": "2.0.1"
+            },
+            "dependencies": {
+                "encodeurl": {
+                    "version": "1.0.2",
+                    "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+                    "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
+                },
+                "mime": {
+                    "version": "1.6.0",
+                    "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+                    "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+                },
+                "ms": {
+                    "version": "2.1.3",
+                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+                    "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+                }
+            }
+        },
+        "serve-static": {
+            "version": "1.16.2",
+            "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+            "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
+            "requires": {
+                "encodeurl": "~2.0.0",
+                "escape-html": "~1.0.3",
+                "parseurl": "~1.3.3",
+                "send": "0.19.0"
+            }
+        },
+        "setprototypeof": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+            "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+        },
+        "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==",
+            "requires": {
+                "shebang-regex": "^3.0.0"
+            }
+        },
+        "shebang-regex": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+            "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
+        },
+        "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==",
+            "requires": {
+                "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"
+            }
+        },
+        "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==",
+            "requires": {
+                "es-errors": "^1.3.0",
+                "object-inspect": "^1.13.3"
+            }
+        },
+        "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==",
+            "requires": {
+                "call-bound": "^1.0.2",
+                "es-errors": "^1.3.0",
+                "get-intrinsic": "^1.2.5",
+                "object-inspect": "^1.13.3"
+            }
+        },
+        "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==",
+            "requires": {
+                "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"
+            }
+        },
+        "signal-exit": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+            "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="
+        },
+        "split2": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+            "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="
+        },
+        "statuses": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+            "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+        },
+        "streamsearch": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+            "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
+        },
+        "string_decoder": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+            "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+            "requires": {
+                "safe-buffer": "~5.2.0"
+            },
+            "dependencies": {
+                "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=="
+                }
+            }
+        },
+        "string-width": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+            "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+            "requires": {
+                "eastasianwidth": "^0.2.0",
+                "emoji-regex": "^9.2.2",
+                "strip-ansi": "^7.0.1"
+            },
+            "dependencies": {
+                "ansi-regex": {
+                    "version": "6.1.0",
+                    "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+                    "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="
+                },
+                "strip-ansi": {
+                    "version": "7.1.0",
+                    "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+                    "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+                    "requires": {
+                        "ansi-regex": "^6.0.1"
+                    }
+                }
+            }
+        },
+        "string-width-cjs": {
+            "version": "npm:string-width@4.2.3",
+            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+            "requires": {
+                "emoji-regex": "^8.0.0",
+                "is-fullwidth-code-point": "^3.0.0",
+                "strip-ansi": "^6.0.1"
+            },
+            "dependencies": {
+                "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=="
+                }
+            }
+        },
+        "strip-ansi": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+            "requires": {
+                "ansi-regex": "^5.0.1"
+            }
+        },
+        "strip-ansi-cjs": {
+            "version": "npm:strip-ansi@6.0.1",
+            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+            "requires": {
+                "ansi-regex": "^5.0.1"
+            }
+        },
+        "tar": {
+            "version": "7.4.3",
+            "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
+            "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
+            "requires": {
+                "@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"
+            },
+            "dependencies": {
+                "mkdirp": {
+                    "version": "3.0.1",
+                    "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+                    "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="
+                },
+                "yallist": {
+                    "version": "5.0.0",
+                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+                    "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="
+                }
+            }
+        },
+        "tldts": {
+            "version": "6.1.73",
+            "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.73.tgz",
+            "integrity": "sha512-/h4bVmuEMm57c2uCiAf1Q9mlQk7cA22m+1Bu0K92vUUtTVT9D4mOFWD9r4WQuTULcG9eeZtNKhLl0Il1LdKGog==",
+            "requires": {
+                "tldts-core": "^6.1.73"
+            }
+        },
+        "tldts-core": {
+            "version": "6.1.73",
+            "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.73.tgz",
+            "integrity": "sha512-k1g5eX87vxu3g//6XMn62y4qjayu4cYby/PF7Ksnh4F4uUK1Z1ze/mJ4a+y5OjdJ+cXRp+YTInZhH+FGdUWy1w=="
+        },
+        "toidentifier": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+            "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+        },
+        "tough-cookie": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.0.tgz",
+            "integrity": "sha512-rvZUv+7MoBYTiDmFPBrhL7Ujx9Sk+q9wwm22x8c8T5IJaR+Wsyc7TNxbVxo84kZoRJZZMazowFLqpankBEQrGg==",
+            "requires": {
+                "tldts": "^6.1.32"
+            }
+        },
+        "tslib": {
+            "version": "2.8.1",
+            "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+            "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
+        },
+        "type-is": {
+            "version": "1.6.18",
+            "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+            "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+            "requires": {
+                "media-typer": "0.3.0",
+                "mime-types": "~2.1.24"
+            },
+            "dependencies": {
+                "media-typer": {
+                    "version": "0.3.0",
+                    "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+                    "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
+                }
+            }
+        },
+        "typedarray": {
+            "version": "0.0.6",
+            "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+            "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
+        },
+        "uglify-js": {
+            "version": "3.17.4",
+            "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
+            "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g=="
+        },
+        "uid-safe": {
+            "version": "2.1.5",
+            "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
+            "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
+            "requires": {
+                "random-bytes": "~1.0.0"
+            }
+        },
+        "uid2": {
+            "version": "0.0.4",
+            "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz",
+            "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA=="
+        },
+        "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=="
+        },
+        "universalify": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+            "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="
+        },
+        "unpipe": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+            "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
+        },
+        "util-deprecate": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+            "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+        },
+        "utils-merge": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+            "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
+        },
+        "uuid": {
+            "version": "9.0.1",
+            "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+            "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="
+        },
+        "vary": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+            "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
+        },
+        "which": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+            "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+            "requires": {
+                "isexe": "^2.0.0"
+            }
+        },
+        "worker-timers": {
+            "version": "7.1.8",
+            "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz",
+            "integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==",
+            "requires": {
+                "@babel/runtime": "^7.24.5",
+                "tslib": "^2.6.2",
+                "worker-timers-broker": "^6.1.8",
+                "worker-timers-worker": "^7.0.71"
+            }
+        },
+        "worker-timers-broker": {
+            "version": "6.1.8",
+            "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz",
+            "integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==",
+            "requires": {
+                "@babel/runtime": "^7.24.5",
+                "fast-unique-numbers": "^8.0.13",
+                "tslib": "^2.6.2",
+                "worker-timers-worker": "^7.0.71"
+            }
+        },
+        "worker-timers-worker": {
+            "version": "7.0.71",
+            "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz",
+            "integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==",
+            "requires": {
+                "@babel/runtime": "^7.24.5",
+                "tslib": "^2.6.2"
+            }
+        },
+        "wrap-ansi": {
+            "version": "8.1.0",
+            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+            "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+            "requires": {
+                "ansi-styles": "^6.1.0",
+                "string-width": "^5.0.1",
+                "strip-ansi": "^7.0.1"
+            },
+            "dependencies": {
+                "ansi-regex": {
+                    "version": "6.1.0",
+                    "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+                    "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="
+                },
+                "strip-ansi": {
+                    "version": "7.1.0",
+                    "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+                    "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+                    "requires": {
+                        "ansi-regex": "^6.0.1"
+                    }
+                }
+            }
+        },
+        "wrap-ansi-cjs": {
+            "version": "npm:wrap-ansi@7.0.0",
+            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+            "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+            "requires": {
+                "ansi-styles": "^4.0.0",
+                "string-width": "^4.1.0",
+                "strip-ansi": "^6.0.0"
+            },
+            "dependencies": {
+                "ansi-styles": {
+                    "version": "4.3.0",
+                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+                    "requires": {
+                        "color-convert": "^2.0.1"
+                    }
+                },
+                "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=="
+                },
+                "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==",
+                    "requires": {
+                        "emoji-regex": "^8.0.0",
+                        "is-fullwidth-code-point": "^3.0.0",
+                        "strip-ansi": "^6.0.1"
+                    }
+                }
+            }
+        },
+        "ws": {
+            "version": "7.5.10",
+            "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+            "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
+            "requires": {}
+        },
+        "xml2js": {
+            "version": "0.6.2",
+            "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
+            "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
+            "requires": {
+                "sax": ">=0.6.0",
+                "xmlbuilder": "~11.0.0"
+            }
+        },
+        "xmlbuilder": {
+            "version": "11.0.1",
+            "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+            "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
+        },
+        "xtend": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+            "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
+        },
+        "yallist": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+            "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
+        }
+    }
+}
diff --git a/meta-selftest/recipes-support/node-red/node-red_4.0.8.bb b/meta-selftest/recipes-support/node-red/node-red_4.0.8.bb
new file mode 100644
index 0000000000..a6ee292516
--- /dev/null
+++ b/meta-selftest/recipes-support/node-red/node-red_4.0.8.bb
@@ -0,0 +1,14 @@
+SUMMARY = "Low-code programming for event-driven applications."
+HOMEPAGE = "https://nodered.org/"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=014f1a23c3da49aa929b21a96808ab22"
+
+SRC_URI = "\
+    ${@npm_src_uri(d)} \
+    file://package-lock.json;subdir=${BP} \
+"
+SRC_URI[sha256sum] = "b933f8a243fb350c7839ff5f486643584f189ebee93c7d3aaa56580dcd91baad"
+
+inherit vendor_npm
+
+INSANE_SKIP:${PN} = "already-stripped arch file-rdeps ldflags"
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 29/30] [DO NOT MERGE] recipes: add nucleoidai npm demo
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (27 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 28/30] [DO NOT MERGE] recipes: add node-red npm demo Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 15:00 ` [RFC PATCH 30/30] [DO NOT MERGE] classes: spdx: use version 2.2 Stefan Herbrechtsmeier
  2025-02-11 23:14 ` [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust Bruce Ashfield
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 .../recipes-support/nucleoidai/nucleoidai_0.7.10.bb   | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 meta-selftest/recipes-support/nucleoidai/nucleoidai_0.7.10.bb

diff --git a/meta-selftest/recipes-support/nucleoidai/nucleoidai_0.7.10.bb b/meta-selftest/recipes-support/nucleoidai/nucleoidai_0.7.10.bb
new file mode 100644
index 0000000000..c4645a73d1
--- /dev/null
+++ b/meta-selftest/recipes-support/nucleoidai/nucleoidai_0.7.10.bb
@@ -0,0 +1,11 @@
+SUMMARY = "Declarative (Logic) Runtime Environment"
+HOMEPAGE = "https://nucleoid.com/"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=b60cddf6d0f2277da4bda65332fe232e"
+
+SRC_URI = "git://github.com/NucleoidAI/Nucleoid.git;protocol=https;nobranch=1"
+SRCREV = "f1d480bce6e13a64cba29e31d904c5559a0b8f82"
+
+S = "${WORKDIR}/git"
+
+inherit vendor_npm
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH 30/30] [DO NOT MERGE] classes: spdx: use version 2.2
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (28 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 29/30] [DO NOT MERGE] recipes: add nucleoidai " Stefan Herbrechtsmeier
@ 2025-02-11 15:00 ` Stefan Herbrechtsmeier
  2025-02-11 23:14 ` [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust Bruce Ashfield
  30 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-11 15:00 UTC (permalink / raw)
  To: openembedded-core; +Cc: Stefan Herbrechtsmeier

From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
---

 meta/classes/create-spdx.bbclass | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/meta/classes/create-spdx.bbclass b/meta/classes/create-spdx.bbclass
index b604973ae0..19c6c0ff0b 100644
--- a/meta/classes/create-spdx.bbclass
+++ b/meta/classes/create-spdx.bbclass
@@ -5,4 +5,4 @@
 #
 # Include this class when you don't care what version of SPDX you get; it will
 # be updated to the latest stable version that is supported
-inherit create-spdx-3.0
+inherit create-spdx-2.2
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 75+ messages in thread

* RE: [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
  2025-02-11 15:00 ` [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable Stefan Herbrechtsmeier
@ 2025-02-11 16:22   ` Peter Kjellerstedt
  2025-02-12  8:55     ` Stefan Herbrechtsmeier
  2025-02-11 19:06   ` Peter Kjellerstedt
  1 sibling, 1 reply; 75+ messages in thread
From: Peter Kjellerstedt @ 2025-02-11 16:22 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss@weidmueller.com,
	openembedded-core@lists.openembedded.org
  Cc: Stefan Herbrechtsmeier, bitbake-devel@lists.openembedded.org

> -----Original Message-----
> From: bitbake-devel@lists.openembedded.org <bitbake-devel@lists.openembedded.org> On Behalf Of Stefan Herbrechtsmeier via lists.openembedded.org
> Sent: den 11 februari 2025 16:00
> To: openembedded-core@lists.openembedded.org
> Cc: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>; bitbake-devel@lists.openembedded.org
> Subject: [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
> 
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> Add the variable SRC_URI_FILES to collect files whichs contains
> additional SRC_URI lines.
> 
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> ---
> 
>  meta/conf/bitbake.conf | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf
> index 8b607088c6..ed67500ba7 100644
> --- a/meta/conf/bitbake.conf
> +++ b/meta/conf/bitbake.conf
> @@ -745,6 +745,7 @@ AUTOREV = "${@bb.fetch2.get_autorev(d)}"
>  SRCPV = ""
> 
>  SRC_URI = ""
> +SRC_URI_FILES = ""

Do we really need a new variable for this? Can't you add some parameter 
instead to the URIs that should be handled separately?

If a parameter is not appropriate, then the name of the variable should 
be reconsidered. Based on the name it is unclear what is expected to go 
in SRC_URI and what should go in SRC_URI_FILES.

> 
>  # Use pseudo as the fakeroot implementation
>  PSEUDO_LOCALSTATEDIR ?= "${WORKDIR}/pseudo/"
> --
> 2.39.5

//Peter



^ permalink raw reply	[flat|nested] 75+ messages in thread

* RE: [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
  2025-02-11 15:00 ` [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable Stefan Herbrechtsmeier
  2025-02-11 16:22   ` [bitbake-devel] " Peter Kjellerstedt
@ 2025-02-11 19:06   ` Peter Kjellerstedt
  1 sibling, 0 replies; 75+ messages in thread
From: Peter Kjellerstedt @ 2025-02-11 19:06 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss@weidmueller.com,
	openembedded-core@lists.openembedded.org
  Cc: Stefan Herbrechtsmeier

> -----Original Message-----
> From: bitbake-devel@lists.openembedded.org <bitbake-devel@lists.openembedded.org> On Behalf Of Stefan Herbrechtsmeier via lists.openembedded.org
> Sent: den 11 februari 2025 16:00
> To: openembedded-core@lists.openembedded.org
> Cc: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>; bitbake-devel@lists.openembedded.org
> Subject: [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable

Using "bitbake.conf:" as prefix would be more fitting.

//Peter

> 
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> Add the variable SRC_URI_FILES to collect files whichs contains
> additional SRC_URI lines.
> 
> Signed-off-by: Stefan Herbrechtsmeier
> <stefan.herbrechtsmeier@weidmueller.com>
> ---
> 
>  meta/conf/bitbake.conf | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf
> index 8b607088c6..ed67500ba7 100644
> --- a/meta/conf/bitbake.conf
> +++ b/meta/conf/bitbake.conf
> @@ -745,6 +745,7 @@ AUTOREV = "${@bb.fetch2.get_autorev(d)}"
>  SRCPV = ""
> 
>  SRC_URI = ""
> +SRC_URI_FILES = ""
> 
>  # Use pseudo as the fakeroot implementation
>  PSEUDO_LOCALSTATEDIR ?= "${WORKDIR}/pseudo/"
> --
> 2.39.5



^ permalink raw reply	[flat|nested] 75+ messages in thread

* RE: [OE-core] [RFC PATCH 16/30] classes: add vendor class
  2025-02-11 15:00 ` [RFC PATCH 16/30] classes: add vendor class Stefan Herbrechtsmeier
@ 2025-02-11 19:17   ` Peter Kjellerstedt
  0 siblings, 0 replies; 75+ messages in thread
From: Peter Kjellerstedt @ 2025-02-11 19:17 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss@weidmueller.com,
	openembedded-core@lists.openembedded.org
  Cc: Stefan Herbrechtsmeier

> -----Original Message-----
> From: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> On Behalf Of Stefan Herbrechtsmeier via lists.openembedded.org
> Sent: den 11 februari 2025 16:00
> To: openembedded-core@lists.openembedded.org
> Cc: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> Subject: [OE-core] [RFC PATCH 16/30] classes: add vendor class

I suggest using "vendor.bbclass: Add bbclass" as subject instead.
And similar for the other commits that add new classes or updates 
existing ones. Using the actual file name as prefix makes it easier 
to see what is actually added/modified.

//Peter

> 
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> Add a common vendor class with a prototype for the do_vendor_resolve
> task and common dump and load SRC_URI_FILES function.
> 
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> ---
> 
>  meta/classes-recipe/vendor.bbclass | 28 ++++++++++++++++++++++++++++
>  1 file changed, 28 insertions(+)
>  create mode 100644 meta/classes-recipe/vendor.bbclass
> 
> diff --git a/meta/classes-recipe/vendor.bbclass b/meta/classes-
> recipe/vendor.bbclass
> new file mode 100644
> index 0000000000..a99c9a3121
> --- /dev/null
> +++ b/meta/classes-recipe/vendor.bbclass
> @@ -0,0 +1,28 @@
> +# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
> +# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> +#
> +# SPDX-License-Identifier: MIT
> +#
> +
> +VENDOR_DIR = "${WORKDIR}/vendor"
> +
> +inherit early
> +
> +def vendor_dump_uris(filepath, uris, d):
> +    import oe.vendor
> +    with open(filepath, "w") as f:
> +        oe.vendor.dump(f, uris)
> +
> +def vendor_load_uris(filepath, d):
> +    import oe.vendor
> +    with open(filepath, "r") as f:
> +        return oe.vendor.load(f)
> +
> +
> +python vendor_do_vendor_resolve() {
> +    vendor_dump_uris([], d)
> +}
> +addtask vendor_resolve after do_patch_early before do_fetch
> +do_vendor_resolve[cleandirs] += "${VENDOR_DIR}"
> +
> +EXPORT_FUNCTIONS do_vendor_resolve
> --
> 2.39.5



^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 04/30] lib: bb: fetch2: add support to unpack .crate files
  2025-02-11 15:00 ` [RFC PATCH 04/30] lib: bb: fetch2: add support to unpack .crate files Stefan Herbrechtsmeier
@ 2025-02-11 21:22   ` Richard Purdie
  0 siblings, 0 replies; 75+ messages in thread
From: Richard Purdie @ 2025-02-11 21:22 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss, openembedded-core; +Cc: Stefan Herbrechtsmeier

On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> ---
> 
>  bitbake/lib/bb/fetch2/__init__.py | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/bitbake/lib/bb/fetch2/__init__.py b/bitbake/lib/bb/fetch2/__init__.py
> index de36f06bfc..e4c489d059 100644
> --- a/bitbake/lib/bb/fetch2/__init__.py
> +++ b/bitbake/lib/bb/fetch2/__init__.py
> @@ -1533,7 +1533,7 @@ class FetchMethod(object):
>                  tar_cmd += ' --strip-components=%s' %  urldata.parm['striplevel']
>              if file.endswith('.tar'):
>                  cmd = '%s -f %s' % (tar_cmd, file)
> -            elif file.endswith('.tgz') or file.endswith('.tar.gz') or file.endswith('.tar.Z'):
> +            elif any(file.endswith(ext) for ext in {'.tgz', '.tar.gz', '.tar.Z', '.crate'}):
>                  cmd = '%s -z -f %s' % (tar_cmd, file)
>              elif file.endswith('.tbz') or file.endswith('.tbz2') or file.endswith('.tar.bz2'):
>                  cmd = 'bzip2 -dc %s | %s -f -' % (file, tar_cmd)

I think you can just do:

file.endswith(('.tgz', '.tar.gz', '.tar.Z', '.crate'))

Cheers,

Richard



^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 05/30] lib: oe: add vendor module
  2025-02-11 15:00 ` [RFC PATCH 05/30] lib: oe: add vendor module Stefan Herbrechtsmeier
@ 2025-02-11 21:31   ` Richard Purdie
  2025-02-12  9:27     ` Stefan Herbrechtsmeier
  0 siblings, 1 reply; 75+ messages in thread
From: Richard Purdie @ 2025-02-11 21:31 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss, openembedded-core; +Cc: Stefan Herbrechtsmeier

On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> Add a vendor package as base for package manager specific
> implementations to resolve dependencies and populate vendor directories.
> Add common dump and load function for SRC_URI files.
> 
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> ---
> 
>  meta/lib/oe/vendor/__init__.py | 28 ++++++++++++++++++++++++++++
>  1 file changed, 28 insertions(+)
>  create mode 100644 meta/lib/oe/vendor/__init__.py

Initially I was going to ask there to be a "fetch" or "download" in the
namespacing. That then made me wonder if in the interests of clarity
and namepacing, these vendor classes should go into
lib/bb/fetch2/vendor in bitbake?

I appreciate the class in OE will use them and separation into bitbake
can be a bit awkward but it would mean we don't confuse this with any
other kind of vendoring, it becomes fetch specific and it places them
alongside the fetch code, which it will need to remain tied to.

I do feel we need to namespace them though as vendor is not specific
enough to be directly in lib/oe.

Cheers,

Richard






^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-11 15:00 ` [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class Stefan Herbrechtsmeier
@ 2025-02-11 21:46   ` Richard Purdie
  2025-02-12 14:36     ` Stefan Herbrechtsmeier
  0 siblings, 1 reply; 75+ messages in thread
From: Richard Purdie @ 2025-02-11 21:46 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss, openembedded-core; +Cc: Stefan Herbrechtsmeier

On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> ---
> 
>  .../python/python3-bcrypt-crates.inc          | 84 -------------------
>  .../python/python3-bcrypt_4.2.1.bb            |  4 +-
>  2 files changed, 1 insertion(+), 87 deletions(-)
>  delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc

So let me as the silly question. This removes the crates.inc file and
doesn't appear to add any kind of new list of locked down modules. 

This means that inspection tools just using the metadata can't see
"into" this recipe any longer for component information. This was
something that some people felt strongly that was a necessary part of
recipe metadata, for license, security and other manifest activities.

Are we basically saying that information is now only available after
the build takes place?

I'm very worried that the previous discussions didn't reach a
conclusion and this is moving the "magic" out of bitbake and into some
vendor classes without addressing the concerns previously raised about
transparency into the manifests of what is going on behind the scenes.

I appreciate some of the requirements are conflicting.

For the record in some recent meetings, I was promised that help would
be forthcoming in helping guide this discussion. I therefore left
things alone in the hope that would happen. It simply hasn't, probably
due to time/work issues, which I can sympathise with but it does mean
I'm left doing a bad job of trying to respond to your patches whilst
trying to do too many other things badly too. That leaves us both very
frustrated.

I really want to see you succeed in reworking this and I appreciate the
time and effort put into the patches. To make this successful, I know
there are key stakeholders who need to buy into it and right now,
they're more likely just to keep doing their own things as it is easier
since this isn't going the direction they want. A key piece of making
this successful is negotiating something which can work for a
significant portion of them. I'm spelling all this out since I do at
least want to make the situation clear.

Yes, I'm very upset the OE community is putting me in this position
despite me repeatedly asking for help and that isn't your fault, which
just frustrates me more.

Cheers,

Richard






^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
  2025-02-11 15:00 ` [RFC PATCH 15/30] classes: add early fetch, unpack and patch support Stefan Herbrechtsmeier
@ 2025-02-11 22:27   ` Richard Purdie
  2025-02-12 12:21     ` Stefan Herbrechtsmeier
  2025-02-11 22:32   ` Bruce Ashfield
  2025-02-12 11:08   ` Alexander Kanavin
  2 siblings, 1 reply; 75+ messages in thread
From: Richard Purdie @ 2025-02-11 22:27 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss, openembedded-core; +Cc: Stefan Herbrechtsmeier

On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> Add support for early fetch, unpack and patches task which run before
> normal patch task. This feature is useful to fetch additional
> dependencies based on a patched source before the normal unpack and
> patch tasks. The patch are marked as early via an early=1 parameter. An
> example use case is a patch for a package manager lock file (Cargo.lock,
> go.sum, package-lock.json).
> 
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> ---
> 
>  meta/classes-global/patch.bbclass | 17 +++++----
>  meta/classes-recipe/early.bbclass | 61 +++++++++++++++++++++++++++++++
>  meta/lib/oe/patch.py              | 10 +++--
>  3 files changed, 77 insertions(+), 11 deletions(-)
>  create mode 100644 meta/classes-recipe/early.bbclass

This level of complexity is going to cause massive headaches in future.
Having two fetch, two unpack and two patch tasks will ultimately just
cause a lot of confusion and make things like the SPDX code and
archiver code more complex too.

Rather than patching a cargo lock file, I'd probably prefer the correct
version be added in a later SRC_URI entry and used to overwrite the
earlier one at unpack time.

I appreciate the challenge there is then that fetcher isn't going to
know what it is fetching at fetch time though as it would potentially
be fetching with the unpatched lock file.

This is partly why we end up with the .inc files the way we do, then it
is explicit.  I'm not sure the fetcher can know deterministically what
it is fetching in advance without the .inc data though, which is one of
the concerns that have been expressed previously.

Cheers,

Richard




^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
  2025-02-11 15:00 ` [RFC PATCH 15/30] classes: add early fetch, unpack and patch support Stefan Herbrechtsmeier
  2025-02-11 22:27   ` [OE-core] " Richard Purdie
@ 2025-02-11 22:32   ` Bruce Ashfield
  2025-02-12 12:42     ` Stefan Herbrechtsmeier
  2025-02-12 11:08   ` Alexander Kanavin
  2 siblings, 1 reply; 75+ messages in thread
From: Bruce Ashfield @ 2025-02-11 22:32 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss; +Cc: openembedded-core, Stefan Herbrechtsmeier

In message: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
on 11/02/2025 Stefan Herbrechtsmeier via lists.openembedded.org wrote:

> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> Add support for early fetch, unpack and patches task which run before
> normal patch task. This feature is useful to fetch additional
> dependencies based on a patched source before the normal unpack and
> patch tasks. The patch are marked as early via an early=1 parameter. An
> example use case is a patch for a package manager lock file (Cargo.lock,
> go.sum, package-lock.json).

I understand why you need to do the above, but there's now multiple
fetch and patch tasks running throughout the pipeline of the
build and that's just more complexity to maintain.

This is what I was asking about in some of my first replies
to the RFC series. When I've done this in the past, I'd just
suggest something simpler like the recipe provide a complete
"lock file" in the layer/recipe-space and have it overlayed
in the source.

Of course that means it is in the same fetch task as what
will be fetching the vendor bits, but coordinating within
the single task is simpler in my experience (and it can
be checked on the SRC_URI). I haven't fully thought through
how to manage it, but wanted to reply to this while it was
fresh in my mind.

Bruce

> 
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> ---
> 
>  meta/classes-global/patch.bbclass | 17 +++++----
>  meta/classes-recipe/early.bbclass | 61 +++++++++++++++++++++++++++++++
>  meta/lib/oe/patch.py              | 10 +++--
>  3 files changed, 77 insertions(+), 11 deletions(-)
>  create mode 100644 meta/classes-recipe/early.bbclass
> 
> diff --git a/meta/classes-global/patch.bbclass b/meta/classes-global/patch.bbclass
> index e5786b1c9a..7fa94c7aa7 100644
> --- a/meta/classes-global/patch.bbclass
> +++ b/meta/classes-global/patch.bbclass
> @@ -82,18 +82,18 @@ python patch_task_postfunc() {
>              oe.patch.GitApplyTree.commitIgnored("Add changes from %s" % func, dir=srcsubdir, files=['.'], d=d)
>  }
>  
> -def src_patches(d, all=False, expand=True):
> +def src_patches(d, all=False, expand=True, early=False):
>      import oe.patch
> -    return oe.patch.src_patches(d, all, expand)
> +    return oe.patch.src_patches(d, all, expand, early)
>  
> -def should_apply(parm, d):
> +def should_apply(parm, d, early=False):
>      """Determine if we should apply the given patch"""
>      import oe.patch
> -    return oe.patch.should_apply(parm, d)
> +    return oe.patch.should_apply(parm, d, early)
>  
>  should_apply[vardepsexclude] = "DATE SRCDATE"
>  
> -python patch_do_patch() {
> +def apply_patches(d, s, early=False):
>      import oe.patch
>  
>      patchsetmap = {
> @@ -113,8 +113,6 @@ python patch_do_patch() {
>  
>      classes = {}
>  
> -    s = d.getVar('S')
> -
>      os.putenv('PATH', d.getVar('PATH'))
>  
>      # We must use one TMPDIR per process so that the "patch" processes
> @@ -124,7 +122,7 @@ python patch_do_patch() {
>      process_tmpdir = tempfile.mkdtemp()
>      os.environ['TMPDIR'] = process_tmpdir
>  
> -    for patch in src_patches(d):
> +    for patch in src_patches(d, early=early):
>          _, _, local, _, _, parm = bb.fetch.decodeurl(patch)
>  
>          if "patchdir" in parm:
> @@ -159,6 +157,9 @@ python patch_do_patch() {
>  
>      bb.utils.remove(process_tmpdir, True)
>      del os.environ['TMPDIR']
> +
> +python patch_do_patch() {
> +    apply_patches(d, d.getVar('S'))
>  }
>  patch_do_patch[vardepsexclude] = "PATCHRESOLVE"
>  
> diff --git a/meta/classes-recipe/early.bbclass b/meta/classes-recipe/early.bbclass
> new file mode 100644
> index 0000000000..e458fd8f7b
> --- /dev/null
> +++ b/meta/classes-recipe/early.bbclass
> @@ -0,0 +1,61 @@
> +# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
> +# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> +#
> +# SPDX-License-Identifier: MIT
> +
> +EARLY_UNPACKDIR = "${WORKDIR}/sources-unpack-early"
> +
> +def get_early_source_dir(d, sourcedir):
> +    unpackdir = d.getVar("UNPACKDIR")
> +    workdir = d.getVar('WORKDIR')
> +    originaldir = unpackdir if sourcedir.startswith(unpackdir) else workdir
> +    early_unpackdir = d.getVar("EARLY_UNPACKDIR")
> +    return sourcedir.replace(originaldir, early_unpackdir)
> +
> +python early_do_fetch_early() {
> +    fetch_src_uris(d, True)
> +}
> +addtask fetch_early
> +do_fetch_early[dirs] = "${DL_DIR}"
> +do_fetch_early[file-checksums] = "${@bb.fetch.get_checksum_file_list(d)}"
> +do_fetch[prefuncs] += "fetcher_hashes_dummyfunc"
> +do_fetch_early[network] = "1"
> +
> +python early_do_unpack_early() {
> +    unpackdir = d.getVar("EARLY_UNPACKDIR")
> +    unpack_src_uris(d, unpackdir, True)
> +}
> +addtask unpack_early after do_fetch_early
> +do_unpack_early[cleandirs] = "${EARLY_UNPACKDIR}"
> +
> +python early_do_patch_early() {
> +    source_dir = d.getVar("S")
> +    source_dir = get_early_source_dir(d, source_dir)
> +    apply_patches(d, source_dir, True)
> +}
> +addtask patch_early after do_unpack_early
> +do_patch_early[dirs] = "${WORKDIR}"
> +do_patch_early[depends] = "${PATCHDEPENDENCY}"
> +do_patch_early[vardepsexclude] = "PATCHRESOLVE"
> +
> +python () {
> +    import bb.fetch
> +    src_uris = get_src_uris(d, True)
> +    for src_uri in src_uris:
> +        uri = bb.fetch.URI(src_uri)
> +        path = uri.params.get("downloadfilename", uri.path)
> +
> +        # HTTP/FTP use the wget fetcher
> +        if uri.scheme in ("http", "https", "ftp"):
> +            d.appendVarFlag('do_fetch_early', 'depends', ' wget-native:do_populate_sysroot')
> +
> +        # Git packages should DEPEND on git-native
> +        elif uri.scheme in ("git", "gitsm"):
> +            d.appendVarFlag('do_fetch_early', 'depends', ' git-native:do_populate_sysroot')
> +
> +        # *.xz should DEPEND on xz-native for unpacking
> +        if path.endswith('.xz') or path.endswith('.txz'):
> +            d.appendVarFlag('do_fetch_early', 'depends', ' xz-native:do_populate_sysroot')
> +}
> +
> +EXPORT_FUNCTIONS do_fetch_early do_unpack_early do_patch_early
> diff --git a/meta/lib/oe/patch.py b/meta/lib/oe/patch.py
> index 58c6e34fe8..7737011e5a 100644
> --- a/meta/lib/oe/patch.py
> +++ b/meta/lib/oe/patch.py
> @@ -904,7 +904,7 @@ def patch_path(url, fetch, unpackdir, expand=True):
>  
>      return local
>  
> -def src_patches(d, all=False, expand=True):
> +def src_patches(d, all=False, expand=True, early=False):
>      unpackdir = d.getVar('UNPACKDIR')
>      fetch = bb.fetch2.Fetch([], d)
>      patches = []
> @@ -921,7 +921,7 @@ def src_patches(d, all=False, expand=True):
>          parm = urldata.parm
>          patchname = parm.get('pname') or os.path.basename(local)
>  
> -        apply, reason = should_apply(parm, d)
> +        apply, reason = should_apply(parm, d, early)
>          if not apply:
>              if reason:
>                  bb.note("Patch %s %s" % (patchname, reason))
> @@ -950,8 +950,12 @@ def src_patches(d, all=False, expand=True):
>      return patches
>  
>  
> -def should_apply(parm, d):
> +def should_apply(parm, d, early=False):
>      import bb.utils
> +
> +    if early and not bb.utils.to_boolean(parm.get('early'), False):
> +        return False, "applies to normal patch task only"
> +
>      if "mindate" in parm or "maxdate" in parm:
>          pn = d.getVar('PN')
>          srcdate = d.getVar('SRCDATE_%s' % pn)
> -- 
> 2.39.5
> 

> 
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#211141): https://lists.openembedded.org/g/openembedded-core/message/211141
> Mute This Topic: https://lists.openembedded.org/mt/111123537/1050810
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [bruce.ashfield@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
> 



^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 18/30] classes: add vendor class for go
  2025-02-11 15:00 ` [RFC PATCH 18/30] classes: add vendor class for go Stefan Herbrechtsmeier
@ 2025-02-11 22:59   ` Bruce Ashfield
  2025-02-12 15:23     ` Stefan Herbrechtsmeier
  0 siblings, 1 reply; 75+ messages in thread
From: Bruce Ashfield @ 2025-02-11 22:59 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss; +Cc: openembedded-core, Stefan Herbrechtsmeier

In message: [OE-core] [RFC PATCH 18/30] classes: add vendor class for go
on 11/02/2025 Stefan Herbrechtsmeier via lists.openembedded.org wrote:

> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> Add a vendor class for go to resolve the dependency SRC_URIs from a
> go.sum file and run populate the go mod vendor folder.
> 
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> ---
> 
>  meta/classes-recipe/vendor_go.bbclass | 59 +++++++++++++++++++++++++++
>  1 file changed, 59 insertions(+)
>  create mode 100644 meta/classes-recipe/vendor_go.bbclass
> 
> diff --git a/meta/classes-recipe/vendor_go.bbclass b/meta/classes-recipe/vendor_go.bbclass
> new file mode 100644
> index 0000000000..dc5f8d1d8d
> --- /dev/null
> +++ b/meta/classes-recipe/vendor_go.bbclass
> @@ -0,0 +1,59 @@
> +# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
> +# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> +#
> +# SPDX-License-Identifier: MIT
> +#
> +
> +# The directory of the go.mod file relative to the root directory, per default
> +# assume there's a file directly in the root directory
> +GO_SRC_DIR ?= ""
> +
> +# The path to the go.mod file
> +GO_MANIFEST_DIR ?= "${GO_SRC_PATH}/go.mod"
> +
> +# The path to go.sum file
> +GO_LOCK_DIR ?= "${@os.path.join(os.path.dirname(d.getVar('GO_MANIFEST_DIR')), 'go.sum')}"
> +
> +# The URL of the go proxy
> +GO_PROXY ?= "https://proxy.golang.org"
> +
> +GO_SRC_PATH = "${S}/${GO_SRC_DIR}"
> +GO_SRC_SUBDIR = "${@os.path.relpath(d.getVar('CARGO_SRC_PATH'), d.getVar('WORKDIR'))}"
> +GO_SRC_URI_FILE = "${VENDOR_DIR}/go-source-uris.txt"
> +SRC_URI_FILES:append = " ${GO_SRC_URI_FILE}"
> +
> +inherit go-mod vendor
> +
> +GO_INSTALL_PREFIX = "."
> +GO_SRC_PATH = "${S}"
> +GO_SRCURI_DESTSUFFIX = ""
> +
> +GOMODCACHE = "invalid"
> +GO_MOD_CACHE_DIR = "go/pkg/mod"
> +GO_WORKPATH = "${GO_SRC_PATH}"
> +GO_MOD_RECRDEPTASK = ""
> +
> +GOBUILDFLAGS:append = " -mod=vendor"
> +
> +python vendor_go_do_vendor_resolve() {
> +    import oe.vendor
> +    import oe.vendor.go
> +
> +    lock_file_dir = d.getVar("GO_LOCK_DIR")
> +    lock_file_subdir = get_early_source_dir(d, lock_file_dir)
> +    proxy = d.getVar("GO_PROXY")
> +    cache_subdir = d.getVar("GO_MOD_CACHE_DIR")
> +    src_uris = oe.vendor.go.resolve_src_uris(lock_file_subdir, proxy, cache_subdir)
> +    with open(d.getVar("GO_SRC_URI_FILE"), "w") as f:
> +        oe.vendor.dump(f, src_uris)
> +}
> +
> +run_go_mod_vendor() {
> +    cd ${GO_SRC_PATH}
> +    export GOMODCACHE="${UNPACKDIR}/${GO_MOD_CACHE_DIR}"
> +    ${GO} mod vendor

What happens if a module isn't in the unpackdir ? I assume it goes
to the go infrastructure and fetches the module ? Or is it
impossible for one to not be in the cache (i.e. is it
always fully pre-poulated via the vendor_go_do_vendor_resolve ?)

It is unclear to me how the vendor'd modules get into an archive
that can be saved for future reproducible builds (can you point
me at that glue?).

Bruce

> +}
> +do_unpack[postfuncs] += "run_go_mod_vendor"
> +do_unpack[depends] += "${@oe.utils.build_depends_string(d.getVar('DEPENDS_GOLANG'), 'do_populate_sysroot')}"
> +
> +EXPORT_FUNCTIONS do_vendor_resolve
> -- 
> 2.39.5
> 

> 
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#211143): https://lists.openembedded.org/g/openembedded-core/message/211143
> Mute This Topic: https://lists.openembedded.org/mt/111123541/1050810
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [bruce.ashfield@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
> 



^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
  2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
                   ` (29 preceding siblings ...)
  2025-02-11 15:00 ` [RFC PATCH 30/30] [DO NOT MERGE] classes: spdx: use version 2.2 Stefan Herbrechtsmeier
@ 2025-02-11 23:14 ` Bruce Ashfield
  2025-02-12  8:41   ` Stefan Herbrechtsmeier
  30 siblings, 1 reply; 75+ messages in thread
From: Bruce Ashfield @ 2025-02-11 23:14 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss
  Cc: openembedded-core, Stefan Herbrechtsmeier, bitbake-devel



In message: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
on 11/02/2025 Stefan Herbrechtsmeier via lists.openembedded.org wrote:

> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> 
> The series adds on-the-fly support for package manager specific
> dependencies and vendor directories. It contains the following changes:
> 1. Adds an early fetch, unpack and patch task to unpack and patch source
>    code with an embedded lock file for dependencies.
> 2. Parse the go.sum, Cargo.lock and package-lock.json lock files and
>    resolve the dependencies to SRC_URIs.
> 3. Save the SRC_URIs in a file and adapt all SRC_URIs users to handle
>    the SRC_URI files beside the SRC_URIs in the recipe.

I made a few comments, and will have another / better look at the
series tomorrow. There's a lot here, and it is hard to wrap my head
around everything that is changing.

I have one specific question below (from the point of view of go).

I've been looking through the series, and can't pick out where #3 is
done. I see patch 14 using SRC_URI_FILES, but where are those files
written ? Is that in patch 18 (vendor_go_do_vendor_resolve ?)  What is
written to those files ?

The concept that I'm not understanding (and that's just me not being
familiar with things, I'll continue reading the series) is that when
we suggested we'd like to have a mode where the dependencies could
clearly be listed in the SRC_URI, at least I was just thinking about a
way run the fetch/module elements that you were adding, write them to
a file and then have the recipe include it.

I can't tell if in the series those files are written each time, and
that there would be no way to edit those SRC_URI_FILES .. but I'll
look again tomorrow.

That file would manipulate the standard SRC_URI. In other words still
support a mode that is like the .inc files with crate://. So someone
could either have the lockfile parsed and fetched, or have a way to
run the parsing and fetching via a task, write a file and include the
file in their recipe to short circuit the processing of the lockfile.
(meaning the expanded and end fetches that are done once you've
processed the file are simply listed as a series of fetches that are
carried out without extra processing .. and "unrolled" dependency
file pointing at the "sources" git, crate, mod, whatever)

If that just doesn't make sense, then if there was a way to copy
the lockfile out of the recipe and have it overlayed onto the fetched
one .. maybe breaking out the individual fetch lines isn't required,
since they could be individually manipulated in that lockfile.

Bruce

> 4. Create a package manager specific vendor directory during unpack to
>    support additional patching of the dependencies.
> 5. Add the dependency name and version to the SBOM.
> 6. Simplify the npm support
> 
> 
> Stefan Herbrechtsmeier (30):
>   classes: create-spdx-2.2: use expanded FetchData for downloaded
>     packages
>   lib: spdx30_tasks: use expanded FetchData for download files
>   classes: create-spdx-2.2: use name and version for download
>     dependencies
>   lib: bb: fetch2: add support to unpack .crate files
>   lib: oe: add vendor module
>   lib: oe: vendor: add cargo support
>   lib: oe: vendor: add go support
>   lib: oe: vendor: add npm support
>   oeqa: oelib: add vendor tests
>   conf: bitbake: add SRC_URI_FILES variable
>   classes: go: make source directory configurable
>   classes: go-mod: make class customizable
>   classes: add nodejs-arch class
>   classes: base: add get_src_uris and unpack_src_uris functions
>   classes: add early fetch, unpack and patch support
>   classes: add vendor class
>   classes: add vendor class for cargo
>   classes: add vendor class for go
>   classes: add vendor class for npm
>   classes: add vendor_npm_build class
>   python3-bcrypt: mirgrate to vendor cargo class
>   python3-cryptography: mirgrate to vendor cargo class
>   python3-maturin: mirgrate to vendor cargo class
>   python3-rpds-py: mirgrate to vendor cargo class
>   librsvg: mirgrate to vendor cargo class
>   librsvg: update dependecies to fix RUSTSEC-2024-0421
>   [DO NOT MERGE] recipes: add crucible go demo
>   [DO NOT MERGE] recipes: add node-red npm demo
>   [DO NOT MERGE] recipes: add nucleoidai npm demo
>   [DO NOT MERGE] classes: spdx: use version 2.2
> 
>  bitbake/lib/bb/fetch2/__init__.py             |    2 +-
>  .../crucible/crucible2_2023.11.02.bb          |   18 +
>  .../node-red/node-red/package-lock.json       | 6096 +++++++++++++++++
>  .../node-red/node-red_4.0.8.bb                |   14 +
>  .../nucleoidai/nucleoidai_0.7.10.bb           |   11 +
>  meta/classes-global/base.bbclass              |   47 +-
>  meta/classes-global/patch.bbclass             |   17 +-
>  meta/classes-recipe/early.bbclass             |   61 +
>  meta/classes-recipe/go-mod.bbclass            |   10 +-
>  meta/classes-recipe/go.bbclass                |   22 +-
>  meta/classes-recipe/nodejs-arch.bbclass       |   15 +
>  meta/classes-recipe/vendor.bbclass            |   28 +
>  meta/classes-recipe/vendor_cargo.bbclass      |   46 +
>  meta/classes-recipe/vendor_go.bbclass         |   59 +
>  meta/classes-recipe/vendor_npm.bbclass        |  115 +
>  meta/classes-recipe/vendor_npm_build.bbclass  |   50 +
>  meta/classes/archiver.bbclass                 |    4 +-
>  meta/classes/buildhistory.bbclass             |    4 +-
>  meta/classes/copyleft_compliance.bbclass      |    2 +-
>  meta/classes/create-spdx-2.2.bbclass          |   14 +-
>  meta/classes/create-spdx.bbclass              |    2 +-
>  meta/classes/externalsrc.bbclass              |    2 +-
>  meta/conf/bitbake.conf                        |    1 +
>  meta/lib/oe/patch.py                          |   10 +-
>  meta/lib/oe/spdx30_tasks.py                   |    5 +-
>  meta/lib/oe/vendor/__init__.py                |   28 +
>  meta/lib/oe/vendor/cargo.py                   |  121 +
>  meta/lib/oe/vendor/go.py                      |   96 +
>  meta/lib/oe/vendor/npm.py                     |  141 +
>  meta/lib/oeqa/selftest/cases/oelib/vendor.py  |  237 +
>  .../python/python3-bcrypt-crates.inc          |   84 -
>  .../python/python3-bcrypt_4.2.1.bb            |    4 +-
>  .../python/python3-cryptography-crates.inc    |   76 -
>  .../python/python3-cryptography.bb            |    4 +-
>  .../python/python3-maturin-crates.inc         |  712 --
>  .../python/python3-maturin_1.8.1.bb           |    4 +-
>  .../python/python3-rpds-py-crates.inc         |   54 -
>  .../python/python3-rpds-py_0.22.3.bb          |    4 +-
>  meta/recipes-gnome/librsvg/librsvg-crates.inc |  590 --
>  ...-to-get-an-updated-idna-rustsec-2024.patch |  398 ++
>  meta/recipes-gnome/librsvg/librsvg_2.59.2.bb  |    7 +-
>  41 files changed, 7633 insertions(+), 1582 deletions(-)
>  create mode 100644 meta-selftest/recipes-support/crucible/crucible2_2023.11.02.bb
>  create mode 100644 meta-selftest/recipes-support/node-red/node-red/package-lock.json
>  create mode 100644 meta-selftest/recipes-support/node-red/node-red_4.0.8.bb
>  create mode 100644 meta-selftest/recipes-support/nucleoidai/nucleoidai_0.7.10.bb
>  create mode 100644 meta/classes-recipe/early.bbclass
>  create mode 100644 meta/classes-recipe/nodejs-arch.bbclass
>  create mode 100644 meta/classes-recipe/vendor.bbclass
>  create mode 100644 meta/classes-recipe/vendor_cargo.bbclass
>  create mode 100644 meta/classes-recipe/vendor_go.bbclass
>  create mode 100644 meta/classes-recipe/vendor_npm.bbclass
>  create mode 100644 meta/classes-recipe/vendor_npm_build.bbclass
>  create mode 100644 meta/lib/oe/vendor/__init__.py
>  create mode 100644 meta/lib/oe/vendor/cargo.py
>  create mode 100644 meta/lib/oe/vendor/go.py
>  create mode 100644 meta/lib/oe/vendor/npm.py
>  create mode 100644 meta/lib/oeqa/selftest/cases/oelib/vendor.py
>  delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc
>  delete mode 100644 meta/recipes-devtools/python/python3-cryptography-crates.inc
>  delete mode 100644 meta/recipes-devtools/python/python3-maturin-crates.inc
>  delete mode 100644 meta/recipes-devtools/python/python3-rpds-py-crates.inc
>  delete mode 100644 meta/recipes-gnome/librsvg/librsvg-crates.inc
>  create mode 100644 meta/recipes-gnome/librsvg/librsvg/0001-update-url-crate-to-get-an-updated-idna-rustsec-2024.patch
> 
> -- 
> 2.39.5
> 

> 
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#17192): https://lists.openembedded.org/g/bitbake-devel/message/17192
> Mute This Topic: https://lists.openembedded.org/mt/111123517/1050810
> Group Owner: bitbake-devel+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/bitbake-devel/unsub [bruce.ashfield@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
> 



^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
  2025-02-11 23:14 ` [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust Bruce Ashfield
@ 2025-02-12  8:41   ` Stefan Herbrechtsmeier
  2025-02-12 14:11     ` Bruce Ashfield
  0 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12  8:41 UTC (permalink / raw)
  To: bruce.ashfield; +Cc: openembedded-core, Stefan Herbrechtsmeier, bitbake-devel

[-- Attachment #1: Type: text/plain, Size: 4073 bytes --]

Am 12.02.2025 um 00:14 schrieb Bruce Ashfield via lists.openembedded.org:
> In message: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
> on 11/02/2025 Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>
>> From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>>
>> The series adds on-the-fly support for package manager specific
>> dependencies and vendor directories. It contains the following changes:
>> 1. Adds an early fetch, unpack and patch task to unpack and patch source
>>     code with an embedded lock file for dependencies.
>> 2. Parse the go.sum, Cargo.lock and package-lock.json lock files and
>>     resolve the dependencies to SRC_URIs.
>> 3. Save the SRC_URIs in a file and adapt all SRC_URIs users to handle
>>     the SRC_URI files beside the SRC_URIs in the recipe.
> I made a few comments, and will have another / better look at the
> series tomorrow. There's a lot here, and it is hard to wrap my head
> around everything that is changing.
>
> I have one specific question below (from the point of view of go).
>
> I've been looking through the series, and can't pick out where #3 is
> done.

The files are created in the package manager specific vendor classes (17 
- 19) in the do_vendor_resolve task. The parsing is implemented in the 
package manager specific modules in the vendor package (6-8).

>   I see patch 14 using SRC_URI_FILES, but where are those files
> written ? Is that in patch 18 (vendor_go_do_vendor_resolve ?)  What is
> written to those files ?

The file is written into the vendor directory below WORKDIR. The 
approach is similar to other classes which need to share data between tasks.

The files contain individual SRC_URIs per line.

> The concept that I'm not understanding (and that's just me not being
> familiar with things, I'll continue reading the series) is that when
> we suggested we'd like to have a mode where the dependencies could
> clearly be listed in the SRC_URI, at least I was just thinking about a
> way run the fetch/module elements that you were adding, write them to
> a file and then have the recipe include it.

The additional SRC_URIs are dynamically added to the recipe without the 
indirection over an include file. The generated SRC_URIs could be 
inspected via the SRC_URI_FILES and manipulated via patches for the lock 
files or an separated lock file.

> I can't tell if in the series those files are written each time, and
> that there would be no way to edit those SRC_URI_FILES .. but I'll
> look again tomorrow.

The files are written if the do_vendor_resolve task need to be rerun. It 
isn't possible to edit the generated SRC_URIs. Instead the lock file 
could be patched.

> That file would manipulate the standard SRC_URI. In other words still
> support a mode that is like the .inc files with crate://. So someone
> could either have the lockfile parsed and fetched, or have a way to
> run the parsing and fetching via a task, write a file and include the
> file in their recipe to short circuit the processing of the lockfile.
> (meaning the expanded and end fetches that are done once you've
> processed the file are simply listed as a series of fetches that are
> carried out without extra processing .. and "unrolled" dependency
> file pointing at the "sources" git, crate, mod, whatever)

What is the motivation "to short circuit the processing of the 
lockfile"? Like any task the processing and its output are cached via 
the sstate cache.

It is possible to use the vendor package to create a include file but we 
should have good reasons to support two solutions for the same problem.

> If that just doesn't make sense, then if there was a way to copy
> the lockfile out of the recipe and have it overlayed onto the fetched
> one .. maybe breaking out the individual fetch lines isn't required,
> since they could be individually manipulated in that lockfile.

I haven't test it but this should be possible. You can place a lock file 
beside the recipe, add it to the SRC_URI and change the XXX_LOCK_PATH.
Regards Stefan

[-- Attachment #2: Type: text/html, Size: 5648 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
  2025-02-11 16:22   ` [bitbake-devel] " Peter Kjellerstedt
@ 2025-02-12  8:55     ` Stefan Herbrechtsmeier
  2025-02-12  9:49       ` [OE-core] " Alexander Kanavin
       [not found]       ` <18236D0FFBD06B89.28278@lists.openembedded.org>
  0 siblings, 2 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12  8:55 UTC (permalink / raw)
  To: Peter Kjellerstedt, openembedded-core@lists.openembedded.org
  Cc: Stefan Herbrechtsmeier, bitbake-devel@lists.openembedded.org

[-- Attachment #1: Type: text/plain, Size: 1757 bytes --]

Am 11.02.2025 um 17:22 schrieb Peter Kjellerstedt:
>> -----Original Message-----
>> From:bitbake-devel@lists.openembedded.org <bitbake-devel@lists.openembedded.org> On Behalf Of Stefan Herbrechtsmeier via lists.openembedded.org
>> Sent: den 11 februari 2025 16:00
>> To:openembedded-core@lists.openembedded.org
>> Cc: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>;bitbake-devel@lists.openembedded.org
>> Subject: [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
>>
>> From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>>
>> Add the variable SRC_URI_FILES to collect files whichs contains
>> additional SRC_URI lines.
>>
>> Signed-off-by: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>> ---
>>
>>   meta/conf/bitbake.conf | 1 +
>>   1 file changed, 1 insertion(+)
>>
>> diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf
>> index 8b607088c6..ed67500ba7 100644
>> --- a/meta/conf/bitbake.conf
>> +++ b/meta/conf/bitbake.conf
>> @@ -745,6 +745,7 @@ AUTOREV ="${@bb.fetch2.get_autorev(d)}"
>>   SRCPV = ""
>>
>>   SRC_URI = ""
>> +SRC_URI_FILES = ""
> Do we really need a new variable for this? Can't you add some parameter
> instead to the URIs that should be handled separately?

The variable holds paths to files which contains dynamic generated 
SRC_URIs. The dynamic SRC_URIs are unknown at parse time and only the 
file paths are fix. The files are filled with generated SRC_URIs via a 
separate task.

> If a parameter is not appropriate, then the name of the variable should
> be reconsidered. Based on the name it is unclear what is expected to go
> in SRC_URI and what should go in SRC_URI_FILES.

Would SRC_URI_MANIFESTS or SRC_URI_MANIFEST_FILES fit better?

[-- Attachment #2: Type: text/html, Size: 3229 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 05/30] lib: oe: add vendor module
  2025-02-11 21:31   ` [OE-core] " Richard Purdie
@ 2025-02-12  9:27     ` Stefan Herbrechtsmeier
  2025-02-12  9:38       ` Richard Purdie
  0 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12  9:27 UTC (permalink / raw)
  To: Richard Purdie, openembedded-core; +Cc: Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 1918 bytes --]

Am 11.02.2025 um 22:31 schrieb Richard Purdie:
> On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>> From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>>
>> Add a vendor package as base for package manager specific
>> implementations to resolve dependencies and populate vendor directories.
>> Add common dump and load function for SRC_URI files.
>>
>> Signed-off-by: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>> ---
>>
>>   meta/lib/oe/vendor/__init__.py | 28 ++++++++++++++++++++++++++++
>>   1 file changed, 28 insertions(+)
>>   create mode 100644 meta/lib/oe/vendor/__init__.py
> Initially I was going to ask there to be a "fetch" or "download" in the
> namespacing. That then made me wonder if in the interests of clarity
> and namepacing, these vendor classes should go into
> lib/bb/fetch2/vendor in bitbake?

The package isn't limited to fetch / download. In some cases it populate 
the vendor directory and could be used for the license extraction in future.

I think it is a bad idea to move code into bitbake which isn't used by 
bitbake. It will complicate future development without any benefit.

> I appreciate the class in OE will use them and separation into bitbake
> can be a bit awkward but it would mean we don't confuse this with any
> other kind of vendoring

What do you mean by "any other kind of vendoring"?

> , it becomes fetch specific and it places them
> alongside the fetch code, which it will need to remain tied to.

It isn't fetch specific. The modules in the package parse lock files and 
extract it content or populate the vendor directory.

> I do feel we need to namespace them though as vendor is not specific
> enough to be directly in lib/oe.

I chose vendor because it is the common name in the package manager to 
create a folder which contains all package manager specific dependencies.

[-- Attachment #2: Type: text/html, Size: 3370 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 05/30] lib: oe: add vendor module
  2025-02-12  9:27     ` Stefan Herbrechtsmeier
@ 2025-02-12  9:38       ` Richard Purdie
  2025-02-12 12:21         ` Stefan Herbrechtsmeier
  0 siblings, 1 reply; 75+ messages in thread
From: Richard Purdie @ 2025-02-12  9:38 UTC (permalink / raw)
  To: Stefan Herbrechtsmeier, openembedded-core; +Cc: Stefan Herbrechtsmeier

On Wed, 2025-02-12 at 10:27 +0100, Stefan Herbrechtsmeier wrote:
> Am 11.02.2025 um 22:31 schrieb Richard Purdie:
> > On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
> > > From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> > > 
> > > Add a vendor package as base for package manager specific
> > > implementations to resolve dependencies and populate vendor directories.
> > > Add common dump and load function for SRC_URI files.
> > > 
> > > Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
> > > ---
> > > 
> > >  meta/lib/oe/vendor/__init__.py | 28 ++++++++++++++++++++++++++++
> > >  1 file changed, 28 insertions(+)
> > >  create mode 100644 meta/lib/oe/vendor/__init__.py
> > >  
> > > 
> >  
> > 
> > Initially I was going to ask there to be a "fetch" or "download" in the
> > namespacing. That then made me wonder if in the interests of clarity
> > and namepacing, these vendor classes should go into
> > lib/bb/fetch2/vendor in bitbake?
> > 
> >   
> The package isn't limited to fetch / download. In some cases it
> populate the vendor directory and could be used for the license
> extraction in future.

"populate" and "extraction" sound related to the fetcher.

>  I think it is a bad idea to move code into bitbake which isn't used
> by bitbake. It will complicate future development without any
> benefit.

You could argue that about the fetch module. It does encourage
strong/stable APIs to the modules, which has been of benefit. I can see
the arguments either way though.

> > I appreciate the class in OE will use them and separation into bitbake
> > can be a bit awkward but it would mean we don't confuse this with any
> > other kind of vendoring
> 
> What do you mean by "any other kind of vendoring"?

When someone customises their BSP, the original might be from "the
vendor" so perhaps this code handles that? OSV as in software vendor is
going to get confused with this. I'd imagine there will be other ways
people could read it too. We have TARGET_VENDOR, HOST_VENDOR,
SDK_VENDOR and so on in the triplets.

My point is that if someone sees a "vendor" module in isolation, they
aren't going to know what it relates to. You're really close to this
topic so it is obvious to you, it is not going to be obvious to others,
or perhaps even you in a few years time.

Cheers,

Richard



^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
  2025-02-12  8:55     ` Stefan Herbrechtsmeier
@ 2025-02-12  9:49       ` Alexander Kanavin
  2025-02-13  7:43         ` Stefan Herbrechtsmeier
       [not found]       ` <18236D0FFBD06B89.28278@lists.openembedded.org>
  1 sibling, 1 reply; 75+ messages in thread
From: Alexander Kanavin @ 2025-02-12  9:49 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss
  Cc: Peter Kjellerstedt, openembedded-core@lists.openembedded.org,
	Stefan Herbrechtsmeier, bitbake-devel@lists.openembedded.org

On Wed, 12 Feb 2025 at 09:55, Stefan Herbrechtsmeier via
lists.openembedded.org
<stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org>
wrote:

> The variable holds paths to files which contains dynamic generated SRC_URIs. The dynamic SRC_URIs are unknown at parse time and only the file paths are fix. The files are filled with generated SRC_URIs via a separate task.

This doesn't explain why we need this separate new variable to begin
with. In what scenarios it would be useful? How does the
implementation rely on it?

I'd suggest SRC_URI_DYNAMIC, we have a precedent in PACKAGES_DYNAMIC.

Alex


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 06/30] lib: oe: vendor: add cargo support
  2025-02-11 15:00 ` [RFC PATCH 06/30] lib: oe: vendor: add cargo support Stefan Herbrechtsmeier
@ 2025-02-12 10:32   ` Alexander Kanavin
  2025-02-12 12:45   ` Frédéric Martinsons
  1 sibling, 0 replies; 75+ messages in thread
From: Alexander Kanavin @ 2025-02-12 10:32 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss; +Cc: openembedded-core, Stefan Herbrechtsmeier

On Tue, 11 Feb 2025 at 16:01, Stefan Herbrechtsmeier via
lists.openembedded.org
<stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org>
wrote:
>
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
>
> Add a vendor module for cargo to resolve dependencies and populate
> vendor directories from a Cargo.lock file.

It isn't clear what is a public API here and what is internal to the
module. Perhaps you could nest the internal functions and constants
into the public functions that use them? Or use the _ prefix in their
names.

Alex


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 13/30] classes: add nodejs-arch class
  2025-02-11 15:00 ` [RFC PATCH 13/30] classes: add nodejs-arch class Stefan Herbrechtsmeier
@ 2025-02-12 10:37   ` Alexander Kanavin
  0 siblings, 0 replies; 75+ messages in thread
From: Alexander Kanavin @ 2025-02-12 10:37 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss; +Cc: openembedded-core, Stefan Herbrechtsmeier

On Tue, 11 Feb 2025 at 16:01, Stefan Herbrechtsmeier via
lists.openembedded.org
<stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org>
wrote:
> diff --git a/meta/classes-recipe/nodejs-arch.bbclass b/meta/classes-recipe/nodejs-arch.bbclass
> new file mode 100644
> index 0000000000..144eaf8409
> --- /dev/null
> +++ b/meta/classes-recipe/nodejs-arch.bbclass
> @@ -0,0 +1,15 @@
> +#
> +# Copyright OpenEmbedded Contributors
> +#
> +# SPDX-License-Identifier: MIT
> +#
> +
> +def map_nodejs_arch(a, d):
> +    import re
> +
> +    if   re.match('i.86$', a): return 'ia32'
> +    elif re.match('x86_64$', a): return 'x64'
> +    elif re.match('aarch64$', a): return 'arm64'
> +    elif re.match('(powerpc64|powerpc64le|ppc64le)$', a): return 'ppc64'
> +    elif re.match('powerpc$', a): return 'ppc'
> +    return a

Why does this need to be in a bbclass, and not in a library function?
Are there multiple users, what are they?

Alex


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
       [not found]       ` <18236D0FFBD06B89.28278@lists.openembedded.org>
@ 2025-02-12 10:42         ` Alexander Kanavin
  0 siblings, 0 replies; 75+ messages in thread
From: Alexander Kanavin @ 2025-02-12 10:42 UTC (permalink / raw)
  To: alex.kanavin
  Cc: stefan.herbrechtsmeier-oss, Peter Kjellerstedt,
	openembedded-core@lists.openembedded.org, Stefan Herbrechtsmeier,
	bitbake-devel@lists.openembedded.org

On Wed, 12 Feb 2025 at 10:50, Alexander Kanavin via
lists.openembedded.org <alex.kanavin=gmail.com@lists.openembedded.org>
wrote:
> This doesn't explain why we need this separate new variable to begin
> with. In what scenarios it would be useful? How does the
> implementation rely on it?

Ok, I'm reading the patchset further and it becomes somewhat more clear.

Stefan, please do write long, descriptive commit messages, so that the
purpose of each change doesn't need to be deduced from reading the
whole patchset. There's only so much my head and other people's heads
can fit in.

Alex


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
  2025-02-11 15:00 ` [RFC PATCH 15/30] classes: add early fetch, unpack and patch support Stefan Herbrechtsmeier
  2025-02-11 22:27   ` [OE-core] " Richard Purdie
  2025-02-11 22:32   ` Bruce Ashfield
@ 2025-02-12 11:08   ` Alexander Kanavin
  2025-02-12 16:23     ` Stefan Herbrechtsmeier
  2 siblings, 1 reply; 75+ messages in thread
From: Alexander Kanavin @ 2025-02-12 11:08 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss; +Cc: openembedded-core, Stefan Herbrechtsmeier

On Tue, 11 Feb 2025 at 16:01, Stefan Herbrechtsmeier via
lists.openembedded.org
<stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org>
wrote:
> Add support for early fetch, unpack and patches task which run before
> normal patch task. This feature is useful to fetch additional
> dependencies based on a patched source before the normal unpack and
> patch tasks. The patch are marked as early via an early=1 parameter. An
> example use case is a patch for a package manager lock file (Cargo.lock,
> go.sum, package-lock.json).

Why there is a need for additional tasks running before regular tasks?
Can't we do regular fetch/unpack/patch for the root item, then run
fetch_vendor_dependencies, unpack_vendor_dependencies,
patch_vendor_dependencies?

I see that others expressed dislike for any additional tasks in
principle, but I don't think that can be avoided? You can't know what
else needs to be fetched until the root item is unpacked and
inspected. I'm ok with that if the additional tasks are clearly named,
and implementations are short, sweet and obvious.

Alex


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
  2025-02-11 22:27   ` [OE-core] " Richard Purdie
@ 2025-02-12 12:21     ` Stefan Herbrechtsmeier
  0 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 12:21 UTC (permalink / raw)
  To: Richard Purdie, openembedded-core; +Cc: Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 3509 bytes --]

Am 11.02.2025 um 23:27 schrieb Richard Purdie:
> On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>> From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>>
>> Add support for early fetch, unpack and patches task which run before
>> normal patch task. This feature is useful to fetch additional
>> dependencies based on a patched source before the normal unpack and
>> patch tasks. The patch are marked as early via an early=1 parameter. An
>> example use case is a patch for a package manager lock file (Cargo.lock,
>> go.sum, package-lock.json).
>>
>> Signed-off-by: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>> ---
>>
>>   meta/classes-global/patch.bbclass | 17 +++++----
>>   meta/classes-recipe/early.bbclass | 61 +++++++++++++++++++++++++++++++
>>   meta/lib/oe/patch.py              | 10 +++--
>>   3 files changed, 77 insertions(+), 11 deletions(-)
>>   create mode 100644 meta/classes-recipe/early.bbclass
> This level of complexity is going to cause massive headaches in future.
> Having two fetch, two unpack and two patch tasks will ultimately just
> cause a lot of confusion and make things like the SPDX code and
> archiver code more complex too.

The tasks don't really increase the complexity. The fetch, unpack and 
patch tasks work like before. The archiver and spdx classes are updated. 
The main difference is that they use a function and not the SRC_URI 
variable direct. The early tasks are only used by the vendor classes. 
The old tasks handle all sources including the dynamic sources. The 
early tasks works like the normal task but with a filtered source list. 
Alternative the steps could be included into the resolve task.

> Rather than patching a cargo lock file, I'd probably prefer the correct
> version be added in a later SRC_URI entry and used to overwrite the
> earlier one at unpack time.

Is this really practical? In many cases you have to update the 
dependencies of the dependency or other meta packages (.mod). It is much 
easier to update the dependency via the package manager and create a 
patch for the lock file. Take a look at patch 26.

> I appreciate the challenge there is then that fetcher isn't going to
> know what it is fetching at fetch time though as it would potentially
> be fetching with the unpatched lock file.

In worst case you have to patch the lock file so that the package 
manager can create the vendor folder.

> This is partly why we end up with the .inc files the way we do, then it
> is explicit.  I'm not sure the fetcher can know deterministically what
> it is fetching in advance without the .inc data though, which is one of
> the concerns that have been expressed previously.
The .inc file is generated from the lock file and the lock file contains 
all required information inclusive check sums.

I'm unsure if the old process of updating a SRC_URI in a .inc file is 
useful for package manager dependencies. The upstream project use 
patches to update the dependency. The .inc file is auto generated and 
any manual change need to be documented otherwise it is unclear how to 
deal with the change during the next update. The changes in the .inc 
file generate a lot of noise and complicate the review of manual updates.

Do we really need the possibility to change a SRC_URI outside of the 
lock file if we integrate the package manager into devtool and allows 
the user to manipulate the lock file via common tools and commands?

[-- Attachment #2: Type: text/html, Size: 5005 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 05/30] lib: oe: add vendor module
  2025-02-12  9:38       ` Richard Purdie
@ 2025-02-12 12:21         ` Stefan Herbrechtsmeier
  0 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 12:21 UTC (permalink / raw)
  To: Richard Purdie, openembedded-core; +Cc: Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 2794 bytes --]


Am 12.02.2025 um 10:38 schrieb Richard Purdie:
> On Wed, 2025-02-12 at 10:27 +0100, Stefan Herbrechtsmeier wrote:
>> Am 11.02.2025 um 22:31 schrieb Richard Purdie:
>>> On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>>>> From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>>>>
>>>> Add a vendor package as base for package manager specific
>>>> implementations to resolve dependencies and populate vendor directories.
>>>> Add common dump and load function for SRC_URI files.
>>>>
>>>> Signed-off-by: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>>>> ---
>>>>
>>>>   meta/lib/oe/vendor/__init__.py | 28 ++++++++++++++++++++++++++++
>>>>   1 file changed, 28 insertions(+)
>>>>   create mode 100644 meta/lib/oe/vendor/__init__.py
>>>>   
>>>>
>>>   
>>>
>>> Initially I was going to ask there to be a "fetch" or "download" in the
>>> namespacing. That then made me wonder if in the interests of clarity
>>> and namepacing, these vendor classes should go into
>>> lib/bb/fetch2/vendor in bitbake?
>>>
>>>    
>> The package isn't limited to fetch / download. In some cases it
>> populate the vendor directory and could be used for the license
>> extraction in future.
> "populate" and "extraction" sound related to the fetcher.
>
>>   I think it is a bad idea to move code into bitbake which isn't used
>> by bitbake. It will complicate future development without any
>> benefit.
> You could argue that about the fetch module. It does encourage
> strong/stable APIs to the modules, which has been of benefit. I can see
> the arguments either way though.

At the moment there is no common api between the different resolve 
functions. The different package manager need different details. But it 
is possible to unify the functions parameters.

Where would you place the code in bitbake?

>>> I appreciate the class in OE will use them and separation into bitbake
>>> can be a bit awkward but it would mean we don't confuse this with any
>>> other kind of vendoring
>> What do you mean by "any other kind of vendoring"?
> When someone customises their BSP, the original might be from "the
> vendor" so perhaps this code handles that? OSV as in software vendor is
> going to get confused with this. I'd imagine there will be other ways
> people could read it too. We have TARGET_VENDOR, HOST_VENDOR,
> SDK_VENDOR and so on in the triplets.
What name do you recommended?

> My point is that if someone sees a "vendor" module in isolation, they
> aren't going to know what it relates to. You're really close to this
> topic so it is obvious to you, it is not going to be obvious to others,
> or perhaps even you in a few years time.

I fear names like dependencies, package manager or resolver are 
misleading too.

[-- Attachment #2: Type: text/html, Size: 4724 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
  2025-02-11 22:32   ` Bruce Ashfield
@ 2025-02-12 12:42     ` Stefan Herbrechtsmeier
  2025-02-12 13:55       ` Bruce Ashfield
  0 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 12:42 UTC (permalink / raw)
  To: bruce.ashfield; +Cc: openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 2181 bytes --]


Am 11.02.2025 um 23:32 schrieb Bruce Ashfield via lists.openembedded.org:
> In message: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
> on 11/02/2025 Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>
>> From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>>
>> Add support for early fetch, unpack and patches task which run before
>> normal patch task. This feature is useful to fetch additional
>> dependencies based on a patched source before the normal unpack and
>> patch tasks. The patch are marked as early via an early=1 parameter. An
>> example use case is a patch for a package manager lock file (Cargo.lock,
>> go.sum, package-lock.json).
> I understand why you need to do the above, but there's now multiple
> fetch and patch tasks running throughout the pipeline of the
> build and that's just more complexity to maintain.

The tasks call the same functions and the difference is really low. The 
early task simple use a filtered list of the SRC_URI. At the moment the 
gitsm fetcher is doing the same but without a possibility to patch a 
dependency.

> This is what I was asking about in some of my first replies
> to the RFC series. When I've done this in the past, I'd just
> suggest something simpler like the recipe provide a complete
> "lock file" in the layer/recipe-space and have it overlayed
> in the source.

This was already supported by my first patch series. The disadvantage is 
a lot of noise during each update.

> Of course that means it is in the same fetch task as what
> will be fetching the vendor bits, but coordinating within
> the single task is simpler in my experience (and it can
> be checked on the SRC_URI). I haven't fully thought through
> how to manage it, but wanted to reply to this while it was
> fresh in my mind.

It is simpler because you manual fetch the lock file, remove the 
possibility to patch the file and skip the unpack. But you still need a 
manual fetch, unpack and maybe patch the source and copy the file into 
the meta layer.

It is also possibility to integrate the early and resolve task into 
fetch task but I'm unsure if this simplify the complexity.

[-- Attachment #2: Type: text/html, Size: 3215 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 06/30] lib: oe: vendor: add cargo support
  2025-02-11 15:00 ` [RFC PATCH 06/30] lib: oe: vendor: add cargo support Stefan Herbrechtsmeier
  2025-02-12 10:32   ` [OE-core] " Alexander Kanavin
@ 2025-02-12 12:45   ` Frédéric Martinsons
  2025-02-12 16:29     ` Stefan Herbrechtsmeier
  1 sibling, 1 reply; 75+ messages in thread
From: Frédéric Martinsons @ 2025-02-12 12:45 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss; +Cc: openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 628 bytes --]

On Tue, 11 Feb 2025 at 16:01, Stefan Herbrechtsmeier via
lists.openembedded.org <stefan.herbrechtsmeier-oss=
weidmueller.com@lists.openembedded.org> wrote:

> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
>
> Add a vendor module for cargo to resolve dependencies and populate
> vendor directories from a Cargo.lock file.
>
>
>
Hello,

Have you looked at vendor subcommand of cargo :
https://doc.rust-lang.org/cargo/commands/cargo-vendor.html ?
I didn't read the series but the commit message makes me think that "cargo
vendor" already exists for resolving dependencies
and populating a vendor directory.

[-- Attachment #2: Type: text/html, Size: 1285 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
  2025-02-12 12:42     ` Stefan Herbrechtsmeier
@ 2025-02-12 13:55       ` Bruce Ashfield
  2025-02-12 14:40         ` Stefan Herbrechtsmeier
  0 siblings, 1 reply; 75+ messages in thread
From: Bruce Ashfield @ 2025-02-12 13:55 UTC (permalink / raw)
  To: Stefan Herbrechtsmeier; +Cc: openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 2925 bytes --]

On Wed, Feb 12, 2025 at 7:42 AM Stefan Herbrechtsmeier <
stefan.herbrechtsmeier-oss@weidmueller.com> wrote:

>
> Am 11.02.2025 um 23:32 schrieb Bruce Ashfield via lists.openembedded.org:
>
> In message: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
> on 11/02/2025 Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>
>
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> <stefan.herbrechtsmeier@weidmueller.com>
>
> Add support for early fetch, unpack and patches task which run before
> normal patch task. This feature is useful to fetch additional
> dependencies based on a patched source before the normal unpack and
> patch tasks. The patch are marked as early via an early=1 parameter. An
> example use case is a patch for a package manager lock file (Cargo.lock,
> go.sum, package-lock.json).
>
> I understand why you need to do the above, but there's now multiple
> fetch and patch tasks running throughout the pipeline of the
> build and that's just more complexity to maintain.
>
> The tasks call the same functions and the difference is really low. The
> early task simple use a filtered list of the SRC_URI. At the moment the
> gitsm fetcher is doing the same but without a possibility to patch a
> dependency.
>
> This is what I was asking about in some of my first replies
> to the RFC series. When I've done this in the past, I'd just
> suggest something simpler like the recipe provide a complete
> "lock file" in the layer/recipe-space and have it overlayed
> in the source.
>
> This was already supported by my first patch series. The disadvantage is a
> lot of noise during each update.
>
> Of course that means it is in the same fetch task as what
> will be fetching the vendor bits, but coordinating within
> the single task is simpler in my experience (and it can
> be checked on the SRC_URI). I haven't fully thought through
> how to manage it, but wanted to reply to this while it was
> fresh in my mind.
>
> It is simpler because you manual fetch the lock file, remove the
> possibility to patch the file and skip the unpack. But you still need a
> manual fetch, unpack and maybe patch the source and copy the file into the
> meta layer.
>

That's a completely different type of complexity. Richard and I are only
talking
about the complexity after "bitbake <foo>" has been called.

>
> It is also possibility to integrate the early and resolve task into fetch
> task but I'm unsure if this simplify the complexity.
>

Having direct calls to additional routines via conditional is less complex
than
tasks (dealing with timing, scheduling, code maintenance, etc), so that is
preferable from at least my point of view.

Bruce




-- 
- Thou shalt not follow the NULL pointer, for chaos and madness await thee
at its end
- "Use the force Harry" - Gandalf, Star Trek II

[-- Attachment #2: Type: text/html, Size: 4630 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
  2025-02-12  8:41   ` Stefan Herbrechtsmeier
@ 2025-02-12 14:11     ` Bruce Ashfield
  2025-02-13  8:36       ` Stefan Herbrechtsmeier
  0 siblings, 1 reply; 75+ messages in thread
From: Bruce Ashfield @ 2025-02-12 14:11 UTC (permalink / raw)
  To: Stefan Herbrechtsmeier
  Cc: openembedded-core, Stefan Herbrechtsmeier, bitbake-devel

[-- Attachment #1: Type: text/plain, Size: 6698 bytes --]

On Wed, Feb 12, 2025 at 3:41 AM Stefan Herbrechtsmeier <
stefan.herbrechtsmeier-oss@weidmueller.com> wrote:

> Am 12.02.2025 um 00:14 schrieb Bruce Ashfield via lists.openembedded.org:
>
> In message: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
> on 11/02/2025 Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>
>
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> <stefan.herbrechtsmeier@weidmueller.com>
>
> The series adds on-the-fly support for package manager specific
> dependencies and vendor directories. It contains the following changes:
> 1. Adds an early fetch, unpack and patch task to unpack and patch source
>    code with an embedded lock file for dependencies.
> 2. Parse the go.sum, Cargo.lock and package-lock.json lock files and
>    resolve the dependencies to SRC_URIs.
> 3. Save the SRC_URIs in a file and adapt all SRC_URIs users to handle
>    the SRC_URI files beside the SRC_URIs in the recipe.
>
> I made a few comments, and will have another / better look at the
> series tomorrow. There's a lot here, and it is hard to wrap my head
> around everything that is changing.
>
> I have one specific question below (from the point of view of go).
>
> I've been looking through the series, and can't pick out where #3 is
> done.
>
> The files are created in the package manager specific vendor classes (17 -
> 19) in the do_vendor_resolve task. The parsing is implemented in the
> package manager specific modules in the vendor package (6-8).
>
>
aha. I'll have a closer look in a bit!



>  I see patch 14 using SRC_URI_FILES, but where are those files
> written ? Is that in patch 18 (vendor_go_do_vendor_resolve ?)  What is
> written to those files ?
>
> The file is written into the vendor directory below WORKDIR. The approach
> is similar to other classes which need to share data between tasks.
>
> The files contain individual SRC_URIs per line.
>
I may have missed that in the patches, but if that isn't described in the
commit logs, then
that description would be a nice addition. Along with a high level
description for each
supported language package manager about what is in the files and what uses
it to
resolve the dependencies.


> The concept that I'm not understanding (and that's just me not being
> familiar with things, I'll continue reading the series) is that when
> we suggested we'd like to have a mode where the dependencies could
> clearly be listed in the SRC_URI, at least I was just thinking about a
> way run the fetch/module elements that you were adding, write them to
> a file and then have the recipe include it.
>
> The additional SRC_URIs are dynamically added to the recipe without the
> indirection over an include file. The generated SRC_URIs could be inspected
> via the SRC_URI_FILES and manipulated via patches for the lock files or an
> separated lock file.
>
The issue with patching those dynamic files .. is just that, they are
dynamic and
they could be regenerated (but hopefully without a SRCREV change they are
identically
generated each time, so maybe it isn't a big deal) and patching could fail.
Much like we
don't patch generated automake files, we patch the .am and .in files that
generate the
outputs.

>
> I can't tell if in the series those files are written each time, and
> that there would be no way to edit those SRC_URI_FILES .. but I'll
> look again tomorrow.
>
> The files are written if the do_vendor_resolve task need to be rerun. It
> isn't possible to edit the generated SRC_URIs. Instead the lock file could
> be patched.
>

ok. So they are really just a way to dump what is being built to disk and
out of "memory",
it really isn't what I was looking for, but at least I understand what you
were trying to
do with the writing and later use of the files now.

I was hoping for something that I could include "statically" (for lack of a
better term) in my
recipes, and then have the handlers for the protocols do the fetching ..
again, much like
the crate:// fetches in the .inc files.

To be clear, I'm not suggesting that mode would be the only mode, just that
the way the
generation of the fetches -> actual fetching was constructed such that I
could avoid
"short circuit" the handling of the lock file and simply list the
dependencies for fetching
(much like how I can go get all of the SRCREVS for a gitsm:// fetch, and
put them into
my recipes as pure git:// fetches if I'm having issues with the git
submodles).

That file would manipulate the standard SRC_URI. In other words still
> support a mode that is like the .inc files with crate://. So someone
> could either have the lockfile parsed and fetched, or have a way to
> run the parsing and fetching via a task, write a file and include the
> file in their recipe to short circuit the processing of the lockfile.
> (meaning the expanded and end fetches that are done once you've
> processed the file are simply listed as a series of fetches that are
> carried out without extra processing .. and "unrolled" dependency
> file pointing at the "sources" git, crate, mod, whatever)
>
> What is the motivation "to short circuit the processing of the lockfile"?
> Like any task the processing and its output are cached via the sstate cache.
>

See above. It isn't about re-running it a later time and re-using the
artifacts, it is about
having a way to make sure nothing is dynamically resolved when bitbake
<foo> is called,
just fetch and the rest of the standard tasks.

>
> It is possible to use the vendor package to create a include file but we
> should have good reasons to support two solutions for the same problem.
>
> If that just doesn't make sense, then if there was a way to copy
> the lockfile out of the recipe and have it overlayed onto the fetched
> one .. maybe breaking out the individual fetch lines isn't required,
> since they could be individually manipulated in that lockfile.
>
> I haven't test it but this should be possible. You can place a lock file
> beside the recipe, add it to the SRC_URI and change the XXX_LOCK_PATH.
>

Something like that is a big step towards having that finer grained control
in a recipe that
I'm looking for. I'd still like some sort of line by line "dumped
dependency list" if there's a
lower level protocol at play (but the lock file really also is just that
line by line list for many
of the languages).

Bruce

> Regards Stefan
>


-- 
- Thou shalt not follow the NULL pointer, for chaos and madness await thee
at its end
- "Use the force Harry" - Gandalf, Star Trek II

[-- Attachment #2: Type: text/html, Size: 11255 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-11 21:46   ` [OE-core] " Richard Purdie
@ 2025-02-12 14:36     ` Stefan Herbrechtsmeier
  2025-02-12 15:06       ` Richard Purdie
  2025-02-12 15:07       ` Bruce Ashfield
  0 siblings, 2 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 14:36 UTC (permalink / raw)
  To: Richard Purdie, openembedded-core; +Cc: Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 5037 bytes --]

Am 11.02.2025 um 22:46 schrieb Richard Purdie:
> On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>> From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>>
>> Signed-off-by: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>> ---
>>
>>   .../python/python3-bcrypt-crates.inc          | 84 -------------------
>>   .../python/python3-bcrypt_4.2.1.bb            |  4 +-
>>   2 files changed, 1 insertion(+), 87 deletions(-)
>>   delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc
> So let me as the silly question. This removes the crates.inc file and
> doesn't appear to add any kind of new list of locked down modules.
The list is generated on the fly like gitsm and doesn't require an extra 
step.

> This means that inspection tools just using the metadata can't see
> "into" this recipe any longer for component information.

We support and use python code inside the variables and thereby need a 
preprocessing of the metadata in any case.

What do you mean by "component information"?

> This was
> something that some people felt strongly that was a necessary part of
> recipe metadata, for license, security and other manifest activities.

Why can't they use the SBOM for this?

> Are we basically saying that information is now only available after
> the build takes place?
They are only available after a special task run.

> I'm very worried that the previous discussions didn't reach a
> conclusion and this is moving the "magic" out of bitbake and into some
> vendor classes without addressing the concerns previously raised about
> transparency into the manifests of what is going on behind the scenes.

I try to address the concerns but don't realize that the missing 
information in the recipe is a blocker.

This version gives the user the possibility to influence the 
dependencies via patches or alternative lock file. It creates a vendor 
folder for easy patch and debug. It integrates the dependencies into the 
SBOM for security tracking.

I skipped the license topic for now because the package managers don't 
handle license integrity. We have to keep the information in the recipe 
but hopefully the license information doesn't change with each update.

I don't understand the requirement for the plain inspection. In my 
opinion external tools should always use a defined output and shouldn't 
depend on the project internal details. I adapt the existing users of 
the SRC_URI to include the dynamic SRC_URIs.

> I appreciate some of the requirements are conflicting.
>
> For the record in some recent meetings, I was promised that help would
> be forthcoming in helping guide this discussion. I therefore left
> things alone in the hope that would happen. It simply hasn't, probably
> due to time/work issues, which I can sympathise with but it does mean
> I'm left doing a bad job of trying to respond to your patches whilst
> trying to do too many other things badly too. That leaves us both very
> frustrated.
>
> I really want to see you succeed in reworking this and I appreciate the
> time and effort put into the patches. To make this successful, I know
> there are key stakeholders who need to buy into it and right now,
> they're more likely just to keep doing their own things as it is easier
> since this isn't going the direction they want. A key piece of making
> this successful is negotiating something which can work for a
> significant portion of them. I'm spelling all this out since I do at
> least want to make the situation clear.
>
> Yes, I'm very upset the OE community is putting me in this position
> despite me repeatedly asking for help and that isn't your fault, which
> just frustrates me more.

My problem is the double standards. We support a fetcher which dynamic 
resolve dependencies and without manual update step since years. Nobody 
suggests to make the gitsm fetcher obsolete and requests the users to 
run an update task after a SRC_URI change to create a .inc file with the 
SRC_URIs of all the recursive submodules. Nobody complains about the 
missing components in the recipe.

Whether we have hard requirements and introduce a git submodule support 
which satisfy the requirements or we accept the advantages of a simple 
user interface and minimize the disadvantages.

It doesn't matter if we run the resolve function inside a resolve, fetch 
or update task. The questions is do we want to support dynamic SRC_URIs 
or do we want an manual update task. The task needs to be manual run 
after a SRC_URI change and can produces a lot of noise in the update 
commit. In any case the manual editing of the SRC_URI isn't practical 
and the users will use the package manager to update dependencies and 
its recursive dependencies.

As a compromise we could add a new feature to generate .inc cache files 
before the main bitbake run. This would eliminate the manual update run 
and the commit noise as well as special fetch, unpack and patch task.

[-- Attachment #2: Type: text/html, Size: 7165 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
  2025-02-12 13:55       ` Bruce Ashfield
@ 2025-02-12 14:40         ` Stefan Herbrechtsmeier
  0 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 14:40 UTC (permalink / raw)
  To: Bruce Ashfield; +Cc: openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 3201 bytes --]

Am 12.02.2025 um 14:55 schrieb Bruce Ashfield:
>
>
> On Wed, Feb 12, 2025 at 7:42 AM Stefan Herbrechtsmeier 
> <stefan.herbrechtsmeier-oss@weidmueller.com> wrote:
>
>
>     Am 11.02.2025 um 23:32 schrieb Bruce Ashfield via
>     lists.openembedded.org <http://lists.openembedded.org>:
>>     In message: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
>>     on 11/02/2025 Stefan Herbrechtsmeier vialists.openembedded.org <http://lists.openembedded.org> wrote:
>>
>>>     From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com> <mailto:stefan.herbrechtsmeier@weidmueller.com>
>>>
>>>     Add support for early fetch, unpack and patches task which run before
>>>     normal patch task. This feature is useful to fetch additional
>>>     dependencies based on a patched source before the normal unpack and
>>>     patch tasks. The patch are marked as early via an early=1 parameter. An
>>>     example use case is a patch for a package manager lock file (Cargo.lock,
>>>     go.sum, package-lock.json).
>>     I understand why you need to do the above, but there's now multiple
>>     fetch and patch tasks running throughout the pipeline of the
>>     build and that's just more complexity to maintain.
>
>     The tasks call the same functions and the difference is really
>     low. The early task simple use a filtered list of the SRC_URI. At
>     the moment the gitsm fetcher is doing the same but without a
>     possibility to patch a dependency.
>
>>     This is what I was asking about in some of my first replies
>>     to the RFC series. When I've done this in the past, I'd just
>>     suggest something simpler like the recipe provide a complete
>>     "lock file" in the layer/recipe-space and have it overlayed
>>     in the source.
>
>     This was already supported by my first patch series. The
>     disadvantage is a lot of noise during each update.
>
>>     Of course that means it is in the same fetch task as what
>>     will be fetching the vendor bits, but coordinating within
>>     the single task is simpler in my experience (and it can
>>     be checked on the SRC_URI). I haven't fully thought through
>>     how to manage it, but wanted to reply to this while it was
>>     fresh in my mind.
>
>     It is simpler because you manual fetch the lock file, remove the
>     possibility to patch the file and skip the unpack. But you still
>     need a manual fetch, unpack and maybe patch the source and copy
>     the file into the meta layer.
>
>
> That's a completely different type of complexity. Richard and I are 
> only talking
> about the complexity after "bitbake <foo>" has been called.
>
>
>     It is also possibility to integrate the early and resolve task
>     into fetch task but I'm unsure if this simplify the complexity.
>
>
> Having direct calls to additional routines via conditional is less 
> complex than
> tasks (dealing with timing, scheduling, code maintenance, etc), so that is
> preferable from at least my point of view.
Okay, I thought separate tasks are preferred. What is the alternative to 
the EXPORT_FUNCTIONS in this case. I need to call different functions 
depending on the inherit class.

[-- Attachment #2: Type: text/html, Size: 5637 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-12 14:36     ` Stefan Herbrechtsmeier
@ 2025-02-12 15:06       ` Richard Purdie
  2025-02-12 17:27         ` Stefan Herbrechtsmeier
  2025-02-12 15:07       ` Bruce Ashfield
  1 sibling, 1 reply; 75+ messages in thread
From: Richard Purdie @ 2025-02-12 15:06 UTC (permalink / raw)
  To: Stefan Herbrechtsmeier, openembedded-core; +Cc: Stefan Herbrechtsmeier

On Wed, 2025-02-12 at 15:36 +0100, Stefan Herbrechtsmeier wrote:
> My problem is the double standards. We support a fetcher which
> dynamic resolve dependencies and without manual update step since
> years. Nobody suggests to make the gitsm fetcher obsolete and
> requests the users to run an update task after a SRC_URI change to
> create a .inc file with the SRC_URIs of all the recursive submodules.
> Nobody complains about the missing components in the recipe.

FWIW there have been problems and complaints about gitsm. There were
some people who explicitly converted gitsm recipes into git urls due to
issues with the fetcher.

We have on the most part dealt with the worst issues in gitsm now but
there are still some who don't use it.

With git there is at least a relatively wide understanding of the
technology. With many other areas like node, go and rust, the tools are
much younger without some of the features we sometimes need, at least
in the past and people's overall trust is much lower as a result.

At this point I'm not sure there would be demand to change gitsm but
there are still the concerns about that approach.

>  Whether we have hard requirements and introduce a git submodule
> support which satisfy the requirements or we accept the advantages of
> a simple user interface and minimize the disadvantages.
>
>  It doesn't matter if we run the resolve function inside a resolve,
> fetch or update task. The questions is do we want to support dynamic
> SRC_URIs or do we want an manual update task. The task needs to be
> manual run after a SRC_URI change and can produces a lot of noise in
> the update commit. In any case the manual editing of the SRC_URI
> isn't practical and the users will use the package manager to update
> dependencies and its recursive dependencies.
>  
> As a compromise we could add a new feature to generate .inc cache
> files before the main bitbake run. This would eliminate the manual
> update run and the commit noise as well as special fetch, unpack and
> patch task.

I've partly being trying to channel some of the feelings I've been
hearing expressed in different places, as I do want any new solution to
meet the needs of the widest group we can. If the .inc is generated but
not checked in (to remove the commit noise), I suspect it loses some of
the value that people have wanted.

I'm personally very torn. I get pushed many different ways, which
include robustness, simplicity and complexity reduction, performance
and various extremes of auditing. I feel I'm doing a bad job of trying
to represent everything :(.

I do see that there are basically two conflicting approaches and I'm
not sure everyone is going to be happy with either. This does worry me
a lot and puts me in a difficult place too.

Cheers,

Richard



^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-12 14:36     ` Stefan Herbrechtsmeier
  2025-02-12 15:06       ` Richard Purdie
@ 2025-02-12 15:07       ` Bruce Ashfield
  2025-02-12 17:24         ` Stefan Herbrechtsmeier
  1 sibling, 1 reply; 75+ messages in thread
From: Bruce Ashfield @ 2025-02-12 15:07 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss
  Cc: Richard Purdie, openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 8866 bytes --]

On Wed, Feb 12, 2025 at 9:36 AM Stefan Herbrechtsmeier via
lists.openembedded.org <stefan.herbrechtsmeier-oss=
weidmueller.com@lists.openembedded.org> wrote:

> Am 11.02.2025 um 22:46 schrieb Richard Purdie:
>
> On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> <stefan.herbrechtsmeier@weidmueller.com>
>
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> <stefan.herbrechtsmeier@weidmueller.com>
> ---
>
>  .../python/python3-bcrypt-crates.inc          | 84 -------------------
>  .../python/python3-bcrypt_4.2.1.bb            |  4 +-
>  2 files changed, 1 insertion(+), 87 deletions(-)
>  delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc
>
> So let me as the silly question. This removes the crates.inc file and
> doesn't appear to add any kind of new list of locked down modules.
>
> The list is generated on the fly like gitsm and doesn't require an extra
> step.
>
> This means that inspection tools just using the metadata can't see
> "into" this recipe any longer for component information.
>
> We support and use python code inside the variables and thereby need a
> preprocessing of the metadata in any case.
>
> What do you mean by "component information"?
>
> This was
> something that some people felt strongly that was a necessary part of
> recipe metadata, for license, security and other manifest activities.
>
> Why can't they use the SBOM for this?
>
> Are we basically saying that information is now only available after
> the build takes place?
>
> They are only available after a special task run.
>
> I'm very worried that the previous discussions didn't reach a
> conclusion and this is moving the "magic" out of bitbake and into some
> vendor classes without addressing the concerns previously raised about
> transparency into the manifests of what is going on behind the scenes.
>
> I try to address the concerns but don't realize that the missing
> information in the recipe is a blocker.
>
> This version gives the user the possibility to influence the dependencies
> via patches or alternative lock file. It creates a vendor folder for easy
> patch and debug. It integrates the dependencies into the SBOM for security
> tracking.
>
> I skipped the license topic for now because the package managers don't
> handle license integrity. We have to keep the information in the recipe but
> hopefully the license information doesn't change with each update.
>
> I don't understand the requirement for the plain inspection. In my opinion
> external tools should always use a defined output and shouldn't depend on
> the project internal details. I adapt the existing users of the SRC_URI to
> include the dynamic SRC_URIs.
>
> I appreciate some of the requirements are conflicting.
>
> For the record in some recent meetings, I was promised that help would
> be forthcoming in helping guide this discussion. I therefore left
> things alone in the hope that would happen. It simply hasn't, probably
> due to time/work issues, which I can sympathise with but it does mean
> I'm left doing a bad job of trying to respond to your patches whilst
> trying to do too many other things badly too. That leaves us both very
> frustrated.
>
> I really want to see you succeed in reworking this and I appreciate the
> time and effort put into the patches. To make this successful, I know
> there are key stakeholders who need to buy into it and right now,
> they're more likely just to keep doing their own things as it is easier
> since this isn't going the direction they want. A key piece of making
> this successful is negotiating something which can work for a
> significant portion of them. I'm spelling all this out since I do at
> least want to make the situation clear.
>
> Yes, I'm very upset the OE community is putting me in this position
> despite me repeatedly asking for help and that isn't your fault, which
> just frustrates me more.
>
> My problem is the double standards. We support a fetcher which dynamic
> resolve dependencies and without manual update step since years. Nobody
> suggests to make the gitsm fetcher obsolete and requests the users to run
> an update task after a SRC_URI change to create a .inc file with the
> SRC_URIs of all the recursive submodules. Nobody complains about the
> missing components in the recipe.
>
There's no double standard, I'd simply say that design decisions of the
past doesn't mean that there aren't better ways to do something new.

Richard went out of his way to explain the status and what sort of review
needs to happen, I'll add that while getting frustrated with it is natural,
pushing back on people doing reviews isn't going to help get things merged,
it will do the opposite.

There have been plenty of complaints and issues with the gitsm fetcher, but
the reality is that if someone wants to get at the base components of what
it is doing, they can do so. I've had to take several of my maintained
recipes out of gitsm and back to the base git fetches. The submodules were
simply fetching code that didn't build and there was no way to fetch it.
The gitsm fetcher is also relatively lightly used, much less complicated
and doesn't need much extra in infrastructure to support it.


> Whether we have hard requirements and introduce a git submodule support
> which satisfy the requirements or we accept the advantages of a simple user
> interface and minimize the disadvantages.
>
Unfortunately in my experience the simple interfaces hiding complexity
don't help when things go wrong. That's how I ended up where I am with my
go recipes, and why I ended up tearing my gitsm recipe back into its
components. There was no way to influence / fix the build otherwise, and
they didn't support bleeding edge development very well.

I'm definitely one of the people Richard is mentioning as a stakeholder,
and one that could likely just ignore all of this .. but I'm attempting to
wade into it again.

None of us have the hands on, daily experience with the components at play
as you do right now, so patience on your part will be needed as we ask many
not-so-intelligent questions.


> It doesn't matter if we run the resolve function inside a resolve, fetch
> or update task. The questions is do we want to support dynamic SRC_URIs or
> do we want an manual update task. The task needs to be manual run after a
> SRC_URI change and can produces a lot of noise in the update commit. In any
> case the manual editing of the SRC_URI isn't practical and the users will
> use the package manager to update dependencies and its recursive
> dependencies.
>
I don't understand the series quite enough yet to say "why can't we do
both", if there was a way to abstract / componentize what is generating
those dynamic SCR_URIS in such a way that an external tool or update task
could generate them, and if they were already in place the dynamic
generation wouldn't run at build time, that should keep both modes working.

I admit to not understanding why we'd be overly concerned about noise in
the commits (for the dependencies) if they are split into separate files in
the recipe. More information is always better when I'm dealing with the
updates. I just scroll past it if I'm not interested and filter it if I am.

I feel the pain (and your pain) of this after supporting complicated
go/mixed language recipes through multiple major releases (and through go's
changing dependency model + bleeding edge code, etc) and needing to track
what has changed, so I definitely encourage you to keep working on this.

As a compromise we could add a new feature to generate .inc cache files
> before the main bitbake run. This would eliminate the manual update run and
> the commit noise as well as special fetch, unpack and patch task.
>
> Can you elaborate on what you mean by before the main bitbake run ? Would
it be still under a single bitbake invokation or would it be multiple runs
(I support multiple runs, so don't take that as a leading question).

Bruce

>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#211243):
> https://lists.openembedded.org/g/openembedded-core/message/211243
> Mute This Topic: https://lists.openembedded.org/mt/111123548/1050810
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [
> bruce.ashfield@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
>

-- 
- Thou shalt not follow the NULL pointer, for chaos and madness await thee
at its end
- "Use the force Harry" - Gandalf, Star Trek II

[-- Attachment #2: Type: text/html, Size: 13003 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 18/30] classes: add vendor class for go
  2025-02-11 22:59   ` [OE-core] " Bruce Ashfield
@ 2025-02-12 15:23     ` Stefan Herbrechtsmeier
  0 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 15:23 UTC (permalink / raw)
  To: Bruce Ashfield; +Cc: openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 3684 bytes --]

Am 11.02.2025 um 23:59 schrieb Bruce Ashfield:
> In message: [OE-core] [RFC PATCH 18/30] classes: add vendor class for go
> on 11/02/2025 Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>
>> From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>>
>> Add a vendor class for go to resolve the dependency SRC_URIs from a
>> go.sum file and run populate the go mod vendor folder.
>>
>> Signed-off-by: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>> ---
>>
>>   meta/classes-recipe/vendor_go.bbclass | 59 +++++++++++++++++++++++++++
>>   1 file changed, 59 insertions(+)
>>   create mode 100644 meta/classes-recipe/vendor_go.bbclass
>>
>> diff --git a/meta/classes-recipe/vendor_go.bbclass b/meta/classes-recipe/vendor_go.bbclass
>> new file mode 100644
>> index 0000000000..dc5f8d1d8d
>> --- /dev/null
>> +++ b/meta/classes-recipe/vendor_go.bbclass
>> @@ -0,0 +1,59 @@
>> +# Copyright (C) 2025 Weidmueller Interface GmbH & Co. KG
>> +# Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com>
>> +#
>> +# SPDX-License-Identifier: MIT
>> +#
>> +
>> +# The directory of the go.mod file relative to the root directory, per default
>> +# assume there's a file directly in the root directory
>> +GO_SRC_DIR ?= ""
>> +
>> +# The path to the go.mod file
>> +GO_MANIFEST_DIR ?= "${GO_SRC_PATH}/go.mod"
>> +
>> +# The path to go.sum file
>> +GO_LOCK_DIR ?="${@os.path.join(os.path.dirname(d.getVar('GO_MANIFEST_DIR')), 
>> 'go.sum')}"
>> +
>> +# The URL of the go proxy
>> +GO_PROXY ?="https://proxy.golang.org"
>> +
>> +GO_SRC_PATH = "${S}/${GO_SRC_DIR}"
>> +GO_SRC_SUBDIR ="${@os.path.relpath(d.getVar('CARGO_SRC_PATH'), d.getVar('WORKDIR'))}"
>> +GO_SRC_URI_FILE = "${VENDOR_DIR}/go-source-uris.txt"
>> +SRC_URI_FILES:append = " ${GO_SRC_URI_FILE}"
>> +
>> +inherit go-mod vendor
>> +
>> +GO_INSTALL_PREFIX = "."
>> +GO_SRC_PATH = "${S}"
>> +GO_SRCURI_DESTSUFFIX = ""
>> +
>> +GOMODCACHE = "invalid"
>> +GO_MOD_CACHE_DIR = "go/pkg/mod"
>> +GO_WORKPATH = "${GO_SRC_PATH}"
>> +GO_MOD_RECRDEPTASK = ""
>> +
>> +GOBUILDFLAGS:append = " -mod=vendor"
>> +
>> +python vendor_go_do_vendor_resolve() {
>> +    import oe.vendor
>> +    import oe.vendor.go
>> +
>> +    lock_file_dir = d.getVar("GO_LOCK_DIR")
>> +    lock_file_subdir = get_early_source_dir(d, lock_file_dir)
>> +    proxy = d.getVar("GO_PROXY")
>> +    cache_subdir = d.getVar("GO_MOD_CACHE_DIR")
>> +    src_uris = oe.vendor.go.resolve_src_uris(lock_file_subdir, proxy, cache_subdir)
>> +    with open(d.getVar("GO_SRC_URI_FILE"), "w") as f:
>> +        oe.vendor.dump(f, src_uris)
>> +}
>> +
>> +run_go_mod_vendor() {
>> +    cd ${GO_SRC_PATH}
>> +    export GOMODCACHE="${UNPACKDIR}/${GO_MOD_CACHE_DIR}"
>> +    ${GO} mod vendor
> What happens if a module isn't in the unpackdir ? I assume it goes
> to the go infrastructure and fetches the module ? Or is it
> impossible for one to not be in the cache (i.e. is it
> always fully pre-poulated via the vendor_go_do_vendor_resolve ?)
A missing packages leads to an build error because the network is 
disabled. But this shouldn't happen because the resolve task add all 
modules to the dynamic SRC_URI.

> It is unclear to me how the vendor'd modules get into an archive
> that can be saved for future reproducible builds (can you point
> me at that glue?).

The do_vendor_resolve task add all modules from the go.sum to the 
dynamic SRC_URI. The fetch and unpack task fetch the modules and unpack 
it to the cache. The go mod vendor command create a vendor directory 
from the populated cache. Depending on the archiver class function the 
archive contains the created vendor directory in S or the recipe and 
dynamic SRC_URI archives.

[-- Attachment #2: Type: text/html, Size: 5001 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 15/30] classes: add early fetch, unpack and patch support
  2025-02-12 11:08   ` Alexander Kanavin
@ 2025-02-12 16:23     ` Stefan Herbrechtsmeier
  0 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 16:23 UTC (permalink / raw)
  To: Alexander Kanavin; +Cc: openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 1592 bytes --]

Am 12.02.2025 um 12:08 schrieb Alexander Kanavin:
> On Tue, 11 Feb 2025 at 16:01, Stefan Herbrechtsmeier via
> lists.openembedded.org
> <stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org>
> wrote:
>> Add support for early fetch, unpack and patches task which run before
>> normal patch task. This feature is useful to fetch additional
>> dependencies based on a patched source before the normal unpack and
>> patch tasks. The patch are marked as early via an early=1 parameter. An
>> example use case is a patch for a package manager lock file (Cargo.lock,
>> go.sum, package-lock.json).
> Why there is a need for additional tasks running before regular tasks?
> Can't we do regular fetch/unpack/patch for the root item, then run
> fetch_vendor_dependencies, unpack_vendor_dependencies,
> patch_vendor_dependencies?

I use early task approach to keep the old behavior. Other classes like 
the archive class depends on the unpack task and expect that everything 
is unpacked after the task. Additional the user use the fetch command to 
fetch the dependencies. Therefore I add additional task before the 
common task to keep the known behavior.

> I see that others expressed dislike for any additional tasks in
> principle, but I don't think that can be avoided? You can't know what
> else needs to be fetched until the root item is unpacked and
> inspected. I'm ok with that if the additional tasks are clearly named,
> and implementations are short, sweet and obvious.

It should be possible to move the early tasks code into a prefuncs of 
fetch to avoid additional tasks.

[-- Attachment #2: Type: text/html, Size: 2493 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 06/30] lib: oe: vendor: add cargo support
  2025-02-12 12:45   ` Frédéric Martinsons
@ 2025-02-12 16:29     ` Stefan Herbrechtsmeier
  2025-02-12 17:48       ` Frédéric Martinsons
  0 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 16:29 UTC (permalink / raw)
  To: Frédéric Martinsons; +Cc: openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 870 bytes --]

Am 12.02.2025 um 13:45 schrieb Frédéric Martinsons:
>
> On Tue, 11 Feb 2025 at 16:01, Stefan Herbrechtsmeier via 
> lists.openembedded.org <http://lists.openembedded.org> 
> <stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org> wrote:
>
>     From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
>
>     Add a vendor module for cargo to resolve dependencies and populate
>     vendor directories from a Cargo.lock file.
>
>
>
> Hello,
>
> Have you looked at vendor subcommand of cargo : 
> https://doc.rust-lang.org/cargo/commands/cargo-vendor.html ?
> I didn't read the series but the commit message makes me think that 
> "cargo vendor" already exists for resolving dependencies
> and populating a vendor directory.
>
The class uses the bitbake fetcher (wget / git) to create a vendor 
directory and emulate the cargo vendor command.


[-- Attachment #2: Type: text/html, Size: 2367 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-12 15:07       ` Bruce Ashfield
@ 2025-02-12 17:24         ` Stefan Herbrechtsmeier
  2025-02-12 17:45           ` Bruce Ashfield
  0 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 17:24 UTC (permalink / raw)
  To: Bruce Ashfield; +Cc: Richard Purdie, openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 10487 bytes --]

Am 12.02.2025 um 16:07 schrieb Bruce Ashfield:
> On Wed, Feb 12, 2025 at 9:36 AM Stefan Herbrechtsmeier via 
> lists.openembedded.org <http://lists.openembedded.org> 
> <stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org> wrote:
>
>     Am 11.02.2025 um 22:46 schrieb Richard Purdie:
>>     On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier vialists.openembedded.org <http://lists.openembedded.org> wrote:
>>>     From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com> <mailto:stefan.herbrechtsmeier@weidmueller.com>
>>>
>>>     Signed-off-by: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com> <mailto:stefan.herbrechtsmeier@weidmueller.com>
>>>     ---
>>>
>>>       .../python/python3-bcrypt-crates.inc          | 84 -------------------
>>>       .../python/python3-bcrypt_4.2.1.bb <http://python3-bcrypt_4.2.1.bb>            |  4 +-
>>>       2 files changed, 1 insertion(+), 87 deletions(-)
>>>       delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc
>>     So let me as the silly question. This removes the crates.inc file and
>>     doesn't appear to add any kind of new list of locked down modules.
>     The list is generated on the fly like gitsm and doesn't require an
>     extra step.
>
>>     This means that inspection tools just using the metadata can't see
>>     "into" this recipe any longer for component information.
>
>     We support and use python code inside the variables and thereby
>     need a preprocessing of the metadata in any case.
>
>     What do you mean by "component information"?
>
>>     This was
>>     something that some people felt strongly that was a necessary part of
>>     recipe metadata, for license, security and other manifest activities.
>
>     Why can't they use the SBOM for this?
>
>>     Are we basically saying that information is now only available after
>>     the build takes place?
>     They are only available after a special task run.
>
>>     I'm very worried that the previous discussions didn't reach a
>>     conclusion and this is moving the "magic" out of bitbake and into some
>>     vendor classes without addressing the concerns previously raised about
>>     transparency into the manifests of what is going on behind the scenes.
>
>     I try to address the concerns but don't realize that the missing
>     information in the recipe is a blocker.
>
>     This version gives the user the possibility to influence the
>     dependencies via patches or alternative lock file. It creates a
>     vendor folder for easy patch and debug. It integrates the
>     dependencies into the SBOM for security tracking.
>
>     I skipped the license topic for now because the package managers
>     don't handle license integrity. We have to keep the information in
>     the recipe but hopefully the license information doesn't change
>     with each update.
>
>     I don't understand the requirement for the plain inspection. In my
>     opinion external tools should always use a defined output and
>     shouldn't depend on the project internal details. I adapt the
>     existing users of the SRC_URI to include the dynamic SRC_URIs.
>
>>     I appreciate some of the requirements are conflicting.
>>
>>     For the record in some recent meetings, I was promised that help would
>>     be forthcoming in helping guide this discussion. I therefore left
>>     things alone in the hope that would happen. It simply hasn't, probably
>>     due to time/work issues, which I can sympathise with but it does mean
>>     I'm left doing a bad job of trying to respond to your patches whilst
>>     trying to do too many other things badly too. That leaves us both very
>>     frustrated.
>>
>>     I really want to see you succeed in reworking this and I appreciate the
>>     time and effort put into the patches. To make this successful, I know
>>     there are key stakeholders who need to buy into it and right now,
>>     they're more likely just to keep doing their own things as it is easier
>>     since this isn't going the direction they want. A key piece of making
>>     this successful is negotiating something which can work for a
>>     significant portion of them. I'm spelling all this out since I do at
>>     least want to make the situation clear.
>>
>>     Yes, I'm very upset the OE community is putting me in this position
>>     despite me repeatedly asking for help and that isn't your fault, which
>>     just frustrates me more.
>
>     My problem is the double standards. We support a fetcher which
>     dynamic resolve dependencies and without manual update step since
>     years. Nobody suggests to make the gitsm fetcher obsolete and
>     requests the users to run an update task after a SRC_URI change to
>     create a .inc file with the SRC_URIs of all the recursive
>     submodules. Nobody complains about the missing components in the
>     recipe.
>
> There's no double standard, I'd simply say that design decisions of 
> the past doesn't mean that there aren't better ways to do something new.
>
> Richard went out of his way to explain the status and what sort of 
> review needs to happen, I'll add that while getting frustrated with it 
> is natural, pushing back on people doing reviews isn't going to help 
> get things merged, it will do the opposite.
>
> There have been plenty of complaints and issues with the gitsm 
> fetcher, but the reality is that if someone wants to get at the base 
> components of what it is doing, they can do so. I've had to take 
> several of my maintained recipes out of gitsm and back to the base git 
> fetches. The submodules were simply fetching code that didn't build 
> and there was no way to fetch it.  The gitsm fetcher is also 
> relatively lightly used, much less complicated and doesn't need much 
> extra in infrastructure to support it.

Thanks for your insides. There a two main solutions for the problem. Add 
patch support to gitsm so that you could use the git submodule command 
and create a patch or generate a .inc file and manipulate the SRCREVs. I 
assume you would prefer a .inc file. What do you think is the downside 
of a patch?

>
>     Whether we have hard requirements and introduce a git submodule
>     support which satisfy the requirements or we accept the advantages
>     of a simple user interface and minimize the disadvantages.
>
> Unfortunately in my experience the simple interfaces hiding complexity 
> don't help when things go wrong. That's how I ended up where I am with 
> my go recipes, and why I ended up tearing my gitsm recipe back into 
> its components. There was no way to influence / fix the build 
> otherwise, and they didn't support bleeding edge development very well.
Do you have a good example for a problematic go recipe to test my approach?

> I'm definitely one of the people Richard is mentioning as a 
> stakeholder, and one that could likely just ignore all of this .. but 
> I'm attempting to wade into it again.

I am very grateful for that.

>
> None of us have the hands on, daily experience with the components at 
> play as you do right now, so patience on your part will be needed as 
> we ask many not-so-intelligent questions.

That's no problem.

>
>     It doesn't matter if we run the resolve function inside a resolve,
>     fetch or update task. The questions is do we want to support
>     dynamic SRC_URIs or do we want an manual update task. The task
>     needs to be manual run after a SRC_URI change and can produces a
>     lot of noise in the update commit. In any case the manual editing
>     of the SRC_URI isn't practical and the users will use the package
>     manager to update dependencies and its recursive dependencies.
>
> I don't understand the series quite enough yet to say "why can't we do 
> both", if there was a way to abstract / componentize what is 
> generating those dynamic SCR_URIS in such a way that an external tool 
> or update task could generate them, and if they were already in place 
> the dynamic generation wouldn't run at build time, that should keep 
> both modes working.
If it is desired I can add both variants.


> I admit to not understanding why we'd be overly concerned about noise 
> in the commits (for the dependencies) if they are split into separate 
> files in the recipe. More information is always better when I'm 
> dealing with the updates. I just scroll past it if I'm not interested 
> and filter it if I am.
The problem is to identify the relevant parts. Lets say you update a 
dependency because of an security issue. Afterwards you update the 
project with a lot of dependency changes. You have to review the 
complete noise to determine if your updated dependency doesn't go 
backward in its version. It is much easier to use a patch. After the 
project update the patch will fail or not. If it fails you have a direct 
focus on the affected dependency. If you back port the patch from the 
project you could simple drop it with the next update.

> I feel the pain (and your pain) of this after supporting complicated 
> go/mixed language recipes through multiple major releases (and through 
> go's changing dependency model + bleeding edge code, etc) and needing 
> to track what has changed, so I definitely encourage you to keep 
> working on this.
>
>     As a compromise we could add a new feature to generate .inc cache
>     files before the main bitbake run. This would eliminate the manual
>     update run and the commit noise as well as special fetch, unpack
>     and patch task.
>
> Can you elaborate on what you mean by before the main bitbake run ? 
> Would it be still under a single bitbake invokation or would it be 
> multiple runs (I support multiple runs, so don't take that as a 
> leading question).

I can't answer this questions and need Richard guidance to implement 
such a feature. I would assume that bitbake already track file changes 
and can update its state. The behavior should be similar to a change in 
the .inc file. Bitbake will detect that a "include_cache" file is 
missing and run an update_cache task on the recipe. Afterwards bitbake 
detect a file change on the "include_cache" file and parse it. We need a 
possibility to mark patches which shouldn't be applied if the 
"include_cache" file is missing because the dependencies are missing. We 
need to run the fetch, unpack and patch task before the update_cache 
task to generate the .inc file.

[-- Attachment #2: Type: text/html, Size: 17235 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-12 15:06       ` Richard Purdie
@ 2025-02-12 17:27         ` Stefan Herbrechtsmeier
  0 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-12 17:27 UTC (permalink / raw)
  To: Richard Purdie, openembedded-core; +Cc: Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 3167 bytes --]

Am 12.02.2025 um 16:06 schrieb Richard Purdie:
> On Wed, 2025-02-12 at 15:36 +0100, Stefan Herbrechtsmeier wrote:
>> My problem is the double standards. We support a fetcher which
>> dynamic resolve dependencies and without manual update step since
>> years. Nobody suggests to make the gitsm fetcher obsolete and
>> requests the users to run an update task after a SRC_URI change to
>> create a .inc file with the SRC_URIs of all the recursive submodules.
>> Nobody complains about the missing components in the recipe.
> FWIW there have been problems and complaints about gitsm. There were
> some people who explicitly converted gitsm recipes into git urls due to
> issues with the fetcher.
>
> We have on the most part dealt with the worst issues in gitsm now but
> there are still some who don't use it.
>
> With git there is at least a relatively wide understanding of the
> technology. With many other areas like node, go and rust, the tools are
> much younger without some of the features we sometimes need, at least
> in the past and people's overall trust is much lower as a result.
>
> At this point I'm not sure there would be demand to change gitsm but
> there are still the concerns about that approach.

>>   Whether we have hard requirements and introduce a git submodule
>> support which satisfy the requirements or we accept the advantages of
>> a simple user interface and minimize the disadvantages.
>>
>>   It doesn't matter if we run the resolve function inside a resolve,
>> fetch or update task. The questions is do we want to support dynamic
>> SRC_URIs or do we want an manual update task. The task needs to be
>> manual run after a SRC_URI change and can produces a lot of noise in
>> the update commit. In any case the manual editing of the SRC_URI
>> isn't practical and the users will use the package manager to update
>> dependencies and its recursive dependencies.
>>   
>> As a compromise we could add a new feature to generate .inc cache
>> files before the main bitbake run. This would eliminate the manual
>> update run and the commit noise as well as special fetch, unpack and
>> patch task.
> I've partly being trying to channel some of the feelings I've been
> hearing expressed in different places, as I do want any new solution to
> meet the needs of the widest group we can. If the .inc is generated but
> not checked in (to remove the commit noise), I suspect it loses some of
> the value that people have wanted.

It would be helpful if more people participation in the discussion. It 
is hard to understand why the .inc is needed if the lock file contains 
the same information and common tools exists to manipulate the lock file.

> I'm personally very torn. I get pushed many different ways, which
> include robustness, simplicity and complexity reduction, performance
> and various extremes of auditing. I feel I'm doing a bad job of trying
> to represent everything :(.
I'm sorry for that.

> I do see that there are basically two conflicting approaches and I'm
> not sure everyone is going to be happy with either. This does worry me
> a lot and puts me in a difficult place too.

Would you accept both solutions?

[-- Attachment #2: Type: text/html, Size: 4332 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-12 17:24         ` Stefan Herbrechtsmeier
@ 2025-02-12 17:45           ` Bruce Ashfield
  2025-02-12 17:52             ` Richard Purdie
  2025-02-13 12:45             ` Stefan Herbrechtsmeier
  0 siblings, 2 replies; 75+ messages in thread
From: Bruce Ashfield @ 2025-02-12 17:45 UTC (permalink / raw)
  To: Stefan Herbrechtsmeier
  Cc: Richard Purdie, openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 12985 bytes --]

On Wed, Feb 12, 2025 at 12:24 PM Stefan Herbrechtsmeier <
stefan.herbrechtsmeier-oss@weidmueller.com> wrote:

> Am 12.02.2025 um 16:07 schrieb Bruce Ashfield:
>
> On Wed, Feb 12, 2025 at 9:36 AM Stefan Herbrechtsmeier via
> lists.openembedded.org <stefan.herbrechtsmeier-oss=
> weidmueller.com@lists.openembedded.org> wrote:
>
>> Am 11.02.2025 um 22:46 schrieb Richard Purdie:
>>
>> On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>>
>> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> <stefan.herbrechtsmeier@weidmueller.com>
>>
>> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> <stefan.herbrechtsmeier@weidmueller.com>
>> ---
>>
>>  .../python/python3-bcrypt-crates.inc          | 84 -------------------
>>  .../python/python3-bcrypt_4.2.1.bb            |  4 +-
>>  2 files changed, 1 insertion(+), 87 deletions(-)
>>  delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc
>>
>> So let me as the silly question. This removes the crates.inc file and
>> doesn't appear to add any kind of new list of locked down modules.
>>
>> The list is generated on the fly like gitsm and doesn't require an extra
>> step.
>>
>> This means that inspection tools just using the metadata can't see
>> "into" this recipe any longer for component information.
>>
>> We support and use python code inside the variables and thereby need a
>> preprocessing of the metadata in any case.
>>
>> What do you mean by "component information"?
>>
>> This was
>> something that some people felt strongly that was a necessary part of
>> recipe metadata, for license, security and other manifest activities.
>>
>> Why can't they use the SBOM for this?
>>
>> Are we basically saying that information is now only available after
>> the build takes place?
>>
>> They are only available after a special task run.
>>
>> I'm very worried that the previous discussions didn't reach a
>> conclusion and this is moving the "magic" out of bitbake and into some
>> vendor classes without addressing the concerns previously raised about
>> transparency into the manifests of what is going on behind the scenes.
>>
>> I try to address the concerns but don't realize that the missing
>> information in the recipe is a blocker.
>>
>> This version gives the user the possibility to influence the dependencies
>> via patches or alternative lock file. It creates a vendor folder for easy
>> patch and debug. It integrates the dependencies into the SBOM for security
>> tracking.
>>
>> I skipped the license topic for now because the package managers don't
>> handle license integrity. We have to keep the information in the recipe but
>> hopefully the license information doesn't change with each update.
>>
>> I don't understand the requirement for the plain inspection. In my
>> opinion external tools should always use a defined output and shouldn't
>> depend on the project internal details. I adapt the existing users of the
>> SRC_URI to include the dynamic SRC_URIs.
>>
>> I appreciate some of the requirements are conflicting.
>>
>> For the record in some recent meetings, I was promised that help would
>> be forthcoming in helping guide this discussion. I therefore left
>> things alone in the hope that would happen. It simply hasn't, probably
>> due to time/work issues, which I can sympathise with but it does mean
>> I'm left doing a bad job of trying to respond to your patches whilst
>> trying to do too many other things badly too. That leaves us both very
>> frustrated.
>>
>> I really want to see you succeed in reworking this and I appreciate the
>> time and effort put into the patches. To make this successful, I know
>> there are key stakeholders who need to buy into it and right now,
>> they're more likely just to keep doing their own things as it is easier
>> since this isn't going the direction they want. A key piece of making
>> this successful is negotiating something which can work for a
>> significant portion of them. I'm spelling all this out since I do at
>> least want to make the situation clear.
>>
>> Yes, I'm very upset the OE community is putting me in this position
>> despite me repeatedly asking for help and that isn't your fault, which
>> just frustrates me more.
>>
>> My problem is the double standards. We support a fetcher which dynamic
>> resolve dependencies and without manual update step since years. Nobody
>> suggests to make the gitsm fetcher obsolete and requests the users to run
>> an update task after a SRC_URI change to create a .inc file with the
>> SRC_URIs of all the recursive submodules. Nobody complains about the
>> missing components in the recipe.
>>
> There's no double standard, I'd simply say that design decisions of the
> past doesn't mean that there aren't better ways to do something new.
>
> Richard went out of his way to explain the status and what sort of review
> needs to happen, I'll add that while getting frustrated with it is natural,
> pushing back on people doing reviews isn't going to help get things merged,
> it will do the opposite.
>
> There have been plenty of complaints and issues with the gitsm fetcher,
> but the reality is that if someone wants to get at the base components of
> what it is doing, they can do so. I've had to take several of my maintained
> recipes out of gitsm and back to the base git fetches. The submodules were
> simply fetching code that didn't build and there was no way to fetch it.
> The gitsm fetcher is also relatively lightly used, much less complicated
> and doesn't need much extra in infrastructure to support it.
>
> Thanks for your insides. There a two main solutions for the problem. Add
> patch support to gitsm so that you could use the git submodule command and
> create a patch or generate a .inc file and manipulate the SRCREVs. I assume
> you would prefer a .inc file. What do you think is the downside of a patch?
>

It is much easier to get a complete view of the file with a drop-in, versus
a patch (depending on the size of the file). You need to know the base
directory, the depth, put in an upstream-status, create it, copy it to your
layer, etc. With a drop-in lock file, I copy it out, edit it, and add it to
my SRC_URI.  Not much difference in the end, but I prefer the drop-in
approach on pretty much any configuration file in my builds, not just this
example.



>
>
>> Whether we have hard requirements and introduce a git submodule support
>> which satisfy the requirements or we accept the advantages of a simple user
>> interface and minimize the disadvantages.
>>
> Unfortunately in my experience the simple interfaces hiding complexity
> don't help when things go wrong. That's how I ended up where I am with my
> go recipes, and why I ended up tearing my gitsm recipe back into its
> components. There was no way to influence / fix the build otherwise, and
> they didn't support bleeding edge development very well.
>
> Do you have a good example for a problematic go recipe to test my approach?
>

Not right now, the current state is relatively stable as I'm working
towards the LTS release. These have just popped up repeatedly over the
maybe 5+ years (I can't remember how long it has been!) in maintaining
meta-virtualization. I have no doubts (and am not implying) that your
series could adapt my recipes and use all of the go mod infrastructure ..
just with all of the vendoring and go mod efforts over the years, going all
the way back to the actual source code gave a lot more visibility into the
vendor dependencies (and not just what was released for them) and I've used
it many times while debugging runtime issues of the container stacks.


> I'm definitely one of the people Richard is mentioning as a stakeholder,
> and one that could likely just ignore all of this .. but I'm attempting to
> wade into it again.
>
> I am very grateful for that.
>
>
> None of us have the hands on, daily experience with the components at play
> as you do right now, so patience on your part will be needed as we ask many
> not-so-intelligent questions.
>
> That's no problem.
>
>
>> It doesn't matter if we run the resolve function inside a resolve, fetch
>> or update task. The questions is do we want to support dynamic SRC_URIs or
>> do we want an manual update task. The task needs to be manual run after a
>> SRC_URI change and can produces a lot of noise in the update commit. In any
>> case the manual editing of the SRC_URI isn't practical and the users will
>> use the package manager to update dependencies and its recursive
>> dependencies.
>>
> I don't understand the series quite enough yet to say "why can't we do
> both", if there was a way to abstract / componentize what is generating
> those dynamic SCR_URIS in such a way that an external tool or update task
> could generate them, and if they were already in place the dynamic
> generation wouldn't run at build time, that should keep both modes working.
>
> If it is desired I can add both variants.
>

Forcing one approach over the other isn't really going to make it mergeable
(or maybe I should say make it adopted by all).

We need to help developers as well as people just doing "load build" for
distros (that should be in a steady state).  I'm under no illusion that the
way I handle the go recipes won't work for everyone either, so I definitely
wouldn't propose it as such.

>
>
>
> I admit to not understanding why we'd be overly concerned about noise in
> the commits (for the dependencies) if they are split into separate files in
> the recipe. More information is always better when I'm dealing with the
> updates. I just scroll past it if I'm not interested and filter it if I am.
>
> The problem is to identify the relevant parts. Lets say you update a
> dependency because of an security issue. Afterwards you update the project
> with a lot of dependency changes. You have to review the complete noise to
> determine if your updated dependency doesn't go backward in its version. It
> is much easier to use a patch. After the project update the patch will fail
> or not. If it fails you have a direct focus on the affected dependency. If
> you back port the patch from the project you could simple drop it with the
> next update.
>

I prefer all of the extra information, but maybe that's my kernel
background. It's the same reason why all my recipe / version updates
contain all the short logs between the releases. I can just skip / ignore
the information most of the time, but it comes in handy when looking for a
security issue, etc.

In my go recipes, I have a look at the dependency SRCREVS between updates.
In particular if I'm debugging a runtime issue, that helps me quickly see
if a dependency changed and by how much it changed.

I could do the same with a drop-in lockfile that was in my recipe, since
I'd have the delta readily available and could see the source revisions,
etc.

Of course if a drop-in file was used, we'd want some sort of hash for the
original file it was clobbering, since that indicates an update would be
required (or dropping it, etc).


>
> I feel the pain (and your pain) of this after supporting complicated
> go/mixed language recipes through multiple major releases (and through go's
> changing dependency model + bleeding edge code, etc) and needing to track
> what has changed, so I definitely encourage you to keep working on this.
>
> As a compromise we could add a new feature to generate .inc cache files
>> before the main bitbake run. This would eliminate the manual update run and
>> the commit noise as well as special fetch, unpack and patch task.
>>
>> Can you elaborate on what you mean by before the main bitbake run ? Would
> it be still under a single bitbake invokation or would it be multiple runs
> (I support multiple runs, so don't take that as a leading question).
>
> I can't answer this questions and need Richard guidance to implement such
> a feature. I would assume that bitbake already track file changes and can
> update its state. The behavior should be similar to a change in the .inc
> file. Bitbake will detect that a "include_cache" file is missing and run an
> update_cache task on the recipe. Afterwards bitbake detect a file change on
> the "include_cache" file and parse it. We need a possibility to mark
> patches which shouldn't be applied if the "include_cache" file is missing
> because the dependencies are missing. We need to run the fetch, unpack and
> patch task before the update_cache task to generate the .inc file.
>
Aha. Maybe Richard will comment later. I was thinking more about something
that was in two distinct phases, but with some more thinking and
explanation, maybe this is workable as well.

Bruce

[-- Attachment #2: Type: text/html, Size: 21120 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 06/30] lib: oe: vendor: add cargo support
  2025-02-12 16:29     ` Stefan Herbrechtsmeier
@ 2025-02-12 17:48       ` Frédéric Martinsons
  2025-02-13  8:53         ` Stefan Herbrechtsmeier
  0 siblings, 1 reply; 75+ messages in thread
From: Frédéric Martinsons @ 2025-02-12 17:48 UTC (permalink / raw)
  To: Stefan Herbrechtsmeier; +Cc: openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 1409 bytes --]

Le mer. 12 févr. 2025, 17:29, Stefan Herbrechtsmeier <
stefan.herbrechtsmeier-oss@weidmueller.com> a écrit :

> Am 12.02.2025 um 13:45 schrieb Frédéric Martinsons:
>
>
> On Tue, 11 Feb 2025 at 16:01, Stefan Herbrechtsmeier via
> lists.openembedded.org <stefan.herbrechtsmeier-oss=
> weidmueller.com@lists.openembedded.org> wrote:
>
>> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
>>
>> Add a vendor module for cargo to resolve dependencies and populate
>> vendor directories from a Cargo.lock file.
>>
>>
>>
> Hello,
>
> Have you looked at vendor subcommand of cargo :
> https://doc.rust-lang.org/cargo/commands/cargo-vendor.html ?
> I didn't read the series but the commit message makes me think that "cargo
> vendor" already exists for resolving dependencies
> and populating a vendor directory.
>
> The class uses the bitbake fetcher (wget / git) to create a vendor
> directory and emulate the cargo vendor command.
>

Yes, I understood that. Let me rephrase my question.
Is it desirable/needed to mimick an existing (upstream and maintained)
command, considering that we already use native cargo to build rust
binaries?

Is the new flow you suggest can use the "cargo vendor" call?

Maybe there is room for less custom code here. Sorry if I missed something
obvious, I just react to some keywords in area that I contributed 2 years
ago.

[-- Attachment #2: Type: text/html, Size: 3129 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-12 17:45           ` Bruce Ashfield
@ 2025-02-12 17:52             ` Richard Purdie
  2025-02-13 12:45             ` Stefan Herbrechtsmeier
  1 sibling, 0 replies; 75+ messages in thread
From: Richard Purdie @ 2025-02-12 17:52 UTC (permalink / raw)
  To: Bruce Ashfield, Stefan Herbrechtsmeier
  Cc: openembedded-core, Stefan Herbrechtsmeier

On Wed, 2025-02-12 at 12:45 -0500, Bruce Ashfield wrote:
> On Wed, Feb 12, 2025 at 12:24 PM Stefan Herbrechtsmeier
> <stefan.herbrechtsmeier-oss@weidmueller.com> wrote:
> 
> > 
> > > 
> > > > 
> > > > As a compromise we could add a new feature to generate .inc
> > > > cache files before the main bitbake run. This would eliminate
> > > > the manual update run and the commit noise as well as special
> > > > fetch, unpack and patch task.
> > > >   
> > > Can you elaborate on what you mean by before the main bitbake run
> > > ? Would it be still under a single bitbake invokation or would it
> > > be multiple runs (I support multiple runs, so don't take that as
> > > a leading question).
> > >  
> > I can't answer this questions and need Richard guidance to
> > implement such a feature. I would assume that bitbake already track
> > file changes and can update its state. The behavior should be
> > similar to a change in the .inc file. Bitbake will detect that a
> > "include_cache" file is missing and run an update_cache task on the
> > recipe. Afterwards bitbake detect a file change on the
> > "include_cache" file and parse it. We need a possibility to mark
> > patches which shouldn't be applied if the "include_cache" file is
> > missing because the dependencies are missing. We need to run the
> > fetch, unpack and patch task before the update_cache task to
> > generate the .inc file.
> >  
> Aha. Maybe Richard will comment later. I was thinking more about
> something that was in two distinct phases, but with some more
> thinking and explanation, maybe this is workable as well.

We don't have anything in bitbake which could support this currently.
We parse once, store a subset of the data and then have all the
information bitbake needs. There is no second parse something else
later in the task graph concept or support, or support for "generate
this file if missing", particularly if generating that file would
require other tasks to run.

That said, I am wondering if we need to do something differently here,
it is obviously just going to complicate things a lot if we need new
concepts and API at that level in bitbake.

Cheers,

Richard










^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
  2025-02-12  9:49       ` [OE-core] " Alexander Kanavin
@ 2025-02-13  7:43         ` Stefan Herbrechtsmeier
  2025-02-13  7:53           ` Alexander Kanavin
  0 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-13  7:43 UTC (permalink / raw)
  To: bitbake-devel

[-- Attachment #1: Type: text/plain, Size: 1177 bytes --]

Am 12.02.2025 um 10:49 schrieb Alexander Kanavin via lists.openembedded.org:
> On Wed, 12 Feb 2025 at 09:55, Stefan Herbrechtsmeier via
> lists.openembedded.org
> <stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org>
> wrote:
>
>> The variable holds paths to files which contains dynamic generated SRC_URIs. The dynamic SRC_URIs are unknown at parse time and only the file paths are fix. The files are filled with generated SRC_URIs via a separate task.
> This doesn't explain why we need this separate new variable to begin
> with. In what scenarios it would be useful? How does the
> implementation rely on it?
We can't manipulate a global variable value inside a task. We need a 
file to exchange values between task. The vendor classes resolve the 
SRC_URIs of the dependency in the resolve task. The new variable 
contains the list of files with SRC_URIs inside it. The later tasks read 
the additional SRC_URIs from the files and merge them with the recipe 
SRC_URIs.

> I'd suggest SRC_URI_DYNAMIC, we have a precedent in PACKAGES_DYNAMIC.

The variable doesn't contain a dynamic for the SRC_URI but instead a 
list of files with SRC_URIs inside the file.

[-- Attachment #2: Type: text/html, Size: 2103 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [bitbake-devel] [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable
  2025-02-13  7:43         ` Stefan Herbrechtsmeier
@ 2025-02-13  7:53           ` Alexander Kanavin
  0 siblings, 0 replies; 75+ messages in thread
From: Alexander Kanavin @ 2025-02-13  7:53 UTC (permalink / raw)
  To: stefan.herbrechtsmeier-oss; +Cc: bitbake-devel

On Thu, 13 Feb 2025 at 08:43, Stefan Herbrechtsmeier via
lists.openembedded.org
<stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org>
wrote:
> The variable holds paths to files which contains dynamic generated SRC_URIs. The dynamic SRC_URIs are unknown at parse time and only the file paths are fix. The files are filled with generated SRC_URIs via a separate task.
>
> This doesn't explain why we need this separate new variable to begin
> with. In what scenarios it would be useful? How does the
> implementation rely on it?
>
> We can't manipulate a global variable value inside a task. We need a file to exchange values between task. The vendor classes resolve the SRC_URIs of the dependency in the resolve task. The new variable contains the list of files with SRC_URIs inside it. The later tasks read the additional SRC_URIs from the files and merge them with the recipe SRC_URIs.
>
> I'd suggest SRC_URI_DYNAMIC, we have a precedent in PACKAGES_DYNAMIC.
>
> The variable doesn't contain a dynamic for the SRC_URI but instead a list of files with SRC_URIs inside the file.

Thanks. But all of this should be in a commit message. And actually
even that is not enough: you need to tell where the variable is set,
show an example value, show an example content of the file(s) it
references, and also tell where the value of the variable is used to
do further processing, and what that processing is, and refer to
commits doing it.

The code is obvious to you because you've worked with it for several
weeks now. It's not obvious to any of the reviewers and you need to
help them at every step, otherwise few people will look and even fewer
will comment, and the whole thing is at risk of fizzling out due to
lack of interest.

Alex


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
  2025-02-12 14:11     ` Bruce Ashfield
@ 2025-02-13  8:36       ` Stefan Herbrechtsmeier
  2025-02-13 17:01         ` Bruce Ashfield
  0 siblings, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-13  8:36 UTC (permalink / raw)
  To: Bruce Ashfield; +Cc: openembedded-core, Stefan Herbrechtsmeier, bitbake-devel

[-- Attachment #1: Type: text/plain, Size: 8983 bytes --]

Am 12.02.2025 um 15:11 schrieb Bruce Ashfield:
>
>
> On Wed, Feb 12, 2025 at 3:41 AM Stefan Herbrechtsmeier 
> <stefan.herbrechtsmeier-oss@weidmueller.com> wrote:
>
>     Am 12.02.2025 um 00:14 schrieb Bruce Ashfield via
>     lists.openembedded.org <http://lists.openembedded.org>:
>>     In message: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
>>     on 11/02/2025 Stefan Herbrechtsmeier vialists.openembedded.org <http://lists.openembedded.org> wrote:
>>
>>>     From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com> <mailto:stefan.herbrechtsmeier@weidmueller.com>
>>>
>>>     The series adds on-the-fly support for package manager specific
>>>     dependencies and vendor directories. It contains the following changes:
>>>     1. Adds an early fetch, unpack and patch task to unpack and patch source
>>>         code with an embedded lock file for dependencies.
>>>     2. Parse the go.sum, Cargo.lock and package-lock.json lock files and
>>>         resolve the dependencies to SRC_URIs.
>>>     3. Save the SRC_URIs in a file and adapt all SRC_URIs users to handle
>>>         the SRC_URI files beside the SRC_URIs in the recipe.
>>     I made a few comments, and will have another / better look at the
>>     series tomorrow. There's a lot here, and it is hard to wrap my head
>>     around everything that is changing.
>>
>>     I have one specific question below (from the point of view of go).
>>
>>     I've been looking through the series, and can't pick out where #3 is
>>     done.
>
>     The files are created in the package manager specific vendor
>     classes (17 - 19) in the do_vendor_resolve task. The parsing is
>     implemented in the package manager specific modules in the vendor
>     package (6-8).
>
>
> aha. I'll have a closer look in a bit!
>
>>       I see patch 14 using SRC_URI_FILES, but where are those files
>>     written ? Is that in patch 18 (vendor_go_do_vendor_resolve ?)  What is
>>     written to those files ?
>
>     The file is written into the vendor directory below WORKDIR. The
>     approach is similar to other classes which need to share data
>     between tasks.
>
>     The files contain individual SRC_URIs per line.
>
> I may have missed that in the patches, but if that isn't described in 
> the commit logs, then
> that description would be a nice addition. Along with a high level 
> description for each
> supported language package manager about what is in the files and what 
> uses it to
> resolve the dependencies.

I will extend the commit messages.

>
>>     The concept that I'm not understanding (and that's just me not being
>>     familiar with things, I'll continue reading the series) is that when
>>     we suggested we'd like to have a mode where the dependencies could
>>     clearly be listed in the SRC_URI, at least I was just thinking about a
>>     way run the fetch/module elements that you were adding, write them to
>>     a file and then have the recipe include it.
>
>     The additional SRC_URIs are dynamically added to the recipe
>     without the indirection over an include file. The generated
>     SRC_URIs could be inspected via the SRC_URI_FILES and manipulated
>     via patches for the lock files or an separated lock file.
>
> The issue with patching those dynamic files .. is just that, they are 
> dynamic and
> they could be regenerated (but hopefully without a SRCREV change they 
> are identically
> generated each time, so maybe it isn't a big deal) and patching could 
> fail. Much like we
> don't patch generated automake files, we patch the .am and .in files 
> that generate the
> outputs.

You can't compare lock files with automake files. The lock files is 
generated but it contains additional information. The only difference is 
that a program and not a human write the file. If an update creates too 
much noise in the file we should discuss with upstream how to minimize 
it.  The lock file is designed to be under revision control and 
shouldn't change without reason. Dependabot automatically creates 
updates and pull requests for dependency updates. This will not work if 
the lock file isn't deterministic.

>
>>     I can't tell if in the series those files are written each time, and
>>     that there would be no way to edit those SRC_URI_FILES .. but I'll
>>     look again tomorrow.
>
>     The files are written if the do_vendor_resolve task need to be
>     rerun. It isn't possible to edit the generated SRC_URIs. Instead
>     the lock file could be patched.
>
>
> ok. So they are really just a way to dump what is being built to disk 
> and out of "memory",
> it really isn't what I was looking for, but at least I understand what 
> you were trying to
> do with the writing and later use of the files now.
>
> I was hoping for something that I could include "statically" (for lack 
> of a better term) in my
> recipes, and then have the handlers for the protocols do the fetching 
> .. again, much like
> the crate:// fetches in the .inc files.

I don't use the fetcher because of its drawbacks and limitations. I use 
the same wget URL without the indirection over the package manager 
specific fetchers. I can follow the pypi approach to generate SRC_URIs 
which call a python function:

${@crate_src_uri(d, 'xyz', '1.2.3')}

But why you need this? In any case the manipulation of a dependency 
could lead to interdependence between dependencies.

> To be clear, I'm not suggesting that mode would be the only mode, just 
> that the way the
> generation of the fetches -> actual fetching was constructed such that 
> I could avoid
> "short circuit" the handling of the lock file and simply list the 
> dependencies for fetching
> (much like how I can go get all of the SRCREVS for a gitsm:// fetch, 
> and put them into
> my recipes as pure git:// fetches if I'm having issues with the git 
> submodles).
Add a function to create this file isn't a problem, but I can't ensure 
that this will work in any case and doesn't create problems because of 
the discrepancy between the manifest / lock file and the available sources.

>>     That file would manipulate the standard SRC_URI. In other words still
>>     support a mode that is like the .inc files with crate://. So someone
>>     could either have the lockfile parsed and fetched, or have a way to
>>     run the parsing and fetching via a task, write a file and include the
>>     file in their recipe to short circuit the processing of the lockfile.
>>     (meaning the expanded and end fetches that are done once you've
>>     processed the file are simply listed as a series of fetches that are
>>     carried out without extra processing .. and "unrolled" dependency
>>     file pointing at the "sources" git, crate, mod, whatever)
>
>     What is the motivation "to short circuit the processing of the
>     lockfile"? Like any task the processing and its output are cached
>     via the sstate cache.
>
>
> See above. It isn't about re-running it a later time and re-using the 
> artifacts, it is about
> having a way to make sure nothing is dynamically resolved when bitbake 
> <foo> is called,
> just fetch and the rest of the standard tasks.

The resolve always create the same URL like the crate fetcher. It only 
changes if you change the resolve function or the crate fetcher. Every 
needed information is defined inside the lock file.

>
>     It is possible to use the vendor package to create a include file
>     but we should have good reasons to support two solutions for the
>     same problem.
>
>>     If that just doesn't make sense, then if there was a way to copy
>>     the lockfile out of the recipe and have it overlayed onto the fetched
>>     one .. maybe breaking out the individual fetch lines isn't required,
>>     since they could be individually manipulated in that lockfile.
>
>     I haven't test it but this should be possible. You can place a
>     lock file beside the recipe, add it to the SRC_URI and change the
>     XXX_LOCK_PATH.
>
>
> Something like that is a big step towards having that finer grained 
> control in a recipe that
> I'm looking for. I'd still like some sort of line by line "dumped 
> dependency list" if there's a
> lower level protocol at play (but the lock file really also is just 
> that line by line list for many
> of the languages).

Why you need this finer grained control in the recipe? You have the 
finer grained control in the lock file and additional tools to manage 
the file and all its interdependence. The resolve is deterministic and 
the .inc is only another representation. Manipulation of the 
representation could lead to problems and complicate the process. It's 
like you translate the .am and .in files into a .inc file to influence 
the generated automake files.

Would it help if we have a devtool shell so that you can run "cargo 
update" inside the folder created by "devtool modify" to update 
dependencies via the common tools and create a patch?

[-- Attachment #2: Type: text/html, Size: 16638 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 06/30] lib: oe: vendor: add cargo support
  2025-02-12 17:48       ` Frédéric Martinsons
@ 2025-02-13  8:53         ` Stefan Herbrechtsmeier
  0 siblings, 0 replies; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-13  8:53 UTC (permalink / raw)
  To: Frédéric Martinsons; +Cc: openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 2149 bytes --]

Am 12.02.2025 um 18:48 schrieb Frédéric Martinsons:
>
>
> Le mer. 12 févr. 2025, 17:29, Stefan Herbrechtsmeier 
> <stefan.herbrechtsmeier-oss@weidmueller.com> a écrit :
>
>     Am 12.02.2025 um 13:45 schrieb Frédéric Martinsons:
>>
>>     On Tue, 11 Feb 2025 at 16:01, Stefan Herbrechtsmeier via
>>     lists.openembedded.org <http://lists.openembedded.org>
>>     <stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org>
>>     wrote:
>>
>>         From: Stefan Herbrechtsmeier
>>         <stefan.herbrechtsmeier@weidmueller.com>
>>
>>         Add a vendor module for cargo to resolve dependencies and
>>         populate
>>         vendor directories from a Cargo.lock file.
>>
>>
>>
>>     Hello,
>>
>>     Have you looked at vendor subcommand of cargo :
>>     https://doc.rust-lang.org/cargo/commands/cargo-vendor.html ?
>>     I didn't read the series but the commit message makes me think
>>     that "cargo vendor" already exists for resolving dependencies
>>     and populating a vendor directory.
>>
>     The class uses the bitbake fetcher (wget / git) to create a vendor
>     directory and emulate the cargo vendor command.
>
>
> Yes, I understood that. Let me rephrase my question.
> Is it desirable/needed to mimick an existing (upstream and maintained) 
> command, considering that we already use native cargo to build rust 
> binaries?
We already mimick the cargo vendor command. But at the moment the code 
is hidden inside the crate fetcher.

We need to bypass the download of crates via cargo to support download 
mirrors and offline build. Therefore we download the files via wget and 
populate a local crate repository.

> Is the new flow you suggest can use the "cargo vendor" call?

It is useless because we already create a vendor folder manual 
(CARGO_VENDORING_DIRECTORY).

> Maybe there is room for less custom code here. Sorry if I missed 
> something obvious, I just react to some keywords in area that I 
> contributed 2 years ago.

I mainly extend existing code from crate fetcher and 
cargo-update-recipe-crate class. We need to extract download information 
from the lock file to create SRC_URIs.

[-- Attachment #2: Type: text/html, Size: 5466 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-12 17:45           ` Bruce Ashfield
  2025-02-12 17:52             ` Richard Purdie
@ 2025-02-13 12:45             ` Stefan Herbrechtsmeier
  2025-02-13 17:07               ` Bruce Ashfield
  1 sibling, 1 reply; 75+ messages in thread
From: Stefan Herbrechtsmeier @ 2025-02-13 12:45 UTC (permalink / raw)
  To: Bruce Ashfield; +Cc: Richard Purdie, openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 14988 bytes --]

Am 12.02.2025 um 18:45 schrieb Bruce Ashfield:
>
>
> On Wed, Feb 12, 2025 at 12:24 PM Stefan Herbrechtsmeier 
> <stefan.herbrechtsmeier-oss@weidmueller.com> wrote:
>
>     Am 12.02.2025 um 16:07 schrieb Bruce Ashfield:
>>     On Wed, Feb 12, 2025 at 9:36 AM Stefan Herbrechtsmeier via
>>     lists.openembedded.org <http://lists.openembedded.org>
>>     <stefan.herbrechtsmeier-oss=weidmueller.com@lists.openembedded.org>
>>     wrote:
>>
>>         Am 11.02.2025 um 22:46 schrieb Richard Purdie:
>>>         On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier vialists.openembedded.org <http://lists.openembedded.org> wrote:
>>>>         From: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com> <mailto:stefan.herbrechtsmeier@weidmueller.com>
>>>>
>>>>         Signed-off-by: Stefan Herbrechtsmeier<stefan.herbrechtsmeier@weidmueller.com> <mailto:stefan.herbrechtsmeier@weidmueller.com>
>>>>         ---
>>>>
>>>>           .../python/python3-bcrypt-crates.inc          | 84 -------------------
>>>>           .../python/python3-bcrypt_4.2.1.bb <http://python3-bcrypt_4.2.1.bb>            |  4 +-
>>>>           2 files changed, 1 insertion(+), 87 deletions(-)
>>>>           delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc
>>>         So let me as the silly question. This removes the crates.inc file and
>>>         doesn't appear to add any kind of new list of locked down modules.
>>         The list is generated on the fly like gitsm and doesn't
>>         require an extra step.
>>
>>>         This means that inspection tools just using the metadata can't see
>>>         "into" this recipe any longer for component information.
>>
>>         We support and use python code inside the variables and
>>         thereby need a preprocessing of the metadata in any case.
>>
>>         What do you mean by "component information"?
>>
>>>         This was
>>>         something that some people felt strongly that was a necessary part of
>>>         recipe metadata, for license, security and other manifest activities.
>>
>>         Why can't they use the SBOM for this?
>>
>>>         Are we basically saying that information is now only available after
>>>         the build takes place?
>>         They are only available after a special task run.
>>
>>>         I'm very worried that the previous discussions didn't reach a
>>>         conclusion and this is moving the "magic" out of bitbake and into some
>>>         vendor classes without addressing the concerns previously raised about
>>>         transparency into the manifests of what is going on behind the scenes.
>>
>>         I try to address the concerns but don't realize that the
>>         missing information in the recipe is a blocker.
>>
>>         This version gives the user the possibility to influence the
>>         dependencies via patches or alternative lock file. It creates
>>         a vendor folder for easy patch and debug. It integrates the
>>         dependencies into the SBOM for security tracking.
>>
>>         I skipped the license topic for now because the package
>>         managers don't handle license integrity. We have to keep the
>>         information in the recipe but hopefully the license
>>         information doesn't change with each update.
>>
>>         I don't understand the requirement for the plain inspection.
>>         In my opinion external tools should always use a defined
>>         output and shouldn't depend on the project internal details.
>>         I adapt the existing users of the SRC_URI to include the
>>         dynamic SRC_URIs.
>>
>>>         I appreciate some of the requirements are conflicting.
>>>
>>>         For the record in some recent meetings, I was promised that help would
>>>         be forthcoming in helping guide this discussion. I therefore left
>>>         things alone in the hope that would happen. It simply hasn't, probably
>>>         due to time/work issues, which I can sympathise with but it does mean
>>>         I'm left doing a bad job of trying to respond to your patches whilst
>>>         trying to do too many other things badly too. That leaves us both very
>>>         frustrated.
>>>
>>>         I really want to see you succeed in reworking this and I appreciate the
>>>         time and effort put into the patches. To make this successful, I know
>>>         there are key stakeholders who need to buy into it and right now,
>>>         they're more likely just to keep doing their own things as it is easier
>>>         since this isn't going the direction they want. A key piece of making
>>>         this successful is negotiating something which can work for a
>>>         significant portion of them. I'm spelling all this out since I do at
>>>         least want to make the situation clear.
>>>
>>>         Yes, I'm very upset the OE community is putting me in this position
>>>         despite me repeatedly asking for help and that isn't your fault, which
>>>         just frustrates me more.
>>
>>         My problem is the double standards. We support a fetcher
>>         which dynamic resolve dependencies and without manual update
>>         step since years. Nobody suggests to make the gitsm fetcher
>>         obsolete and requests the users to run an update task after a
>>         SRC_URI change to create a .inc file with the SRC_URIs of all
>>         the recursive submodules. Nobody complains about the missing
>>         components in the recipe.
>>
>>     There's no double standard, I'd simply say that design decisions
>>     of the past doesn't mean that there aren't better ways to do
>>     something new.
>>
>>     Richard went out of his way to explain the status and what sort
>>     of review needs to happen, I'll add that while getting frustrated
>>     with it is natural, pushing back on people doing reviews isn't
>>     going to help get things merged, it will do the opposite.
>>
>>     There have been plenty of complaints and issues with the gitsm
>>     fetcher, but the reality is that if someone wants to get at the
>>     base components of what it is doing, they can do so. I've had to
>>     take several of my maintained recipes out of gitsm and back to
>>     the base git fetches. The submodules were simply fetching code
>>     that didn't build and there was no way to fetch it.  The gitsm
>>     fetcher is also relatively lightly used, much less complicated
>>     and doesn't need much extra in infrastructure to support it.
>
>     Thanks for your insides. There a two main solutions for the
>     problem. Add patch support to gitsm so that you could use the git
>     submodule command and create a patch or generate a .inc file and
>     manipulate the SRCREVs. I assume you would prefer a .inc file.
>     What do you think is the downside of a patch?
>
>
> It is much easier to get a complete view of the file with a drop-in, 
> versus a patch (depending on the size of the file). You need to know 
> the base directory, the depth, put in an upstream-status, create it, 
> copy it to your layer, etc. With a drop-in lock file, I copy it out, 
> edit it, and add it to my SRC_URI.  Not much difference in the end, 
> but I prefer the drop-in approach on pretty much any configuration 
> file in my builds, not just this example.

Is a drop-in lock file okay for you or do you require a support to 
generate .inc files?

>
>>
>>         Whether we have hard requirements and introduce a git
>>         submodule support which satisfy the requirements or we accept
>>         the advantages of a simple user interface and minimize the
>>         disadvantages.
>>
>>     Unfortunately in my experience the simple interfaces hiding
>>     complexity don't help when things go wrong. That's how I ended up
>>     where I am with my go recipes, and why I ended up tearing my
>>     gitsm recipe back into its components. There was no way to
>>     influence / fix the build otherwise, and they didn't support
>>     bleeding edge development very well.
>     Do you have a good example for a problematic go recipe to test my
>     approach?
>
>
> Not right now, the current state is relatively stable as I'm working 
> towards the LTS release. These have just popped up repeatedly over the 
> maybe 5+ years (I can't remember how long it has been!) in maintaining 
> meta-virtualization. I have no doubts (and am not implying) that your 
> series could adapt my recipes and use all of the go mod infrastructure 
> .. just with all of the vendoring and go mod efforts over the years, 
> going all the way back to the actual source code gave a lot more 
> visibility into the vendor dependencies (and not just what was 
> released for them) and I've used it many times while debugging runtime 
> issues of the container stacks.
>
>
>>     I'm definitely one of the people Richard is mentioning as a
>>     stakeholder, and one that could likely just ignore all of this ..
>>     but I'm attempting to wade into it again.
>
>     I am very grateful for that.
>
>>
>>     None of us have the hands on, daily experience with the
>>     components at play as you do right now, so patience on your part
>>     will be needed as we ask many not-so-intelligent questions.
>
>     That's no problem.
>
>>
>>         It doesn't matter if we run the resolve function inside a
>>         resolve, fetch or update task. The questions is do we want to
>>         support dynamic SRC_URIs or do we want an manual update task.
>>         The task needs to be manual run after a SRC_URI change and
>>         can produces a lot of noise in the update commit. In any case
>>         the manual editing of the SRC_URI isn't practical and the
>>         users will use the package manager to update dependencies and
>>         its recursive dependencies.
>>
>>     I don't understand the series quite enough yet to say "why can't
>>     we do both", if there was a way to abstract / componentize what
>>     is generating those dynamic SCR_URIS in such a way that an
>>     external tool or update task could generate them, and if they
>>     were already in place the dynamic generation wouldn't run at
>>     build time, that should keep both modes working.
>     If it is desired I can add both variants.
>
>
> Forcing one approach over the other isn't really going to make it 
> mergeable (or maybe I should say make it adopted by all).
>
> We need to help developers as well as people just doing "load build" 
> for distros (that should be in a steady state).  I'm under no illusion 
> that the way I handle the go recipes won't work for everyone either, 
> so I definitely wouldn't propose it as such.
The disadvantage of two approach is that you double the issues. It is 
much simpler if we always depend on the lock file and only support 
embedded and drop-in lock files. I can optimize the generated SRC_URIs 
but wouldn't support the manipulation of the SRC_URI because of it 
unforeseeable consequences. We didn't know which commands of the package 
manager depends on the lock file and I would avoid the regeneration of 
the lock file.

>>     I admit to not understanding why we'd be overly concerned about
>>     noise in the commits (for the dependencies) if they are split
>>     into separate files in the recipe. More information is always
>>     better when I'm dealing with the updates. I just scroll past it
>>     if I'm not interested and filter it if I am.
>     The problem is to identify the relevant parts. Lets say you update
>     a dependency because of an security issue. Afterwards you update
>     the project with a lot of dependency changes. You have to review
>     the complete noise to determine if your updated dependency doesn't
>     go backward in its version. It is much easier to use a patch.
>     After the project update the patch will fail or not. If it fails
>     you have a direct focus on the affected dependency. If you back
>     port the patch from the project you could simple drop it with the
>     next update.
>
>
> I prefer all of the extra information, but maybe that's my kernel 
> background. It's the same reason why all my recipe / version updates 
> contain all the short logs between the releases. I can just skip / 
> ignore the information most of the time, but it comes in handy when 
> looking for a security issue, etc.
Maybe we could add the dynamic dependencies to the buildhistory.

> In my go recipes, I have a look at the dependency SRCREVS between 
> updates. In particular if I'm debugging a runtime issue, that helps me 
> quickly see if a dependency changed and by how much it changed.
>
> I could do the same with a drop-in lockfile that was in my recipe, 
> since I'd have the delta readily available and could see the source 
> revisions, etc.
>
> Of course if a drop-in file was used, we'd want some sort of hash for 
> the original file it was clobbering, since that indicates an update 
> would be required (or dropping it, etc).
>
>
>
>>     I feel the pain (and your pain) of this after supporting
>>     complicated go/mixed language recipes through multiple major
>>     releases (and through go's changing dependency model + bleeding
>>     edge code, etc) and needing to track what has changed, so I
>>     definitely encourage you to keep working on this.
>>
>>         As a compromise we could add a new feature to generate .inc
>>         cache files before the main bitbake run. This would eliminate
>>         the manual update run and the commit noise as well as special
>>         fetch, unpack and patch task.
>>
>>     Can you elaborate on what you mean by before the main bitbake run
>>     ? Would it be still under a single bitbake invokation or would it
>>     be multiple runs (I support multiple runs, so don't take that as
>>     a leading question).
>
>     I can't answer this questions and need Richard guidance to
>     implement such a feature. I would assume that bitbake already
>     track file changes and can update its state. The behavior should
>     be similar to a change in the .inc file. Bitbake will detect that
>     a "include_cache" file is missing and run an update_cache task on
>     the recipe. Afterwards bitbake detect a file change on the
>     "include_cache" file and parse it. We need a possibility to mark
>     patches which shouldn't be applied if the "include_cache" file is
>     missing because the dependencies are missing. We need to run the
>     fetch, unpack and patch task before the update_cache task to
>     generate the .inc file.
>
> Aha. Maybe Richard will comment later. I was thinking more about 
> something that was in two distinct phases, but with some more thinking 
> and explanation, maybe this is workable as well.

This is only needed if we need the dynamic SRC_URIs outside of bitbake 
in the common bitbake format (SRC_URI += "..."). Otherwise we could save 
the information inside the WORKDIR and depend on the sstate cache.

[-- Attachment #2: Type: text/html, Size: 27458 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
  2025-02-13  8:36       ` Stefan Herbrechtsmeier
@ 2025-02-13 17:01         ` Bruce Ashfield
  0 siblings, 0 replies; 75+ messages in thread
From: Bruce Ashfield @ 2025-02-13 17:01 UTC (permalink / raw)
  To: Stefan Herbrechtsmeier
  Cc: openembedded-core, Stefan Herbrechtsmeier, bitbake-devel

[-- Attachment #1: Type: text/plain, Size: 11990 bytes --]

On Thu, Feb 13, 2025 at 3:36 AM Stefan Herbrechtsmeier <
stefan.herbrechtsmeier-oss@weidmueller.com> wrote:

> Am 12.02.2025 um 15:11 schrieb Bruce Ashfield:
>
>
>
> On Wed, Feb 12, 2025 at 3:41 AM Stefan Herbrechtsmeier <
> stefan.herbrechtsmeier-oss@weidmueller.com> wrote:
>
>> Am 12.02.2025 um 00:14 schrieb Bruce Ashfield via lists.openembedded.org:
>>
>> In message: [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust
>> on 11/02/2025 Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>>
>>
>> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> <stefan.herbrechtsmeier@weidmueller.com>
>>
>> The series adds on-the-fly support for package manager specific
>> dependencies and vendor directories. It contains the following changes:
>> 1. Adds an early fetch, unpack and patch task to unpack and patch source
>>    code with an embedded lock file for dependencies.
>> 2. Parse the go.sum, Cargo.lock and package-lock.json lock files and
>>    resolve the dependencies to SRC_URIs.
>> 3. Save the SRC_URIs in a file and adapt all SRC_URIs users to handle
>>    the SRC_URI files beside the SRC_URIs in the recipe.
>>
>> I made a few comments, and will have another / better look at the
>> series tomorrow. There's a lot here, and it is hard to wrap my head
>> around everything that is changing.
>>
>> I have one specific question below (from the point of view of go).
>>
>> I've been looking through the series, and can't pick out where #3 is
>> done.
>>
>> The files are created in the package manager specific vendor classes (17
>> - 19) in the do_vendor_resolve task. The parsing is implemented in the
>> package manager specific modules in the vendor package (6-8).
>>
>>
> aha. I'll have a closer look in a bit!
>
>
>
>>  I see patch 14 using SRC_URI_FILES, but where are those files
>> written ? Is that in patch 18 (vendor_go_do_vendor_resolve ?)  What is
>> written to those files ?
>>
>> The file is written into the vendor directory below WORKDIR. The approach
>> is similar to other classes which need to share data between tasks.
>>
>> The files contain individual SRC_URIs per line.
>>
> I may have missed that in the patches, but if that isn't described in the
> commit logs, then
> that description would be a nice addition. Along with a high level
> description for each
> supported language package manager about what is in the files and what
> uses it to
> resolve the dependencies.
>
> I will extend the commit messages.
>
>
>> The concept that I'm not understanding (and that's just me not being
>> familiar with things, I'll continue reading the series) is that when
>> we suggested we'd like to have a mode where the dependencies could
>> clearly be listed in the SRC_URI, at least I was just thinking about a
>> way run the fetch/module elements that you were adding, write them to
>> a file and then have the recipe include it.
>>
>> The additional SRC_URIs are dynamically added to the recipe without the
>> indirection over an include file. The generated SRC_URIs could be inspected
>> via the SRC_URI_FILES and manipulated via patches for the lock files or an
>> separated lock file.
>>
> The issue with patching those dynamic files .. is just that, they are
> dynamic and
> they could be regenerated (but hopefully without a SRCREV change they are
> identically
> generated each time, so maybe it isn't a big deal) and patching could
> fail. Much like we
> don't patch generated automake files, we patch the .am and .in files that
> generate the
> outputs.
>
> You can't compare lock files with automake files. The lock files is
> generated but it contains additional information. The only difference is
> that a program and not a human write the file. If an update creates too
> much noise in the file we should discuss with upstream how to minimize it.
> The lock file is designed to be under revision control and shouldn't change
> without reason. Dependabot automatically creates updates and pull requests
> for dependency updates. This will not work if the lock file isn't
> deterministic.
>

I may be using different terminology, but I do know what the lock files are
(I interchange the dependency and lock files at times though), patching
*anything* that is generated is a bad idea, that's my point (so the
comparison is valid).


>
>> I can't tell if in the series those files are written each time, and
>> that there would be no way to edit those SRC_URI_FILES .. but I'll
>> look again tomorrow.
>>
>> The files are written if the do_vendor_resolve task need to be rerun. It
>> isn't possible to edit the generated SRC_URIs. Instead the lock file could
>> be patched.
>>
>
> ok. So they are really just a way to dump what is being built to disk and
> out of "memory",
> it really isn't what I was looking for, but at least I understand what you
> were trying to
> do with the writing and later use of the files now.
>
> I was hoping for something that I could include "statically" (for lack of
> a better term) in my
> recipes, and then have the handlers for the protocols do the fetching ..
> again, much like
> the crate:// fetches in the .inc files.
>
> I don't use the fetcher because of its drawbacks and limitations. I use
> the same wget URL without the indirection over the package manager specific
> fetchers. I can follow the pypi approach to generate SRC_URIs which call a
> python function:
>
Can you elaborate on the limitations ?

 Although from your description, I'm fine calling wget a "fetcher". I'm
just talking about something that pulls in the dependency source code,
whether it be git, wget, or some other protocol, it's the concept that is
the same.

> ${@crate_src_uri(d, 'xyz', '1.2.3')}
>
> But why you need this? In any case the manipulation of a dependency could
> lead to interdependence between dependencies.\
>

Because I need to redirect and update them manually. Anything that runs in
python to determine the fetch is also hard to debug, since I'd be
interested in the output of that processing if there's an issue.

I'm describing something like (and I'm describing it badly .. but I'll try
anyway:

 <language file that describes the dependencies>
 <process that file into a specific source  revision and fetch/download
location>
 <have a language / protocol specific fetcher get the modules / source code
iteratively from a list of expanded dependencies>
 <put them into place for the build>
 <arrange for the build to use those fetched depdendencies>

wget would fall into that "language specific fetcher", as would git or "go
vendor" (Although I don't really like that, since it isn't transparent
where the source code is being pulled from).  Copying the files into
vendor, or again "go mod vendor" (doing both the fetch and placement) would
be the "put them in place for the build".

I realize that is what your series is doing.

The processing, fetching, placement  stages could run fully behind the
scenes from a dependency/lock file, or be skipped if broken out into the
list of fetches (from the SCR_URI (via .inc file or whatever)). Those are
the two modes I'm describing, where the "processing the file into a
specific source revision / fetch steps" can be avoided.



>
>
> To be clear, I'm not suggesting that mode would be the only mode, just
> that the way the
> generation of the fetches -> actual fetching was constructed such that I
> could avoid
> "short circuit" the handling of the lock file and simply list the
> dependencies for fetching
> (much like how I can go get all of the SRCREVS for a gitsm:// fetch, and
> put them into
> my recipes as pure git:// fetches if I'm having issues with the git
> submodles).
>
> Add a function to create this file isn't a problem, but I can't ensure
> that this will work in any case and doesn't create problems because of the
> discrepancy between the manifest / lock file and the available sources.
>

Right, and that is fine. If someone bumps a revision to the point where the
dependency now has different dependencies that are not in the lock file,
then they've taken things fully into their control and need to deal with
any issues.  That obviously isn't the default, but does allow an advanced
user/developer the possibility to have fine grained control and debug.


>
> That file would manipulate the standard SRC_URI. In other words still
>> support a mode that is like the .inc files with crate://. So someone
>> could either have the lockfile parsed and fetched, or have a way to
>> run the parsing and fetching via a task, write a file and include the
>> file in their recipe to short circuit the processing of the lockfile.
>> (meaning the expanded and end fetches that are done once you've
>> processed the file are simply listed as a series of fetches that are
>> carried out without extra processing .. and "unrolled" dependency
>> file pointing at the "sources" git, crate, mod, whatever)
>>
>> What is the motivation "to short circuit the processing of the lockfile"?
>> Like any task the processing and its output are cached via the sstate cache.
>>
>
> See above. It isn't about re-running it a later time and re-using the
> artifacts, it is about
> having a way to make sure nothing is dynamically resolved when bitbake
> <foo> is called,
> just fetch and the rest of the standard tasks.
>
> The resolve always create the same URL like the crate fetcher. It only
> changes if you change the resolve function or the crate fetcher. Every
> needed information is defined inside the lock file.
>
That's good, and if the lock file is present (versus just a dependency
file), would the processing and creation of the lock file be skipped ?



>
>
>> It is possible to use the vendor package to create a include file but we
>> should have good reasons to support two solutions for the same problem.
>>
>> If that just doesn't make sense, then if there was a way to copy
>> the lockfile out of the recipe and have it overlayed onto the fetched
>> one .. maybe breaking out the individual fetch lines isn't required,
>> since they could be individually manipulated in that lockfile.
>>
>> I haven't test it but this should be possible. You can place a lock file
>> beside the recipe, add it to the SRC_URI and change the XXX_LOCK_PATH.
>>
>
> Something like that is a big step towards having that finer grained
> control in a recipe that
> I'm looking for. I'd still like some sort of line by line "dumped
> dependency list" if there's a
> lower level protocol at play (but the lock file really also is just that
> line by line list for many
> of the languages).
>
> Why you need this finer grained control in the recipe? You have the finer
> grained control in the lock file and additional tools to manage the file
> and all its interdependence. The resolve is deterministic and the .inc is
> only another representation. Manipulation of the representation could lead
> to problems and complicate the process. It's like you translate the .am and
> .in files into a .inc file to influence the generated automake files.
>
The tools that I'm talking about are a text editor, not anything language
specific.  I don't want or need tools to manipulate those files, I want to
see the base fetches of the dependencies, it is those that I'm manipulating.

I'm simply describing what I've done in the past to fix issues with the
builds and pull in fixes, so yes, it is something that I need.


> Would it help if we have a devtool shell so that you can run "cargo
> update" inside the folder created by "devtool modify" to update
> dependencies via the common tools and create a patch?
>

Maybe, but I don't use devtool at all for my recipe maintenance, and I
would push back against it being a requirement to do so.

Bruce

[-- Attachment #2: Type: text/html, Size: 22053 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [OE-core] [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class
  2025-02-13 12:45             ` Stefan Herbrechtsmeier
@ 2025-02-13 17:07               ` Bruce Ashfield
  0 siblings, 0 replies; 75+ messages in thread
From: Bruce Ashfield @ 2025-02-13 17:07 UTC (permalink / raw)
  To: Stefan Herbrechtsmeier
  Cc: Richard Purdie, openembedded-core, Stefan Herbrechtsmeier

[-- Attachment #1: Type: text/plain, Size: 15644 bytes --]

On Thu, Feb 13, 2025 at 7:45 AM Stefan Herbrechtsmeier <
stefan.herbrechtsmeier-oss@weidmueller.com> wrote:

> Am 12.02.2025 um 18:45 schrieb Bruce Ashfield:
>
>
>
> On Wed, Feb 12, 2025 at 12:24 PM Stefan Herbrechtsmeier <
> stefan.herbrechtsmeier-oss@weidmueller.com> wrote:
>
>> Am 12.02.2025 um 16:07 schrieb Bruce Ashfield:
>>
>> On Wed, Feb 12, 2025 at 9:36 AM Stefan Herbrechtsmeier via
>> lists.openembedded.org <stefan.herbrechtsmeier-oss=
>> weidmueller.com@lists.openembedded.org> wrote:
>>
>>> Am 11.02.2025 um 22:46 schrieb Richard Purdie:
>>>
>>> On Tue, 2025-02-11 at 16:00 +0100, Stefan Herbrechtsmeier via lists.openembedded.org wrote:
>>>
>>> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> <stefan.herbrechtsmeier@weidmueller.com>
>>>
>>> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> <stefan.herbrechtsmeier@weidmueller.com>
>>> ---
>>>
>>>  .../python/python3-bcrypt-crates.inc          | 84 -------------------
>>>  .../python/python3-bcrypt_4.2.1.bb            |  4 +-
>>>  2 files changed, 1 insertion(+), 87 deletions(-)
>>>  delete mode 100644 meta/recipes-devtools/python/python3-bcrypt-crates.inc
>>>
>>> So let me as the silly question. This removes the crates.inc file and
>>> doesn't appear to add any kind of new list of locked down modules.
>>>
>>> The list is generated on the fly like gitsm and doesn't require an extra
>>> step.
>>>
>>> This means that inspection tools just using the metadata can't see
>>> "into" this recipe any longer for component information.
>>>
>>> We support and use python code inside the variables and thereby need a
>>> preprocessing of the metadata in any case.
>>>
>>> What do you mean by "component information"?
>>>
>>> This was
>>> something that some people felt strongly that was a necessary part of
>>> recipe metadata, for license, security and other manifest activities.
>>>
>>> Why can't they use the SBOM for this?
>>>
>>> Are we basically saying that information is now only available after
>>> the build takes place?
>>>
>>> They are only available after a special task run.
>>>
>>> I'm very worried that the previous discussions didn't reach a
>>> conclusion and this is moving the "magic" out of bitbake and into some
>>> vendor classes without addressing the concerns previously raised about
>>> transparency into the manifests of what is going on behind the scenes.
>>>
>>> I try to address the concerns but don't realize that the missing
>>> information in the recipe is a blocker.
>>>
>>> This version gives the user the possibility to influence the
>>> dependencies via patches or alternative lock file. It creates a vendor
>>> folder for easy patch and debug. It integrates the dependencies into the
>>> SBOM for security tracking.
>>>
>>> I skipped the license topic for now because the package managers don't
>>> handle license integrity. We have to keep the information in the recipe but
>>> hopefully the license information doesn't change with each update.
>>>
>>> I don't understand the requirement for the plain inspection. In my
>>> opinion external tools should always use a defined output and shouldn't
>>> depend on the project internal details. I adapt the existing users of the
>>> SRC_URI to include the dynamic SRC_URIs.
>>>
>>> I appreciate some of the requirements are conflicting.
>>>
>>> For the record in some recent meetings, I was promised that help would
>>> be forthcoming in helping guide this discussion. I therefore left
>>> things alone in the hope that would happen. It simply hasn't, probably
>>> due to time/work issues, which I can sympathise with but it does mean
>>> I'm left doing a bad job of trying to respond to your patches whilst
>>> trying to do too many other things badly too. That leaves us both very
>>> frustrated.
>>>
>>> I really want to see you succeed in reworking this and I appreciate the
>>> time and effort put into the patches. To make this successful, I know
>>> there are key stakeholders who need to buy into it and right now,
>>> they're more likely just to keep doing their own things as it is easier
>>> since this isn't going the direction they want. A key piece of making
>>> this successful is negotiating something which can work for a
>>> significant portion of them. I'm spelling all this out since I do at
>>> least want to make the situation clear.
>>>
>>> Yes, I'm very upset the OE community is putting me in this position
>>> despite me repeatedly asking for help and that isn't your fault, which
>>> just frustrates me more.
>>>
>>> My problem is the double standards. We support a fetcher which dynamic
>>> resolve dependencies and without manual update step since years. Nobody
>>> suggests to make the gitsm fetcher obsolete and requests the users to run
>>> an update task after a SRC_URI change to create a .inc file with the
>>> SRC_URIs of all the recursive submodules. Nobody complains about the
>>> missing components in the recipe.
>>>
>> There's no double standard, I'd simply say that design decisions of the
>> past doesn't mean that there aren't better ways to do something new.
>>
>> Richard went out of his way to explain the status and what sort of review
>> needs to happen, I'll add that while getting frustrated with it is natural,
>> pushing back on people doing reviews isn't going to help get things merged,
>> it will do the opposite.
>>
>> There have been plenty of complaints and issues with the gitsm fetcher,
>> but the reality is that if someone wants to get at the base components of
>> what it is doing, they can do so. I've had to take several of my maintained
>> recipes out of gitsm and back to the base git fetches. The submodules were
>> simply fetching code that didn't build and there was no way to fetch it.
>> The gitsm fetcher is also relatively lightly used, much less complicated
>> and doesn't need much extra in infrastructure to support it.
>>
>> Thanks for your insides. There a two main solutions for the problem. Add
>> patch support to gitsm so that you could use the git submodule command and
>> create a patch or generate a .inc file and manipulate the SRCREVs. I assume
>> you would prefer a .inc file. What do you think is the downside of a patch?
>>
>
> It is much easier to get a complete view of the file with a drop-in,
> versus a patch (depending on the size of the file). You need to know the
> base directory, the depth, put in an upstream-status, create it, copy it to
> your layer, etc. With a drop-in lock file, I copy it out, edit it, and add
> it to my SRC_URI.  Not much difference in the end, but I prefer the drop-in
> approach on pretty much any configuration file in my builds, not just this
> example.
>
> Is a drop-in lock file okay for you or do you require a support to
> generate .inc files?
>
If the drop-in lock file is a one by one listing of dependencies that can
be mapped to fetches, then it serves the same purpose as the .inc file, so
that would be fine with me. But I'd have to see what the implementation
looked like to be sure!



>
>
>>
>>> Whether we have hard requirements and introduce a git submodule support
>>> which satisfy the requirements or we accept the advantages of a simple user
>>> interface and minimize the disadvantages.
>>>
>> Unfortunately in my experience the simple interfaces hiding complexity
>> don't help when things go wrong. That's how I ended up where I am with my
>> go recipes, and why I ended up tearing my gitsm recipe back into its
>> components. There was no way to influence / fix the build otherwise, and
>> they didn't support bleeding edge development very well.
>>
>> Do you have a good example for a problematic go recipe to test my
>> approach?
>>
>
> Not right now, the current state is relatively stable as I'm working
> towards the LTS release. These have just popped up repeatedly over the
> maybe 5+ years (I can't remember how long it has been!) in maintaining
> meta-virtualization. I have no doubts (and am not implying) that your
> series could adapt my recipes and use all of the go mod infrastructure ..
> just with all of the vendoring and go mod efforts over the years, going all
> the way back to the actual source code gave a lot more visibility into the
> vendor dependencies (and not just what was released for them) and I've used
> it many times while debugging runtime issues of the container stacks.
>
>
>> I'm definitely one of the people Richard is mentioning as a stakeholder,
>> and one that could likely just ignore all of this .. but I'm attempting to
>> wade into it again.
>>
>> I am very grateful for that.
>>
>>
>> None of us have the hands on, daily experience with the components at
>> play as you do right now, so patience on your part will be needed as we ask
>> many not-so-intelligent questions.
>>
>> That's no problem.
>>
>>
>>> It doesn't matter if we run the resolve function inside a resolve, fetch
>>> or update task. The questions is do we want to support dynamic SRC_URIs or
>>> do we want an manual update task. The task needs to be manual run after a
>>> SRC_URI change and can produces a lot of noise in the update commit. In any
>>> case the manual editing of the SRC_URI isn't practical and the users will
>>> use the package manager to update dependencies and its recursive
>>> dependencies.
>>>
>> I don't understand the series quite enough yet to say "why can't we do
>> both", if there was a way to abstract / componentize what is generating
>> those dynamic SCR_URIS in such a way that an external tool or update task
>> could generate them, and if they were already in place the dynamic
>> generation wouldn't run at build time, that should keep both modes working.
>>
>> If it is desired I can add both variants.
>>
>
> Forcing one approach over the other isn't really going to make it
> mergeable (or maybe I should say make it adopted by all).
>
> We need to help developers as well as people just doing "load build" for
> distros (that should be in a steady state).  I'm under no illusion that the
> way I handle the go recipes won't work for everyone either, so I definitely
> wouldn't propose it as such.
>
> The disadvantage of two approach is that you double the issues. It is much
> simpler if we always depend on the lock file and only support embedded and
> drop-in lock files. I can optimize the generated SRC_URIs but wouldn't
> support the manipulation of the SRC_URI because of it unforeseeable
> consequences. We didn't know which commands of the package manager depends
> on the lock file and I would avoid the regeneration of the lock file.
>

Agreed that we need something maintainable, but we can't just forget about
the developer use case. We need to be able to support iterative, developer
workflows. This is something that we've always tried to do with the kernel
workflows, they aren't perfect, but those modes of working are considered.



>
> I admit to not understanding why we'd be overly concerned about noise in
>> the commits (for the dependencies) if they are split into separate files in
>> the recipe. More information is always better when I'm dealing with the
>> updates. I just scroll past it if I'm not interested and filter it if I am.
>>
>> The problem is to identify the relevant parts. Lets say you update a
>> dependency because of an security issue. Afterwards you update the project
>> with a lot of dependency changes. You have to review the complete noise to
>> determine if your updated dependency doesn't go backward in its version. It
>> is much easier to use a patch. After the project update the patch will fail
>> or not. If it fails you have a direct focus on the affected dependency. If
>> you back port the patch from the project you could simple drop it with the
>> next update.
>>
>
> I prefer all of the extra information, but maybe that's my kernel
> background. It's the same reason why all my recipe / version updates
> contain all the short logs between the releases. I can just skip / ignore
> the information most of the time, but it comes in handy when looking for a
> security issue, etc.
>
> Maybe we could add the dynamic dependencies to the buildhistory.
>

That would make buildhistory a requirement, which is something (as an
example) that I don't use. I'm just talking about something that goes along
with the git history of the recipe updates. All the information in one
place. I wouldn't get to hung up on this right now, as it would be simple
enough to commit changes to lock files, etc, with generated long logs that
contained all the information. That is outside of what this series needs to
consider.



>
> In my go recipes, I have a look at the dependency SRCREVS between updates.
> In particular if I'm debugging a runtime issue, that helps me quickly see
> if a dependency changed and by how much it changed.
>
> I could do the same with a drop-in lockfile that was in my recipe, since
> I'd have the delta readily available and could see the source revisions,
> etc.
>
> Of course if a drop-in file was used, we'd want some sort of hash for the
> original file it was clobbering, since that indicates an update would be
> required (or dropping it, etc).
>
>
>>
>> I feel the pain (and your pain) of this after supporting complicated
>> go/mixed language recipes through multiple major releases (and through go's
>> changing dependency model + bleeding edge code, etc) and needing to track
>> what has changed, so I definitely encourage you to keep working on this.
>>
>> As a compromise we could add a new feature to generate .inc cache files
>>> before the main bitbake run. This would eliminate the manual update run and
>>> the commit noise as well as special fetch, unpack and patch task.
>>>
>>> Can you elaborate on what you mean by before the main bitbake run ?
>> Would it be still under a single bitbake invokation or would it be multiple
>> runs (I support multiple runs, so don't take that as a leading question).
>>
>> I can't answer this questions and need Richard guidance to implement such
>> a feature. I would assume that bitbake already track file changes and can
>> update its state. The behavior should be similar to a change in the .inc
>> file. Bitbake will detect that a "include_cache" file is missing and run an
>> update_cache task on the recipe. Afterwards bitbake detect a file change on
>> the "include_cache" file and parse it. We need a possibility to mark
>> patches which shouldn't be applied if the "include_cache" file is missing
>> because the dependencies are missing. We need to run the fetch, unpack and
>> patch task before the update_cache task to generate the .inc file.
>>
> Aha. Maybe Richard will comment later. I was thinking more about something
> that was in two distinct phases, but with some more thinking and
> explanation, maybe this is workable as well.
>
> This is only needed if we need the dynamic SRC_URIs outside of bitbake in
> the common bitbake format (SRC_URI += "..."). Otherwise we could save the
> information inside the WORKDIR and depend on the sstate cache.
>

I think we are describing different things again. I'm just looking for the
ability to run some of the tasks separately and do it in two distinct
steps. So that wouldn't involve WORKDIR or sstate, but would just generate
the lock or .inc file, or whatever. And then have the build use that file
later.

Bruce

[-- Attachment #2: Type: text/html, Size: 29800 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

end of thread, other threads:[~2025-02-13 17:07 UTC | newest]

Thread overview: 75+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-11 15:00 [RFC PATCH 00/30] Add vendor support for go, npm and rust Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 01/30] classes: create-spdx-2.2: use expanded FetchData for downloaded packages Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 02/30] lib: spdx30_tasks: use expanded FetchData for download files Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 03/30] classes: create-spdx-2.2: use name and version for download dependencies Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 04/30] lib: bb: fetch2: add support to unpack .crate files Stefan Herbrechtsmeier
2025-02-11 21:22   ` [OE-core] " Richard Purdie
2025-02-11 15:00 ` [RFC PATCH 05/30] lib: oe: add vendor module Stefan Herbrechtsmeier
2025-02-11 21:31   ` [OE-core] " Richard Purdie
2025-02-12  9:27     ` Stefan Herbrechtsmeier
2025-02-12  9:38       ` Richard Purdie
2025-02-12 12:21         ` Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 06/30] lib: oe: vendor: add cargo support Stefan Herbrechtsmeier
2025-02-12 10:32   ` [OE-core] " Alexander Kanavin
2025-02-12 12:45   ` Frédéric Martinsons
2025-02-12 16:29     ` Stefan Herbrechtsmeier
2025-02-12 17:48       ` Frédéric Martinsons
2025-02-13  8:53         ` Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 07/30] lib: oe: vendor: add go support Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 08/30] lib: oe: vendor: add npm support Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 09/30] oeqa: oelib: add vendor tests Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 10/30] conf: bitbake: add SRC_URI_FILES variable Stefan Herbrechtsmeier
2025-02-11 16:22   ` [bitbake-devel] " Peter Kjellerstedt
2025-02-12  8:55     ` Stefan Herbrechtsmeier
2025-02-12  9:49       ` [OE-core] " Alexander Kanavin
2025-02-13  7:43         ` Stefan Herbrechtsmeier
2025-02-13  7:53           ` Alexander Kanavin
     [not found]       ` <18236D0FFBD06B89.28278@lists.openembedded.org>
2025-02-12 10:42         ` Alexander Kanavin
2025-02-11 19:06   ` Peter Kjellerstedt
2025-02-11 15:00 ` [RFC PATCH 11/30] classes: go: make source directory configurable Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 12/30] classes: go-mod: make class customizable Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 13/30] classes: add nodejs-arch class Stefan Herbrechtsmeier
2025-02-12 10:37   ` [OE-core] " Alexander Kanavin
2025-02-11 15:00 ` [RFC PATCH 14/30] classes: base: add get_src_uris and unpack_src_uris functions Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 15/30] classes: add early fetch, unpack and patch support Stefan Herbrechtsmeier
2025-02-11 22:27   ` [OE-core] " Richard Purdie
2025-02-12 12:21     ` Stefan Herbrechtsmeier
2025-02-11 22:32   ` Bruce Ashfield
2025-02-12 12:42     ` Stefan Herbrechtsmeier
2025-02-12 13:55       ` Bruce Ashfield
2025-02-12 14:40         ` Stefan Herbrechtsmeier
2025-02-12 11:08   ` Alexander Kanavin
2025-02-12 16:23     ` Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 16/30] classes: add vendor class Stefan Herbrechtsmeier
2025-02-11 19:17   ` [OE-core] " Peter Kjellerstedt
2025-02-11 15:00 ` [RFC PATCH 17/30] classes: add vendor class for cargo Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 18/30] classes: add vendor class for go Stefan Herbrechtsmeier
2025-02-11 22:59   ` [OE-core] " Bruce Ashfield
2025-02-12 15:23     ` Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 19/30] classes: add vendor class for npm Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 20/30] classes: add vendor_npm_build class Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 21/30] python3-bcrypt: mirgrate to vendor cargo class Stefan Herbrechtsmeier
2025-02-11 21:46   ` [OE-core] " Richard Purdie
2025-02-12 14:36     ` Stefan Herbrechtsmeier
2025-02-12 15:06       ` Richard Purdie
2025-02-12 17:27         ` Stefan Herbrechtsmeier
2025-02-12 15:07       ` Bruce Ashfield
2025-02-12 17:24         ` Stefan Herbrechtsmeier
2025-02-12 17:45           ` Bruce Ashfield
2025-02-12 17:52             ` Richard Purdie
2025-02-13 12:45             ` Stefan Herbrechtsmeier
2025-02-13 17:07               ` Bruce Ashfield
2025-02-11 15:00 ` [RFC PATCH 22/30] python3-cryptography: " Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 23/30] python3-maturin: " Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 24/30] python3-rpds-py: " Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 25/30] librsvg: " Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 26/30] librsvg: update dependecies to fix RUSTSEC-2024-0421 Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 27/30] [DO NOT MERGE] recipes: add crucible go demo Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 28/30] [DO NOT MERGE] recipes: add node-red npm demo Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 29/30] [DO NOT MERGE] recipes: add nucleoidai " Stefan Herbrechtsmeier
2025-02-11 15:00 ` [RFC PATCH 30/30] [DO NOT MERGE] classes: spdx: use version 2.2 Stefan Herbrechtsmeier
2025-02-11 23:14 ` [bitbake-devel] [RFC PATCH 00/30] Add vendor support for go, npm and rust Bruce Ashfield
2025-02-12  8:41   ` Stefan Herbrechtsmeier
2025-02-12 14:11     ` Bruce Ashfield
2025-02-13  8:36       ` Stefan Herbrechtsmeier
2025-02-13 17:01         ` Bruce Ashfield

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.