From b96ede28ba109b5fdeab78dfa1259246b4975a4f Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Mon, 30 Mar 2026 14:21:27 +0530 Subject: [PATCH 1/9] Added POC for Wrapper using Koffi --- .gitignore | 1 + .../wrappers/spannerlib-nodejs-poc/ipc/go.mod | 3 + .../spannerlib-nodejs-poc/ipc/package.json | 12 + .../spannerlib-nodejs-poc/koffi/README.md | 56 + .../spannerlib-nodejs-poc/koffi/index.js | 21 + .../koffi/package-lock.json | 2601 +++++++++++++++++ .../spannerlib-nodejs-poc/koffi/package.json | 19 + .../spannerlib-nodejs-poc/koffi/setup_db.js | 46 + .../koffi/src/ffi/bindings.js | 46 + .../koffi/src/ffi/utils.js | 74 + .../koffi/src/lib/connection.js | 87 + .../koffi/src/lib/pool.js | 80 + .../koffi/src/lib/rows.js | 72 + .../koffi/src/lib/spannerlib.js | 51 + .../spannerlib-nodejs-poc/koffi/test-db.txt | 1 + .../spannerlib-nodejs-poc/koffi/test.js | 58 + .../spannerlib-nodejs-poc/napi/package.json | 12 + 17 files changed, 3240 insertions(+) create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/go.mod create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package.json create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/README.md create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/index.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package-lock.json create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package.json create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/setup_db.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/bindings.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/utils.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/connection.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/pool.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/rows.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/spannerlib.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test-db.txt create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json diff --git a/.gitignore b/.gitignore index 8818a661..0c0f1c52 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ gorm/ .idea .DS_Store +node_modules diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/go.mod b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/go.mod new file mode 100644 index 00000000..e6a85e01 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/go.mod @@ -0,0 +1,3 @@ +module ipc-poc + +go 1.25.0 diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package.json b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package.json new file mode 100644 index 00000000..4e5cedba --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package.json @@ -0,0 +1,12 @@ +{ + "name": "ipc", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "" +} diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/README.md b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/README.md new file mode 100644 index 00000000..4c151b12 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/README.md @@ -0,0 +1,56 @@ +# Koffi POC for the Real Spanner Shared Library + +This directory contains a Proof of Concept (POC) demonstrating how to use [Koffi](https://koffi.dev/)—a fast and lightweight pure JavaScript Foreign Function Interface (FFI)—to interact **directly** with the compiled `go-sql-spanner` C-Shared Library. + +By using Koffi, we can bridge Node.js directly to the Go Driver without writing a single line of C/C++ intermediary code. + +## Step-by-Step Implementation + +### Step 1: Compile the Go Shared Library (`.so` / `.dylib`) +Instead of using a mock C file, this POC connects to the actual Go codebase. First, the Go code must be exportable as a C-compatible shared library. We achieved this by navigating to `spannerlib/shared` and running: +```bash +go build -buildmode=c-shared -o libspanner.so shared_lib.go +``` +*This produces `libspanner.so` (the compiled binary) and `libspanner.h` (the C-Header definitions of your exported Go functions).* + +### Step 2: Initialize Koffi in Node.js +We initialized an isolated npm workspace for the Koffi POC and installed the dependency: +```bash +npm install koffi +``` + +### Step 3: Map Go C-ABI Types to Koffi (`index.js`) +Go's CGO engine translates complex types into C-structs in `libspanner.h`. We used Koffi's `struct` mappings to perfectly mirror Go's memory layouts inside JavaScript: + +- **`GoString`**: Go handles C-strings as a struct containing a pointer and a length. + ```javascript + const GoString = koffi.struct('GoString', { p: 'string', n: 'size_t' }); + ``` +- **`GoSlice`**: Byte slices (used for passing protobuf payloads like SQL Statements) are mapped as: + ```javascript + const GoSlice = koffi.struct('GoSlice', { data: 'void*', len: 'int64', cap: 'int64' }); + ``` +- **`GoReturnTuple`**: Go functions that return multiple arguments (e.g., `(int64, int32, int64, int32, unsafe.Pointer)`) are compiled by CGO into a single unified C-struct. We mapped this 5-element struct directly in Koffi to easily extract `objectId`, `statusCode`, and `resPointer`. + +### Step 4: Define FFI Bindings +We pointed Koffi to `libspanner.so` and registered your exported Go functions natively: +```javascript +const CreatePool = lib.func('CreatePool', GoReturnTuple, [GoString, GoString]); +const Execute = lib.func('Execute', GoReturnTuple, ['int64', 'int64', GoSlice]); +``` + +### Step 5: Handling Responses & Extracting Memory (`resPointer`) +When the Go driver throws an error or returns protobuf data, it packs bytes into the `resPointer` (returned in `tuple.r4`) and the length in `tuple.r3`. We used Koffi to safely decode that raw memory straight into a Node.js `Buffer`: +```javascript +const bytesArray = koffi.decode(result.r4, 'uint8', result.r3); +const decodedMessage = Buffer.from(bytesArray).toString('utf8'); +``` +This allowed the JavaScript wrapper to natively throw the exact inner Go error: `Spanner Native Error (Code 3): Invalid CreateSession request.` + +### Step 6: Integration Test (`test.js`) +We provided a test script (`node test.js`) to demonstrate the binding. It initializes a Go Session Pool, requests a simulated FFI connection, fires an empty execute payload, and gracefully frees the Go pointer memory (`Release`). + +## Key Findings & Advantages +- **No C++ Toolchain (`node-gyp`) Required:** Koffi avoids the complexity of compiling N-API bindings. +- **Perfect Go Memory Introspection:** Koffi natively reads Go's internal `uint8` byte streams (`koffi.decode`), making Protobuf decoding exceptionally fast and seamless. +- **Idiomatic Result Handling:** By mapping Go's C-Tuple returns, the JavaScript developer sees a standard Object-Oriented client interface (`client.createPool(...)`) while Koffi handles all the strict struct-bridging to Go underneath. diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/index.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/index.js new file mode 100644 index 00000000..bdd907de --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/index.js @@ -0,0 +1,21 @@ +const { spannerLib } = require('./src/lib/spannerlib.js'); +const { Pool } = require('./src/lib/pool.js'); +const { Connection } = require('./src/lib/connection.js'); +const { Rows } = require('./src/lib/rows.js'); +const { SpannerLibError } = require('./src/ffi/utils.js'); + +/** + * Cleanup function to force release of all trapped Go CGO pinners + * when the application shuts down. + */ +function cleanup() { + spannerLib.releaseAll(); +} + +module.exports = { + Pool, + Connection, + Rows, + SpannerLibError, + cleanup +}; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package-lock.json b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package-lock.json new file mode 100644 index 00000000..dd89d01f --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package-lock.json @@ -0,0 +1,2601 @@ +{ + "name": "koffi", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "koffi", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@google-cloud/spanner": "^8.6.0", + "koffi": "^2.15.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.7.tgz", + "integrity": "sha512-BU2f9tlKQ5CAthiMIgpzAh4eDTLWo1mqi9jqE2OxMG0E/OM199VJt2q8BztTxpnSW0i1ymdwLXRJnYzvDM5r2w==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.27.7", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.7", + "@babel/types": "^7.27.7", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports/node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.7.tgz", + "integrity": "sha512-X6ZlfR/O/s5EQ/SnUSLzr+6kGnkg8HXGMzpgsMsrJVcfDtH1vIp6ctCN4eZ1LS5c0+te5Cb6Y514fASjMRJ1nw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.5", + "@babel/parser": "^7.27.7", + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.7", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@google-cloud/common": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-6.0.0.tgz", + "integrity": "sha512-IXh04DlkLMxWgYLIUYuHHKXKOUwPDzDgke1ykkkJPe48cGIS9kkL2U/o0pm4ankHLlvzLF/ma1eO86n/bkumIA==", + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "^4.0.0", + "arrify": "^2.0.0", + "duplexify": "^4.1.3", + "extend": "^3.0.2", + "google-auth-library": "^10.0.0-rc.1", + "html-entities": "^2.5.2", + "retry-request": "^8.0.0", + "teeny-request": "^10.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/common/node_modules/@google-cloud/projectify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", + "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/common/node_modules/@google-cloud/promisify": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.1.0.tgz", + "integrity": "sha512-G/FQx5cE/+DqBbOpA5jKsegGwdPniU6PuIEMt+qxWgFxvxuFOzVmp6zYchtYuwAWV5/8Dgs0yAmjvNZv3uXLQg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/monitoring": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@google-cloud/monitoring/-/monitoring-5.3.1.tgz", + "integrity": "sha512-f88LJn4PrzhiDaK0VH5KPxEXZfzJ7X8AGfYnK3KTfZEfH3cyxlvCnpgQQaScNTPhv+zX2MrdW/lJHDOpLsm71Q==", + "license": "Apache-2.0", + "dependencies": { + "google-gax": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/opentelemetry-resource-util": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@google-cloud/opentelemetry-resource-util/-/opentelemetry-resource-util-2.4.0.tgz", + "integrity": "sha512-/7ujlMoKtDtrbQlJihCjQnm31n2s2RTlvJqcSbt2jV3OkCzPAdo3u31Q13HNugqtIRUSk7bUoLx6AzhURkhW4w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.22.0", + "gcp-metadata": "^6.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/resources": "^1.0.0" + } + }, + "node_modules/@google-cloud/precise-date": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-5.0.0.tgz", + "integrity": "sha512-9h0Gvw92EvPdE8AK8AgZPbMnH5ftDyPtKm7/KUfcJVaPEPjwGDsJd1QV0H8esBDV4II41R/2lDWH1epBqIoKUw==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/projectify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-5.0.0.tgz", + "integrity": "sha512-XXQLaIcLrOAMWvRrzz+mlUGtN6vlVNja3XQbMqRi/V7XJTAVwib3VcKd7oRwyZPkp7rBVlHGcaqdyGRrcnkhlA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-5.0.0.tgz", + "integrity": "sha512-N8qS6dlORGHwk7WjGXKOSsLjIjNINCPicsOX6gyyLiYk7mq3MtII96NZ9N2ahwA2vnkLmZODOIH9rlNniYWvCQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@google-cloud/spanner": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@google-cloud/spanner/-/spanner-8.6.0.tgz", + "integrity": "sha512-ed7nQgNXj1Tjrvwwc1MmeMFBfmU5mdxVtJw+gQI+ic0rvHf0BHZ9dlz+cvxgZEOC/Uy7/Gv/00zpoIrQ2i6DCg==", + "license": "Apache-2.0", + "dependencies": { + "@babel/core": "7.27.7", + "@babel/helpers": "7.27.6", + "@babel/traverse": "7.27.7", + "@google-cloud/common": "^6.0.0", + "@google-cloud/monitoring": "^5.0.0", + "@google-cloud/opentelemetry-resource-util": "^2.4.0", + "@google-cloud/precise-date": "^5.0.0", + "@google-cloud/projectify": "^5.0.0", + "@google-cloud/promisify": "^5.0.0", + "@grpc/grpc-js": "^1.13.2", + "@grpc/proto-loader": "^0.8.0", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^2.0.0", + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^1.8.0", + "@opentelemetry/sdk-metrics": "^1.30.1", + "@opentelemetry/semantic-conventions": "^1.30.0", + "@types/big.js": "^6.2.2", + "@types/stack-trace": "^0.0.33", + "big.js": "^7.0.0", + "checkpoint-stream": "^0.1.2", + "duplexify": "^4.1.3", + "events-intercept": "^2.0.0", + "extend": "^3.0.2", + "google-auth-library": "^10.0.0-rc.1", + "google-gax": "5.0.6", + "grpc-gcp": "^1.0.1", + "lodash.snakecase": "^4.1.1", + "merge-stream": "^2.0.0", + "p-queue": "^6.0.2", + "protobufjs": "^7.4.0", + "retry-request": "^8.0.0", + "split-array-stream": "^2.0.0", + "stack-trace": "0.0.10", + "stream-events": "^1.0.5", + "teeny-request": "^10.0.0", + "through2": "^4.0.2", + "uuid": "^11.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", + "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", + "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.3", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.6.0.tgz", + "integrity": "sha512-L8UyDwqpTcbkIK5cgwDRDYDoEhQoj8wp8BwsO19w3LB1Z41yEQm2VJyNfAi9DrLP/YTqXqWpKHyZfR9/tFYo1Q==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.0.tgz", + "integrity": "sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.30.1.tgz", + "integrity": "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", + "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.30.1.tgz", + "integrity": "sha512-q9zcZ0Okl8jRgmy7eNW3Ku1XSgg3sDLa5evHZpCwjspw7E8Is4K/haRPDJrBcX3YSn/Y7gUvFnByNYEKQNbNog==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/resources": "1.30.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/core": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", + "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", + "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "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==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@types/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-e2cOW9YlVzFY2iScnGBBkplKsrn2CsObHQ2Hiw4V1sSyiGbgWL8IyqE3zFi1Pt5o1pdAtYkDAIsF3KKUPjdzaA==", + "license": "MIT" + }, + "node_modules/@types/duplexify": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.5.tgz", + "integrity": "sha512-fB56ACzlW91UdZ5F3VXplVMDngO8QaX5Y2mjvADtN01TT2TMy4WjF0Lg+tFDvt4uMBeTe4SgaD+qCrA7dL5/tA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/pumpify": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/pumpify/-/pumpify-1.4.5.tgz", + "integrity": "sha512-BGVAQyK5yJdfIII230fVYGY47V63hUNAhryuuS3b4lEN2LNwxUXFKsEf8QLDCjmZuimlj23BHppJgcrGvNtqKg==", + "license": "MIT", + "dependencies": { + "@types/duplexify": "*", + "@types/node": "*" + } + }, + "node_modules/@types/stack-trace": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.33.tgz", + "integrity": "sha512-O7in6531Bbvlb2KEsJ0dq0CHZvc3iWSR5ZYMtvGgnHA56VgriAN/AU2LorfmcvAl2xc9N5fbCTRyMRRl8nd74g==", + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.10", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz", + "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/big.js": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-7.0.1.tgz", + "integrity": "sha512-iFgV784tD8kq4ccF1xtNMZnXeZzVuXWWM+ERFzKQjv+A5G9HC8CY3DuV45vgzFFcW+u2tIvmF95+AzWgs6BjCg==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001781", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", + "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/checkpoint-stream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/checkpoint-stream/-/checkpoint-stream-0.1.2.tgz", + "integrity": "sha512-eYXIcydL3mPjjEVLxHdi1ISgTwmxGJZ8vyJ3lYVvFTDRyTOZMTbKZdRJqiA7Gi1rPcwOyyzcrZmGLL8ff7e69w==", + "license": "MIT", + "dependencies": { + "@types/pumpify": "^1.4.1", + "events-intercept": "^2.0.0", + "pumpify": "^1.3.5", + "split-array-stream": "^1.0.0", + "through2": "^2.0.3" + } + }, + "node_modules/checkpoint-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/checkpoint-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/checkpoint-stream/node_modules/split-array-stream": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/split-array-stream/-/split-array-stream-1.0.3.tgz", + "integrity": "sha512-yGY35QmZFzZkWZ0eHE06RPBi63umym8m+pdtuC/dlO1ADhdKSfCj0uNn87BYCXBBDFxyTq4oTw0BgLYT0K5z/A==", + "license": "MIT", + "dependencies": { + "async": "^2.4.0", + "is-stream-ended": "^0.1.0" + } + }, + "node_modules/checkpoint-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/checkpoint-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=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==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.323", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.323.tgz", + "integrity": "sha512-oQm+FxbazvN2WICCbvJgj3IYPKV8awip57+W5VP+Aatk4kFU4pDYCPHZOX22Z27zpw8uttBehEqgK+VTJAYrVw==", + "license": "ISC" + }, + "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==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/events-intercept": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/events-intercept/-/events-intercept-2.0.0.tgz", + "integrity": "sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/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" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/google-auth-library": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", + "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/gaxios": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", + "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/google-auth-library/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/google-gax": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-5.0.6.tgz", + "integrity": "sha512-1kGbqVQBZPAAu4+/R1XxPQKP0ydbNYoLAr4l0ZO2bMV0kLyLW4I1gAk++qBLWt7DPORTzmWRMsCZe86gDjShJA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.12.6", + "@grpc/proto-loader": "^0.8.0", + "duplexify": "^4.1.3", + "google-auth-library": "^10.1.0", + "google-logging-utils": "^1.1.1", + "node-fetch": "^3.3.2", + "object-hash": "^3.0.0", + "proto3-json-serializer": "^3.0.0", + "protobufjs": "^7.5.3", + "retry-request": "^8.0.0", + "rimraf": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-gax/node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/google-gax/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/grpc-gcp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/grpc-gcp/-/grpc-gcp-1.0.1.tgz", + "integrity": "sha512-06r73IoGaAIpzT+DRPnw7V5BXvZ5mjy1OcKqSPX+ZHOgbLxT+lJfz8IN83z/sbA3t55ZX88MfDaaCjDGdveVIA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", + "license": "MIT" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/koffi": { + "version": "2.15.2", + "resolved": "https://registry.npmjs.org/koffi/-/koffi-2.15.2.tgz", + "integrity": "sha512-r9tjJLVRSOhCRWdVyQlF3/Ugzeg13jlzS4czS82MAgLff4W+BcYOW7g8Y62t9O5JYjYOLAjAovAZDNlDfZNu+g==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "license": "MIT" + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "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==", + "license": "MIT" + }, + "node_modules/proto3-json-serializer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-3.0.4.tgz", + "integrity": "sha512-E1sbAYg3aEbXrq0n1ojJkRHQJGE1kaE/O6GLA94y8rnJBfgvOPTOd1b9hOceQK1FFZI9qMh1vBERCyO2ifubcw==", + "license": "Apache-2.0", + "dependencies": { + "protobufjs": "^7.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/protobufjs": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/pumpify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/pumpify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/pumpify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/retry-request": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-8.0.2.tgz", + "integrity": "sha512-JzFPAfklk1kjR1w76f0QOIhoDkNkSqW8wYKT08n9yysTmZfB+RQ2QoXoTAeOi1HD9ZipTyTAZg3c4pM/jeqgSw==", + "license": "MIT", + "dependencies": { + "extend": "^3.0.2", + "teeny-request": "^10.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/split-array-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/split-array-stream/-/split-array-stream-2.0.0.tgz", + "integrity": "sha512-hmMswlVY91WvGMxs0k8MRgq8zb2mSen4FmDNc5AFiTWtrBpdZN6nwD6kROVe4vNL+ywrvbCKsWVCnEd4riELIg==", + "license": "MIT", + "dependencies": { + "is-stream-ended": "^0.1.4" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "license": "MIT", + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", + "license": "MIT" + }, + "node_modules/teeny-request": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-10.1.2.tgz", + "integrity": "sha512-Xj0ZAQ0CeuQn6UxCDPLbFRlgcSTUEyO3+wiepr2grjIjyL/lMMs1Z4OwXn8kLvn/V1OuaEP0UY7Na6UDNNsYrQ==", + "license": "Apache-2.0", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2", + "stream-events": "^1.0.5" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/teeny-request/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/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==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/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==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package.json b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package.json new file mode 100644 index 00000000..93eb6ab8 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package.json @@ -0,0 +1,19 @@ +{ + "name": "koffi", + "version": "1.0.0", + "main": "index.js", + "engines": { + "node": ">=20.0.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@google-cloud/spanner": "^8.6.0", + "koffi": "^2.15.2" + } +} diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/setup_db.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/setup_db.js new file mode 100644 index 00000000..14d1321a --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/setup_db.js @@ -0,0 +1,46 @@ +const { Spanner } = require('@google-cloud/spanner'); + +const projectId = 'span-cloud-testing'; +const instanceId = 'gargsurbhi-testing'; +const databaseId = `test-db-koffi-${Math.floor(Math.random() * 1000)}`; + +const spanner = new Spanner({ projectId }); +const instance = spanner.instance(instanceId); + +async function setupDatabase() { + console.log(`Setting up Spanner Database: ${databaseId}...`); + try { + const [database, operation] = await instance.createDatabase(databaseId, { + schema: [ + `CREATE TABLE Singers ( + SingerId INT64 NOT NULL, + FirstName STRING(1024), + LastName STRING(1024), + IsActive BOOL, + Balance FLOAT64 + ) PRIMARY KEY (SingerId)` + ], + }); + + console.log(`Database creation initiated. Waiting for operation...`); + await operation.promise(); + console.log(`Database ${database.id} created with Schema.`); + + console.log('Inserting dummy data...'); + const table = database.table('Singers'); + await table.insert([ + { SingerId: 1, FirstName: 'Marc', LastName: 'Richards', IsActive: true, Balance: 100.50 }, + { SingerId: 2, FirstName: 'Catalina', LastName: 'Smith', IsActive: false, Balance: 250.75 }, + { SingerId: 3, FirstName: 'Alice', LastName: 'Trentor', IsActive: true, Balance: 0.10 } + ]); + console.log('Dummy data inserted successfully!'); + + // Save DB name to file so the test can pick it up + require('fs').writeFileSync('./test-db.txt', databaseId); + + } catch (err) { + console.error('ERROR:', err); + } +} + +setupDatabase().catch(console.error); diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/bindings.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/bindings.js new file mode 100644 index 00000000..f0e5a656 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/bindings.js @@ -0,0 +1,46 @@ +const koffi = require('koffi'); +const path = require('path'); + +// Dynamically locate the actual compiled Go shared library +const libPath = path.resolve(__dirname, '../../../../../shared/libspanner.so'); +const lib = koffi.load(libPath); + +// --- Define C-ABI Go Types --- +const GoString = koffi.struct('GoString', { + p: 'string', // Maps to const char* + n: 'size_t' // Maps to ptrdiff_t +}); + +const GoSlice = koffi.struct('GoSlice', { + data: 'void*', + len: 'int64', + cap: 'int64' +}); + +const GoReturnTuple = koffi.struct('GoReturnTuple', { + r0: 'int64', // pinnerId + r1: 'int32', // statusCode + r2: 'int64', // objectId + r3: 'int32', // length + r4: 'void*' // resPointer +}); + +// --- Function Bindings --- +module.exports = { + koffi, + lib, + types: { + GoString, + GoSlice, + GoReturnTuple + }, + // FFI Native Functions + CreatePool: lib.func('CreatePool', GoReturnTuple, [GoString, GoString]), + ClosePool: lib.func('ClosePool', GoReturnTuple, ['int64']), + CreateConnection: lib.func('CreateConnection', GoReturnTuple, ['int64']), + CloseConnection: lib.func('CloseConnection', GoReturnTuple, ['int64', 'int64']), + Execute: lib.func('Execute', GoReturnTuple, ['int64', 'int64', GoSlice]), + Next: lib.func('Next', GoReturnTuple, ['int64', 'int64', 'int64', 'int32', 'int32']), + CloseRows: lib.func('CloseRows', GoReturnTuple, ['int64', 'int64', 'int64']), + Release: lib.func('Release', 'int32', ['int64']) +}; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/utils.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/utils.js new file mode 100644 index 00000000..ed72b80a --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/utils.js @@ -0,0 +1,74 @@ +const { koffi } = require('./bindings.js'); + +class SpannerLibError extends Error { + constructor(code, message) { + super(`Spanner Native Error (Code ${code}): ${message}`); + this.code = code; + this.name = 'SpannerLibError'; + } +} + +function toGoString(str) { + if (!str) return { p: null, n: 0 }; + return { p: str, n: Buffer.byteLength(str, 'utf8') }; +} + +function toGoSlice(bufOrStr) { + const buf = Buffer.isBuffer(bufOrStr) ? bufOrStr : Buffer.from(bufOrStr, 'utf8'); + return { data: buf, len: buf.length, cap: buf.length }; +} + +/** + * Validates the raw Go Return Tuple and safely decodes `resPointer` Protobuf bytes. + * Throws wrapped JavaScript Errors smoothly cleanly. + */ +function handleGoResult(result, refInstance, pinManager) { + // 1. Use FinalizationRegistry to register Go Memory bound to this JS Object! + if (result && result.r0 > 0 && pinManager && refInstance) { + pinManager.register(refInstance, result.r0); + refInstance.pinnerId = result.r0; // Store it safely on the object it belongs to + } + + let msg = "Unknown protobuf payload"; + let decodedBytes = Buffer.alloc(0); + + // We expect r4 to contain the protobuf response. + if (result && result.r4 !== null && result.r3 > 0) { + decodedBytes = Buffer.from(koffi.decode(result.r4, 'uint8', result.r3)); + msg = decodedBytes.toString('utf8'); + } + + if (result && result.r1 !== 0) { + throw new SpannerLibError(result.r1, msg); + } + + // Returns objectId (r2) and the raw binary (Protobuf) + return { objectId: result.r2, protobufBytes: decodedBytes, message: msg }; +} + +/** + * Promisifies asynchronous Koffi executions to prevent Node.js main thread blocking. + */ +function invokeAsync(koffiFunc, refInstance, pinManager, ...args) { + return new Promise((resolve, reject) => { + // Execute Koffi FFI on a background libuv thread natively. + koffiFunc.async(...args, (err, resultTuple) => { + if (err) { + return reject(err); + } + try { + // Now safely process the FFI response and register it for memory tracking + resolve(handleGoResult(resultTuple, refInstance, pinManager)); + } catch (goError) { + reject(goError); + } + }); + }); +} + +module.exports = { + SpannerLibError, + toGoString, + toGoSlice, + invokeAsync +}; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/connection.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/connection.js new file mode 100644 index 00000000..a7e4955a --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/connection.js @@ -0,0 +1,87 @@ +const { CreateConnection, CloseConnection, Execute } = require('../ffi/bindings.js'); +const { toGoSlice, invokeAsync } = require('../ffi/utils.js'); +const { spannerLib } = require('./spannerlib.js'); +const { Rows } = require('./rows.js'); +const { spanner_v1 } = require('@google-cloud/spanner/build/protos/protos.js'); + +class Connection { + /** + * @param {import('./pool.js').Pool} pool + */ + static async create(pool) { + const c = new Connection(); + c.pool = pool; + + const handled = await invokeAsync( + CreateConnection, + c, // Self reference for GC memory watcher + spannerLib, // Watcher + pool.oid + ); + + c.oid = handled.objectId; + return c; + } + + constructor() { + this.pool = null; + + /** + * The Object ID (OID). + * The global identifier for this specific Connection inside the Go engine. + * @type {Number|null} + */ + this.oid = null; + + /** + * The Memory Pinner ID. + * The exact GC lock holding this Connection's memory intact in Go. + * We pass this to native `Release()` via the Registry to stop leaks. + * @type {Number|null} + */ + this.pinnerId = null; + + this.closed = false; + } + + /** + * Natively executes a SQL query on Node's background LibUV thread while V8 proceeds! + * Integrates raw JS Protobuf definitions (from @google-cloud/spanner package). + */ + async executeSql(sqlString) { + if (this.closed) throw new Error("Connection is already closed"); + + const requestObj = { sql: sqlString, session: "poc/dummy" }; + const { google } = require('@google-cloud/spanner/build/protos/protos.js'); + const ExecuteSqlRequestProto = google.spanner.v1.ExecuteSqlRequest; + const serializedPb = ExecuteSqlRequestProto.encode(requestObj).finish(); + + // 2. Transmit the standard protobuf binary buffer over CGO FFI seamlessly + const handled = await invokeAsync( + Execute, + null, // Rows gets constructed afterward + null, + this.pool.oid, + this.oid, + toGoSlice(serializedPb) + ); + + return new Rows(this, handled.objectId); + } + + /** + * Release the connection back to the pool asynchronously + */ + async close() { + if (!this.closed) { + this.closed = true; + try { + await invokeAsync(CloseConnection, this, spannerLib, this.pool.oid, this.oid); + } finally { + spannerLib.unregister(this, this.pinnerId); + } + } + } +} + +module.exports = { Connection }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/pool.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/pool.js new file mode 100644 index 00000000..57114b91 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/pool.js @@ -0,0 +1,80 @@ +const { CreatePool, ClosePool } = require('../ffi/bindings.js'); +const { toGoString, invokeAsync } = require('../ffi/utils.js'); +const { spannerLib } = require('./spannerlib.js'); +const { Connection } = require('./connection.js'); + +class Pool { + /** + * Initializes a Pool object by invoking the underlying CGO `CreatePool`. + * Because FFI async spans the Go initialization process, we use `static async create` + * to safely handle promises natively inside JS. + */ + static async create(userAgent, connectionString) { + const p = new Pool(); + const handled = await invokeAsync( + CreatePool, + p, // Ref instance for memory registry + spannerLib,// Our Memory manager + toGoString(userAgent), + toGoString(connectionString) + ); + + p.oid = handled.objectId; + return p; + } + + constructor() { + /** + * The Object ID (OID). + * This is a unique identifier generated by the underlying Go Spanner driver + * to represent this specific Pool instance in its internal state map. + * We pass this OID back to Go when we execute operations (like executeSql) + * so Go knows which active Pool/Connection instance to use. + * @type {Number|null} + */ + this.oid = null; + + /** + * The Memory Pinner ID. + * Because Go Garbage Collection might move or delete objects currently + * being used by Node.js over FFI, Go "pins" the memory in place and + * returns a Pinner ID. We must explicitly invoke Go's `Release(pinnerId)` + * when this object is closed to prevent CGO memory leaks. + * @type {Number|null} + */ + this.pinnerId = null; + + /** + * State flag tracking whether this Pool has been explicitly closed. + * @type {Boolean} + */ + this.closed = false; + } + + /** + * Creates or borrows a new Connection within this Pool asynchronously. + * @returns {Promise} + */ + async createConnection() { + if (this.closed) throw new Error("Pool is already closed"); + return await Connection.create(this); + } + + /** + * Closes the underlying Go Spanner pool and explicitly drops memory pinned on Go's end. + */ + async close() { + if (!this.closed) { + this.closed = true; + try { + // Background execution of close logic + await invokeAsync(ClosePool, this, spannerLib, this.oid); + } finally { + // Explicitly unregister from the GC watcher, guaranteeing immediate cleanup + spannerLib.unregister(this, this.pinnerId); + } + } + } +} + +module.exports = { Pool }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/rows.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/rows.js new file mode 100644 index 00000000..9d0f089d --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/rows.js @@ -0,0 +1,72 @@ +const { CloseRows, Next } = require('../ffi/bindings.js'); +const { invokeAsync } = require('../ffi/utils.js'); +const { spannerLib } = require('./spannerlib.js'); +const { google } = require('@google-cloud/spanner/build/protos/protos.js'); + +class Rows { + /** + * @param {import('./connection.js').Connection} conn + * @param {Number} objectId - The OID identifying these rows inside the Go Driver + */ + constructor(conn, objectId) { + this.conn = conn; + + /** + * The Object ID (OID). + * Used to execute operations like `.next()` against THIS specific ResultSet inside Go. + * @type {Number|null} + */ + this.oid = objectId; + + this.closed = false; + + // FinalizationRegistry could optionally be mapped to this via + // spannerLib.register(this, pinnerId_from_execute) + // For the POC, we won't fully map the Rows Pinner unless needed + // by the Next() function iterator. + } + + /** + * Iterates to the next result chunk. + * In a full implementation, it would call `Next(poolId, connId, rowsId, ...)` natively. + */ + async next() { + if (this.closed) throw new Error("Rows object is already closed"); + + // Go Signature: Next(poolId, connId, rowsId, numRows, encodeRowOption) + // We pass 1 for numRows, and 0 for encodeRowOption as per POC defaults + const handled = await invokeAsync(Next, null, null, this.conn.pool.oid, this.conn.oid, this.oid, 1, 0); + + // Handle EOF case (The chunk buffer is perfectly empty or contains no message) + if (!handled.protobufBytes || handled.protobufBytes.length === 0) { + return null; // Signals end of rows to the caller + } + + // The returned message contains a google.protobuf.ListValue according to the spec! + // We natively unpack those bytes matching standard Protobuf conventions. + const listValueProto = google.protobuf.ListValue; + const decodedList = listValueProto.decode(handled.protobufBytes); + + // This converts the complex generic Protobuf ListValue deeply into native Javascript! + const jsonRecord = listValueProto.toObject(decodedList, { + longs: String, // Ensure Int64 types from Spanner decode as Strings instead of mangled JS doubles + enums: String, + bytes: String, + }); + + return jsonRecord.values || []; + } + + /** + * Closes the rows object safely, waiting on the network. + */ + async close() { + if (!this.closed) { + this.closed = true; + // Native FFI execution in the background + await invokeAsync(CloseRows, null, spannerLib, this.conn.pool.oid, this.conn.oid, this.oid); + } + } +} + +module.exports = { Rows }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/spannerlib.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/spannerlib.js new file mode 100644 index 00000000..810a696b --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/spannerlib.js @@ -0,0 +1,51 @@ +const { Release } = require('../ffi/bindings.js'); + +class SpannerLib { + constructor() { + this.activePinners = new Set(); + + // FinalizationRegistry automatically guarantees that V8 Garbage Collection + // dropping an object triggers this callback, where we gracefully + // wipe the matching Go pointer from memory via `Release(id)`. + this.registry = new FinalizationRegistry((pinnerId) => { + if (pinnerId && pinnerId > 0) { + Release(pinnerId); + this.activePinners.delete(pinnerId); + } + }); + } + + /** + * Registers a JavaScript object with this Memory Tracker. + * When JS garbage collects `refInstance`, `pinnerId` is automatically natively released. + */ + register(refInstance, pinnerId) { + if (pinnerId > 0) { + this.activePinners.add(pinnerId); + this.registry.register(refInstance, pinnerId, refInstance); + } + } + + unregister(refInstance, pinnerId) { + if (pinnerId > 0) { + Release(pinnerId); + this.registry.unregister(refInstance); + this.activePinners.delete(pinnerId); + } + } + + /** + * Fallback shutdown function to crash-stop everything not collected yet. + */ + releaseAll() { + for (const pinnerId of this.activePinners) { + Release(pinnerId); + } + this.activePinners.clear(); + } +} + +// Global Singleton +const spannerLib = new SpannerLib(); + +module.exports = { spannerLib }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test-db.txt b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test-db.txt new file mode 100644 index 00000000..89c9bdd6 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test-db.txt @@ -0,0 +1 @@ +test-db-koffi-136 \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test.js new file mode 100644 index 00000000..62de5264 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test.js @@ -0,0 +1,58 @@ +const { Pool, cleanup } = require('./index.js'); +const { performance } = require('perf_hooks'); +const fs = require('fs'); + +async function runTest() { + console.log("=================================================="); + console.log(" Spanner Shared Library POC (PRODUCTION ASYNC) "); + console.log("==================================================\n"); + + let pool, connection, rows; + + // Read the database name created by setup_db.js + let dbName = "dummy-testing-db"; + try { + dbName = fs.readFileSync('./test-db.txt', 'utf8').trim(); + } catch (e) { } + + const dbPath = `projects/span-cloud-testing/instances/gargsurbhi-testing/databases/${dbName}`; + + try { + console.log(`[JS-App] 1. Creating Pool attached to: \n -> ${dbPath}`); + pool = await Pool.create("nodejs-koffi-poc", dbPath); + console.log(`Pool created: OID ${pool.oid}`); + + console.log("\n[JS-App] 2. Creating Database Connection..."); + connection = await pool.createConnection(); + console.log(`Connection created: OID ${connection.oid}`); + + console.log("\n[JS-App] 3. Executing SQL using pure Nodejs @google-cloud/spanner Protobufs..."); + const sqlQuery = "SELECT SingerId, FirstName, Balance, IsActive FROM Singers"; + console.log(` -> Serializing FFI payload for: "${sqlQuery}"`); + + const startTime = performance.now(); + rows = await connection.executeSql(sqlQuery); + console.log(`Executed SQL successfully in ${(performance.now() - startTime).toFixed(3)}ms (Rows OID: ${rows.oid})`); + + console.log("\n[JS-App] 4. Fetching ResultSet Native Types (Int, String, Float, Bool)..."); + let nextRow; + while ((nextRow = await rows.next()) !== null) { + // nextRow is an array of Value protobuf objects (Google Protobuf Structs) + console.log(" - Fetched native row chunk ->"); + console.log(" " + JSON.stringify(nextRow)); + } + + } catch (err) { + console.error("Test execution caught an expected Native Error:"); + console.error(" -> " + err.message); + } finally { + console.log("\n[JS-App] 5. Graceful Async Cleanup..."); + if (rows) await rows.close(); + if (connection) await connection.close(); + if (pool) await pool.close(); + cleanup(); + console.log("Cleaned up gracefully."); + } +} + +runTest().catch(console.error); diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json new file mode 100644 index 00000000..46cd6f40 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json @@ -0,0 +1,12 @@ +{ + "name": "napi", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "" +} From e8981a129868c16e84a4c064d8b4bb5b9b105661 Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Mon, 6 Apr 2026 14:16:55 +0530 Subject: [PATCH 2/9] NAPI implementation --- .gitignore | 1 + .../spannerlib-nodejs-poc/napi/binding.gyp | 45 + .../spannerlib-nodejs-poc/napi/build/Makefile | 352 ++++ .../build/Release/.deps/Release/nothing.a.d | 1 + .../obj.target/spanner_napi/src/cpp/addon.o.d | 19 + .../Release/.deps/Release/spanner_napi.node.d | 1 + .../napi/build/Release/nothing.a | Bin 0 -> 984 bytes .../obj.target/spanner_napi/src/cpp/addon.o | Bin 0 -> 447392 bytes .../napi/build/Release/spanner_napi.node | Bin 0 -> 103584 bytes .../napi/build/binding.Makefile | 6 + .../napi/build/config.gypi | 506 +++++ .../napi/build/gyp-mac-tool | 766 ++++++++ .../napi/build/spanner_napi.target.mk | 195 ++ .../spannerlib-nodejs-poc/napi/index.js | 21 + .../napi/package-lock.json | 1675 +++++++++++++++++ .../spannerlib-nodejs-poc/napi/package.json | 18 +- .../spannerlib-nodejs-poc/napi/setup_db.js | 46 + .../napi/src/cpp/addon.cc | 294 +++ .../napi/src/ffi/bindings.js | 14 + .../napi/src/ffi/utils.js | 48 + .../napi/src/lib/connection.js | 87 + .../napi/src/lib/pool.js | 80 + .../napi/src/lib/rows.js | 72 + .../napi/src/lib/spannerlib.js | 51 + .../spannerlib-nodejs-poc/napi/test-db.txt | 1 + .../spannerlib-nodejs-poc/napi/test.js | 58 + 26 files changed, 4351 insertions(+), 6 deletions(-) create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Makefile create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/nothing.a.d create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/spanner_napi.node.d create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/nothing.a create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/obj.target/spanner_napi/src/cpp/addon.o create mode 100755 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/spanner_napi.node create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/binding.Makefile create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi create mode 100755 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/gyp-mac-tool create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/spanner_napi.target.mk create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/index.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/package-lock.json create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/setup_db.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/cpp/addon.cc create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/bindings.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/utils.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/connection.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/pool.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/rows.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/spannerlib.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/test-db.txt create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/test.js diff --git a/.gitignore b/.gitignore index 0c0f1c52..8769a30e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ gorm/ .idea .DS_Store node_modules +build/ \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp new file mode 100644 index 00000000..ad7f52bb --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp @@ -0,0 +1,45 @@ +{ + "targets": [ + { + "target_name": "spanner_napi", + "sources": [ "src/cpp/addon.cc" ], + "include_dirs": [ + "> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) -o $@ $< $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) -o $@ $< $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c + +quiet_cmd_objc = CXX($(TOOLSET)) $@ +cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< + +quiet_cmd_objcxx = CXX($(TOOLSET)) $@ +cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# Commands for precompiled header files. +quiet_cmd_pch_c = CXX($(TOOLSET)) $@ +cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ +cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_m = CXX($(TOOLSET)) $@ +cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< +quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ +cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# gyp-mac-tool is written next to the root Makefile by gyp. +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd +# already. +quiet_cmd_mac_tool = MACTOOL $(4) $< +cmd_mac_tool = /Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3 gyp-mac-tool $(4) $< "$@" + +quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ +cmd_mac_package_framework = /Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3 gyp-mac-tool package-framework "$@" $(4) + +quiet_cmd_infoplist = INFOPLIST $@ +cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@") + +quiet_cmd_symlink = SYMLINK $@ +cmd_symlink = ln -sf "$<" "$@" + +quiet_cmd_alink = LIBTOOL-STATIC $@ +cmd_alink = rm -f $@ && /Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3 gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 2,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,node_modules/node-addon-api/nothing.target.mk)))),) + include node_modules/node-addon-api/nothing.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,spanner_napi.target.mk)))),) + include spanner_napi.target.mk +endif + +quiet_cmd_regen_makefile = ACTION Regenerating $@ +cmd_regen_makefile = cd $(srcdir); /Users/gargsurbhi/.npm/_npx/c463d28440264a05/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1" "-Dnode_gyp_dir=/Users/gargsurbhi/.npm/_npx/c463d28440264a05/node_modules/node-gyp" "-Dnode_lib_file=/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi -I/Users/gargsurbhi/.npm/_npx/c463d28440264a05/node_modules/node-gyp/addon.gypi -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/common.gypi "--toplevel-dir=." binding.gyp +Makefile: $(srcdir)/../../../../../../../.npm/_npx/c463d28440264a05/node_modules/node-gyp/addon.gypi $(srcdir)/../../../../../../../Library/Caches/node-gyp/22.17.1/include/node/common.gypi $(srcdir)/binding.gyp $(srcdir)/build/config.gypi $(srcdir)/node_modules/node-addon-api/node_api.gyp + $(call do_cmd,regen_makefile) + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/nothing.a.d b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/nothing.a.d new file mode 100644 index 00000000..05726278 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/nothing.a.d @@ -0,0 +1 @@ +cmd_Release/nothing.a := rm -f Release/nothing.a && /Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3 gyp-mac-tool filter-libtool libtool -static -o Release/nothing.a Release/obj.target/nothing/node_modules/node-addon-api/nothing.o diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d new file mode 100644 index 00000000..b0f2800a --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d @@ -0,0 +1,19 @@ +cmd_Release/obj.target/spanner_napi/src/cpp/addon.o := c++ -o Release/obj.target/spanner_napi/src/cpp/addon.o ../src/cpp/addon.cc '-DNODE_GYP_MODULE_NAME=spanner_napi' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_FILE_OFFSET_BITS=64' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DBUILDING_NODE_EXTENSION' -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/src -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/openssl/config -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/openssl/openssl/include -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/uv/include -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/zlib -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/v8/include -I/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api -I../../../shared -O3 -gdwarf-2 -fno-strict-aliasing -mmacosx-version-min=10.15 -arch arm64 -Wall -Wendif-labels -W -Wno-unused-parameter -std=gnu++17 -stdlib=libc++ -fno-rtti -MMD -MF ./Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d.raw -c +Release/obj.target/spanner_napi/src/cpp/addon.o: ../src/cpp/addon.cc \ + /Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi.h \ + /Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/node_api.h \ + /Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/js_native_api.h \ + /Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/js_native_api_types.h \ + /Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/node_api_types.h \ + /Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi-inl.h \ + /Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi-inl.deprecated.h \ + ../src/cpp/../../../../../shared/libspanner.h +../src/cpp/addon.cc: +/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi.h: +/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/node_api.h: +/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/js_native_api.h: +/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/js_native_api_types.h: +/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/node_api_types.h: +/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi-inl.h: +/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi-inl.deprecated.h: +../src/cpp/../../../../../shared/libspanner.h: diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/spanner_napi.node.d b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/spanner_napi.node.d new file mode 100644 index 00000000..6b70bfb7 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/spanner_napi.node.d @@ -0,0 +1 @@ +cmd_Release/spanner_napi.node := c++ -bundle -Wl,-rpath,/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/../../../shared -undefined dynamic_lookup -Wl,-search_paths_first -mmacosx-version-min=10.15 -arch arm64 -L./Release -stdlib=libc++ -o Release/spanner_napi.node Release/obj.target/spanner_napi/src/cpp/addon.o Release/nothing.a /Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/../../../shared/libspanner.so diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/nothing.a b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/nothing.a new file mode 100644 index 0000000000000000000000000000000000000000..b0eec0554db93862fb8b47d5e29c57dd48e2bf09 GIT binary patch literal 984 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%0DE}g_&uaN7yy&V6_bN-~{ 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 literal 0 HcmV?d00001 diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/spanner_napi.node b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/spanner_napi.node new file mode 100755 index 0000000000000000000000000000000000000000..0cafbc86a0ff037aa34b864d516c035a48814698 GIT binary patch literal 103584 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 z z-6*Or&bCwReWabPw{mQ1nB9NZk8fDNlM?A9;xee@<1yHB5sxh@Guig*y3qsDm^k!E zR$|lbIf>1sXC!;9x}F@J0XtqLY{T0Uv{9oH8g1UGwxyyYBS~mTyMB$NEB}vr!yF&( z>6Zk}UzPB&N5?gKOiu8VG3>U?<)}3W>)Hn5RcX!}`MWkV&>8>tepKdb{mxCE*~ei3 zh@PL#o8rsY$H=Hl@7-E;oS)F?8bS5hOQd0RA3e=!-sMxL${!r?1^MeAqlF!l-3>FQ z8)j@b%(!ltoNk!$-7pinVJ3FNOzMWoj*;o^dCcyf$?WcV%I=8k<-1{Io*q$(><%>yJrF`YkQ*@-@QN+y60;`cl8sytDl(7 zu{3|4zD6{MSB2^}C61y_icF;O!&s4@7Oan7i;EdhLxi) zOhEF)$>NM|$xD81DTD1yvu}z*bzdl%Ig+eV3lPf~NGV1EVwUyVZZi-|cf28AQezLp z7ST3jN~AW<0b}lCR8*F%z;8^6QP<$tuBt{Y@mDUXT3)%RxMURPF{3Uo2^KG3G-^rt zh^l3!BdRL=_=&N~Q8FwoSu|>;^`mN48g2x)_HV2jQBhtviu)X+7A-F+EgCg)5HDG2vOFDS)h@$ zzR3Nk_xoqNM)vs5?MSw)Yq1nNKX4Q}FU{p6*w=Y{S6so>5eA%{}cq@2!4tcF#wS zjcoqx>|d7^_v*9gt}SbSbEE4g6N0~5mv{AJsmo`NNon%m^wW}a+Pxn(2Y$S2_N3AO z_WEz$yz8FMpN+l#t$r;xHNIE1{KijTD17F(BX^Ct?z#Ee+Y8dxam{zH;cGQClv!^}Pp1Kl0}d1AhA9H4o(dI@`Evm+zsS zFP2<(-b+^>zhn5PYwvj?<5hq8qqpsNe17?F|F*cv_2#Ru-sG4)KdE!=&b2px=dEYH zJN?e#Kl@MVr_#%B?mH;0ZORqDdG?a=zkG6R|CG5?dc8hu??0A4e9=FixavRE|7G%3 zSH3vy$~UL{dP?B3-Fd5T4No8Re&>8 zhIXTI;&>yOa1<|I(YGfHxIwP-<`GU=~Y*JuWp<8;SI0$9RAJQe(}wxKh6E= z>9h7dJbT9zZ#;POvcbn{T8~`x%G2LFyKZyYuKWLM<%_q3ub=(-MaM&@xBa%)(pPTE z?LBeb@Jkn@toy~RpD%6m?wz+FX?5y*c|S>>_|o)6rE6N&-reij>m0*6?tP-{s>wwu JoBt)m{{t}@_8R~I literal 0 HcmV?d00001 diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/binding.Makefile b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/binding.Makefile new file mode 100644 index 00000000..156660be --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/binding.Makefile @@ -0,0 +1,6 @@ +# This file is generated by gyp; do not edit. + +export builddir_name ?= ./build/. +.PHONY: all +all: + $(MAKE) spanner_napi diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi new file mode 100644 index 00000000..cf1a772d --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi @@ -0,0 +1,506 @@ +# Do not edit. File was generated by node-gyp's "configure" step +{ + "target_defaults": { + "cflags": [], + "configurations": { + "Debug": { + "v8_enable_v8_checks": 0, + "variables": {} + }, + "Release": { + "v8_enable_v8_checks": 1, + "variables": {} + } + }, + "default_configuration": "Release", + "defines": [], + "include_dirs": [], + "libraries": [], + "msvs_configuration_platform": "ARM64", + "xcode_configuration_platform": "arm64" + }, + "variables": { + "arm_fpu": "neon", + "asan": 0, + "clang": 1, + "control_flow_guard": "false", + "coverage": "false", + "dcheck_always_on": 0, + "debug_nghttp2": "false", + "debug_node": "false", + "enable_lto": "false", + "enable_pgo_generate": "false", + "enable_pgo_use": "false", + "error_on_warn": "false", + "force_dynamic_crt": 0, + "host_arch": "arm64", + "icu_data_in": "../../deps/icu-tmp/icudt77l.dat", + "icu_endianness": "l", + "icu_gyp_path": "tools/icu/icu-generic.gyp", + "icu_path": "deps/icu-small", + "icu_small": "false", + "icu_ver_major": "77", + "libdir": "lib", + "llvm_version": "16.0", + "napi_build_version": "10", + "node_builtin_shareable_builtins": [ + "deps/cjs-module-lexer/lexer.js", + "deps/cjs-module-lexer/dist/lexer.js", + "deps/undici/undici.js", + "deps/amaro/dist/index.js" + ], + "node_byteorder": "little", + "node_cctest_sources": [ + "src/node_snapshot_stub.cc", + "test/cctest/inspector/test_node_protocol.cc", + "test/cctest/node_test_fixture.cc", + "test/cctest/test_aliased_buffer.cc", + "test/cctest/test_base64.cc", + "test/cctest/test_base_object_ptr.cc", + "test/cctest/test_cppgc.cc", + "test/cctest/test_crypto_clienthello.cc", + "test/cctest/test_dataqueue.cc", + "test/cctest/test_environment.cc", + "test/cctest/test_inspector_socket.cc", + "test/cctest/test_inspector_socket_server.cc", + "test/cctest/test_json_utils.cc", + "test/cctest/test_linked_binding.cc", + "test/cctest/test_node_api.cc", + "test/cctest/test_node_crypto.cc", + "test/cctest/test_node_crypto_env.cc", + "test/cctest/test_node_postmortem_metadata.cc", + "test/cctest/test_node_task_runner.cc", + "test/cctest/test_path.cc", + "test/cctest/test_per_process.cc", + "test/cctest/test_platform.cc", + "test/cctest/test_quic_cid.cc", + "test/cctest/test_quic_error.cc", + "test/cctest/test_quic_tokens.cc", + "test/cctest/test_report.cc", + "test/cctest/test_sockaddr.cc", + "test/cctest/test_traced_value.cc", + "test/cctest/test_util.cc", + "test/cctest/node_test_fixture.h" + ], + "node_debug_lib": "false", + "node_enable_d8": "false", + "node_enable_v8_vtunejit": "false", + "node_fipsinstall": "false", + "node_install_corepack": "true", + "node_install_npm": "true", + "node_library_files": [ + "lib/_http_agent.js", + "lib/_http_client.js", + "lib/_http_common.js", + "lib/_http_incoming.js", + "lib/_http_outgoing.js", + "lib/_http_server.js", + "lib/_stream_duplex.js", + "lib/_stream_passthrough.js", + "lib/_stream_readable.js", + "lib/_stream_transform.js", + "lib/_stream_wrap.js", + "lib/_stream_writable.js", + "lib/_tls_common.js", + "lib/_tls_wrap.js", + "lib/assert.js", + "lib/assert/strict.js", + "lib/async_hooks.js", + "lib/buffer.js", + "lib/child_process.js", + "lib/cluster.js", + "lib/console.js", + "lib/constants.js", + "lib/crypto.js", + "lib/dgram.js", + "lib/diagnostics_channel.js", + "lib/dns.js", + "lib/dns/promises.js", + "lib/domain.js", + "lib/events.js", + "lib/fs.js", + "lib/fs/promises.js", + "lib/http.js", + "lib/http2.js", + "lib/https.js", + "lib/inspector.js", + "lib/inspector/promises.js", + "lib/internal/abort_controller.js", + "lib/internal/assert.js", + "lib/internal/assert/assertion_error.js", + "lib/internal/assert/calltracker.js", + "lib/internal/assert/myers_diff.js", + "lib/internal/assert/utils.js", + "lib/internal/async_context_frame.js", + "lib/internal/async_hooks.js", + "lib/internal/async_local_storage/async_context_frame.js", + "lib/internal/async_local_storage/async_hooks.js", + "lib/internal/blob.js", + "lib/internal/blocklist.js", + "lib/internal/bootstrap/node.js", + "lib/internal/bootstrap/realm.js", + "lib/internal/bootstrap/shadow_realm.js", + "lib/internal/bootstrap/switches/does_not_own_process_state.js", + "lib/internal/bootstrap/switches/does_own_process_state.js", + "lib/internal/bootstrap/switches/is_main_thread.js", + "lib/internal/bootstrap/switches/is_not_main_thread.js", + "lib/internal/bootstrap/web/exposed-wildcard.js", + "lib/internal/bootstrap/web/exposed-window-or-worker.js", + "lib/internal/buffer.js", + "lib/internal/child_process.js", + "lib/internal/child_process/serialization.js", + "lib/internal/cli_table.js", + "lib/internal/cluster/child.js", + "lib/internal/cluster/primary.js", + "lib/internal/cluster/round_robin_handle.js", + "lib/internal/cluster/shared_handle.js", + "lib/internal/cluster/utils.js", + "lib/internal/cluster/worker.js", + "lib/internal/console/constructor.js", + "lib/internal/console/global.js", + "lib/internal/constants.js", + "lib/internal/crypto/aes.js", + "lib/internal/crypto/certificate.js", + "lib/internal/crypto/cfrg.js", + "lib/internal/crypto/cipher.js", + "lib/internal/crypto/diffiehellman.js", + "lib/internal/crypto/ec.js", + "lib/internal/crypto/hash.js", + "lib/internal/crypto/hashnames.js", + "lib/internal/crypto/hkdf.js", + "lib/internal/crypto/keygen.js", + "lib/internal/crypto/keys.js", + "lib/internal/crypto/mac.js", + "lib/internal/crypto/pbkdf2.js", + "lib/internal/crypto/random.js", + "lib/internal/crypto/rsa.js", + "lib/internal/crypto/scrypt.js", + "lib/internal/crypto/sig.js", + "lib/internal/crypto/util.js", + "lib/internal/crypto/webcrypto.js", + "lib/internal/crypto/webidl.js", + "lib/internal/crypto/x509.js", + "lib/internal/data_url.js", + "lib/internal/debugger/inspect.js", + "lib/internal/debugger/inspect_client.js", + "lib/internal/debugger/inspect_repl.js", + "lib/internal/dgram.js", + "lib/internal/dns/callback_resolver.js", + "lib/internal/dns/promises.js", + "lib/internal/dns/utils.js", + "lib/internal/encoding.js", + "lib/internal/error_serdes.js", + "lib/internal/errors.js", + "lib/internal/event_target.js", + "lib/internal/events/abort_listener.js", + "lib/internal/events/symbols.js", + "lib/internal/file.js", + "lib/internal/fixed_queue.js", + "lib/internal/freelist.js", + "lib/internal/freeze_intrinsics.js", + "lib/internal/fs/cp/cp-sync.js", + "lib/internal/fs/cp/cp.js", + "lib/internal/fs/dir.js", + "lib/internal/fs/glob.js", + "lib/internal/fs/promises.js", + "lib/internal/fs/read/context.js", + "lib/internal/fs/recursive_watch.js", + "lib/internal/fs/rimraf.js", + "lib/internal/fs/streams.js", + "lib/internal/fs/sync_write_stream.js", + "lib/internal/fs/utils.js", + "lib/internal/fs/watchers.js", + "lib/internal/heap_utils.js", + "lib/internal/histogram.js", + "lib/internal/http.js", + "lib/internal/http2/compat.js", + "lib/internal/http2/core.js", + "lib/internal/http2/util.js", + "lib/internal/inspector/network.js", + "lib/internal/inspector/network_http.js", + "lib/internal/inspector/network_undici.js", + "lib/internal/inspector_async_hook.js", + "lib/internal/inspector_network_tracking.js", + "lib/internal/js_stream_socket.js", + "lib/internal/legacy/processbinding.js", + "lib/internal/linkedlist.js", + "lib/internal/main/check_syntax.js", + "lib/internal/main/embedding.js", + "lib/internal/main/eval_stdin.js", + "lib/internal/main/eval_string.js", + "lib/internal/main/inspect.js", + "lib/internal/main/mksnapshot.js", + "lib/internal/main/print_help.js", + "lib/internal/main/prof_process.js", + "lib/internal/main/repl.js", + "lib/internal/main/run_main_module.js", + "lib/internal/main/test_runner.js", + "lib/internal/main/watch_mode.js", + "lib/internal/main/worker_thread.js", + "lib/internal/mime.js", + "lib/internal/modules/cjs/loader.js", + "lib/internal/modules/customization_hooks.js", + "lib/internal/modules/esm/assert.js", + "lib/internal/modules/esm/create_dynamic_module.js", + "lib/internal/modules/esm/formats.js", + "lib/internal/modules/esm/get_format.js", + "lib/internal/modules/esm/hooks.js", + "lib/internal/modules/esm/initialize_import_meta.js", + "lib/internal/modules/esm/load.js", + "lib/internal/modules/esm/loader.js", + "lib/internal/modules/esm/module_job.js", + "lib/internal/modules/esm/module_map.js", + "lib/internal/modules/esm/resolve.js", + "lib/internal/modules/esm/shared_constants.js", + "lib/internal/modules/esm/translators.js", + "lib/internal/modules/esm/utils.js", + "lib/internal/modules/esm/worker.js", + "lib/internal/modules/helpers.js", + "lib/internal/modules/package_json_reader.js", + "lib/internal/modules/run_main.js", + "lib/internal/modules/typescript.js", + "lib/internal/navigator.js", + "lib/internal/net.js", + "lib/internal/options.js", + "lib/internal/per_context/domexception.js", + "lib/internal/per_context/messageport.js", + "lib/internal/per_context/primordials.js", + "lib/internal/perf/event_loop_delay.js", + "lib/internal/perf/event_loop_utilization.js", + "lib/internal/perf/nodetiming.js", + "lib/internal/perf/observe.js", + "lib/internal/perf/performance.js", + "lib/internal/perf/performance_entry.js", + "lib/internal/perf/resource_timing.js", + "lib/internal/perf/timerify.js", + "lib/internal/perf/usertiming.js", + "lib/internal/perf/utils.js", + "lib/internal/priority_queue.js", + "lib/internal/process/execution.js", + "lib/internal/process/finalization.js", + "lib/internal/process/per_thread.js", + "lib/internal/process/permission.js", + "lib/internal/process/pre_execution.js", + "lib/internal/process/promises.js", + "lib/internal/process/report.js", + "lib/internal/process/signal.js", + "lib/internal/process/task_queues.js", + "lib/internal/process/warning.js", + "lib/internal/process/worker_thread_only.js", + "lib/internal/promise_hooks.js", + "lib/internal/querystring.js", + "lib/internal/quic/quic.js", + "lib/internal/quic/state.js", + "lib/internal/quic/stats.js", + "lib/internal/quic/symbols.js", + "lib/internal/readline/callbacks.js", + "lib/internal/readline/emitKeypressEvents.js", + "lib/internal/readline/interface.js", + "lib/internal/readline/promises.js", + "lib/internal/readline/utils.js", + "lib/internal/repl.js", + "lib/internal/repl/await.js", + "lib/internal/repl/history.js", + "lib/internal/repl/utils.js", + "lib/internal/socket_list.js", + "lib/internal/socketaddress.js", + "lib/internal/source_map/prepare_stack_trace.js", + "lib/internal/source_map/source_map.js", + "lib/internal/source_map/source_map_cache.js", + "lib/internal/source_map/source_map_cache_map.js", + "lib/internal/stream_base_commons.js", + "lib/internal/streams/add-abort-signal.js", + "lib/internal/streams/compose.js", + "lib/internal/streams/destroy.js", + "lib/internal/streams/duplex.js", + "lib/internal/streams/duplexify.js", + "lib/internal/streams/duplexpair.js", + "lib/internal/streams/end-of-stream.js", + "lib/internal/streams/from.js", + "lib/internal/streams/lazy_transform.js", + "lib/internal/streams/legacy.js", + "lib/internal/streams/operators.js", + "lib/internal/streams/passthrough.js", + "lib/internal/streams/pipeline.js", + "lib/internal/streams/readable.js", + "lib/internal/streams/state.js", + "lib/internal/streams/transform.js", + "lib/internal/streams/utils.js", + "lib/internal/streams/writable.js", + "lib/internal/test/binding.js", + "lib/internal/test/transfer.js", + "lib/internal/test_runner/assert.js", + "lib/internal/test_runner/coverage.js", + "lib/internal/test_runner/harness.js", + "lib/internal/test_runner/mock/loader.js", + "lib/internal/test_runner/mock/mock.js", + "lib/internal/test_runner/mock/mock_timers.js", + "lib/internal/test_runner/reporter/dot.js", + "lib/internal/test_runner/reporter/junit.js", + "lib/internal/test_runner/reporter/lcov.js", + "lib/internal/test_runner/reporter/spec.js", + "lib/internal/test_runner/reporter/tap.js", + "lib/internal/test_runner/reporter/utils.js", + "lib/internal/test_runner/reporter/v8-serializer.js", + "lib/internal/test_runner/runner.js", + "lib/internal/test_runner/snapshot.js", + "lib/internal/test_runner/test.js", + "lib/internal/test_runner/tests_stream.js", + "lib/internal/test_runner/utils.js", + "lib/internal/timers.js", + "lib/internal/tls/secure-context.js", + "lib/internal/tls/secure-pair.js", + "lib/internal/trace_events_async_hooks.js", + "lib/internal/tty.js", + "lib/internal/url.js", + "lib/internal/util.js", + "lib/internal/util/colors.js", + "lib/internal/util/comparisons.js", + "lib/internal/util/debuglog.js", + "lib/internal/util/diff.js", + "lib/internal/util/inspect.js", + "lib/internal/util/inspector.js", + "lib/internal/util/parse_args/parse_args.js", + "lib/internal/util/parse_args/utils.js", + "lib/internal/util/types.js", + "lib/internal/v8/startup_snapshot.js", + "lib/internal/v8_prof_polyfill.js", + "lib/internal/v8_prof_processor.js", + "lib/internal/validators.js", + "lib/internal/vm.js", + "lib/internal/vm/module.js", + "lib/internal/wasm_web_api.js", + "lib/internal/watch_mode/files_watcher.js", + "lib/internal/watchdog.js", + "lib/internal/webidl.js", + "lib/internal/webstorage.js", + "lib/internal/webstreams/adapters.js", + "lib/internal/webstreams/compression.js", + "lib/internal/webstreams/encoding.js", + "lib/internal/webstreams/queuingstrategies.js", + "lib/internal/webstreams/readablestream.js", + "lib/internal/webstreams/transfer.js", + "lib/internal/webstreams/transformstream.js", + "lib/internal/webstreams/util.js", + "lib/internal/webstreams/writablestream.js", + "lib/internal/worker.js", + "lib/internal/worker/io.js", + "lib/internal/worker/js_transferable.js", + "lib/internal/worker/messaging.js", + "lib/module.js", + "lib/net.js", + "lib/os.js", + "lib/path.js", + "lib/path/posix.js", + "lib/path/win32.js", + "lib/perf_hooks.js", + "lib/process.js", + "lib/punycode.js", + "lib/querystring.js", + "lib/readline.js", + "lib/readline/promises.js", + "lib/repl.js", + "lib/sea.js", + "lib/sqlite.js", + "lib/stream.js", + "lib/stream/consumers.js", + "lib/stream/promises.js", + "lib/stream/web.js", + "lib/string_decoder.js", + "lib/sys.js", + "lib/test.js", + "lib/test/reporters.js", + "lib/timers.js", + "lib/timers/promises.js", + "lib/tls.js", + "lib/trace_events.js", + "lib/tty.js", + "lib/url.js", + "lib/util.js", + "lib/util/types.js", + "lib/v8.js", + "lib/vm.js", + "lib/wasi.js", + "lib/worker_threads.js", + "lib/zlib.js" + ], + "node_module_version": 127, + "node_no_browser_globals": "false", + "node_prefix": "/", + "node_release_urlbase": "https://nodejs.org/download/release/", + "node_shared": "false", + "node_shared_ada": "false", + "node_shared_brotli": "false", + "node_shared_cares": "false", + "node_shared_http_parser": "false", + "node_shared_libuv": "false", + "node_shared_nghttp2": "false", + "node_shared_nghttp3": "false", + "node_shared_ngtcp2": "false", + "node_shared_openssl": "false", + "node_shared_simdjson": "false", + "node_shared_simdutf": "false", + "node_shared_sqlite": "false", + "node_shared_uvwasi": "false", + "node_shared_zlib": "false", + "node_shared_zstd": "false", + "node_tag": "", + "node_target_type": "executable", + "node_use_amaro": "true", + "node_use_bundled_v8": "true", + "node_use_node_code_cache": "true", + "node_use_node_snapshot": "true", + "node_use_openssl": "true", + "node_use_sqlite": "true", + "node_use_v8_platform": "true", + "node_with_ltcg": "false", + "node_without_node_options": "false", + "node_write_snapshot_as_array_literals": "false", + "openssl_is_fips": "false", + "openssl_quic": "false", + "ossfuzz": "false", + "shlib_suffix": "127.dylib", + "single_executable_application": "true", + "suppress_all_error_on_warn": "false", + "target_arch": "arm64", + "ubsan": 0, + "use_ccache_win": 0, + "use_prefix_to_find_headers": "false", + "v8_enable_31bit_smis_on_64bit_arch": 0, + "v8_enable_extensible_ro_snapshot": 0, + "v8_enable_external_code_space": 0, + "v8_enable_gdbjit": 0, + "v8_enable_hugepage": 0, + "v8_enable_i18n_support": 1, + "v8_enable_inspector": 1, + "v8_enable_javascript_promise_hooks": 1, + "v8_enable_lite_mode": 0, + "v8_enable_maglev": 0, + "v8_enable_object_print": 1, + "v8_enable_pointer_compression": 0, + "v8_enable_pointer_compression_shared_cage": 0, + "v8_enable_sandbox": 0, + "v8_enable_shared_ro_heap": 1, + "v8_enable_webassembly": 1, + "v8_optimized_debug": 1, + "v8_promise_internal_field_count": 1, + "v8_random_seed": 0, + "v8_trace_maps": 0, + "v8_use_siphash": 1, + "want_separate_host_toolset": 0, + "xcode_version": "16.0", + "nodedir": "/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1", + "python": "/Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3", + "standalone_static_library": 1, + "prefix": "/Users/gargsurbhi/.asdf/installs/nodejs/22.17.1", + "user_agent": "npm/10.9.2 node/v22.17.1 darwin arm64 workspaces/false", + "cache": "/Users/gargsurbhi/.npm", + "node_gyp": "/Users/gargsurbhi/.asdf/installs/nodejs/22.17.1/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", + "npm_version": "10.9.2", + "init_module": "/Users/gargsurbhi/.npm-init.js", + "userconfig": "/Users/gargsurbhi/.npmrc", + "globalconfig": "/Users/gargsurbhi/.asdf/installs/nodejs/22.17.1/etc/npmrc", + "local_prefix": "/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi", + "global_prefix": "/Users/gargsurbhi/.asdf/installs/nodejs/22.17.1" + } +} diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/gyp-mac-tool b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/gyp-mac-tool new file mode 100755 index 00000000..ab21cf16 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/gyp-mac-tool @@ -0,0 +1,766 @@ +#!/usr/bin/env python3 +# Generated by gyp. Do not edit. +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Utility functions to perform Xcode-style build steps. + +These functions are executed via gyp-mac-tool when using the Makefile generator. +""" + +import fcntl +import fnmatch +import glob +import json +import os +import plistlib +import re +import shutil +import struct +import subprocess +import sys +import tempfile + + +def main(args): + executor = MacTool() + if (exit_code := executor.Dispatch(args)) is not None: + sys.exit(exit_code) + + +class MacTool: + """This class performs all the Mac tooling steps. The methods can either be + executed directly, or dispatched from an argument list.""" + + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + return getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like copy-info-plist to CopyInfoPlist""" + return name_string.title().replace("-", "") + + def ExecCopyBundleResource(self, source, dest, convert_to_binary): + """Copies a resource file to the bundle/Resources directory, performing any + necessary compilation on each resource.""" + convert_to_binary = convert_to_binary == "True" + extension = os.path.splitext(source)[1].lower() + if os.path.isdir(source): + # Copy tree. + # TODO(thakis): This copies file attributes like mtime, while the + # single-file branch below doesn't. This should probably be changed to + # be consistent with the single-file branch. + if os.path.exists(dest): + shutil.rmtree(dest) + shutil.copytree(source, dest) + elif extension in {".xib", ".storyboard"}: + return self._CopyXIBFile(source, dest) + elif extension == ".strings" and not convert_to_binary: + self._CopyStringsFile(source, dest) + else: + if os.path.exists(dest): + os.unlink(dest) + shutil.copy(source, dest) + + if convert_to_binary and extension in {".plist", ".strings"}: + self._ConvertToBinary(dest) + + def _CopyXIBFile(self, source, dest): + """Compiles a XIB file with ibtool into a binary plist in the bundle.""" + + # ibtool sometimes crashes with relative paths. See crbug.com/314728. + base = os.path.dirname(os.path.realpath(__file__)) + if os.path.relpath(source): + source = os.path.join(base, source) + if os.path.relpath(dest): + dest = os.path.join(base, dest) + + args = ["xcrun", "ibtool", "--errors", "--warnings", "--notices"] + + if os.environ["XCODE_VERSION_ACTUAL"] > "0700": + args.extend(["--auto-activate-custom-fonts"]) + if "IPHONEOS_DEPLOYMENT_TARGET" in os.environ: + args.extend( + [ + "--target-device", + "iphone", + "--target-device", + "ipad", + "--minimum-deployment-target", + os.environ["IPHONEOS_DEPLOYMENT_TARGET"], + ] + ) + else: + args.extend( + [ + "--target-device", + "mac", + "--minimum-deployment-target", + os.environ["MACOSX_DEPLOYMENT_TARGET"], + ] + ) + + args.extend( + ["--output-format", "human-readable-text", "--compile", dest, source] + ) + + ibtool_section_re = re.compile(r"/\*.*\*/") + ibtool_re = re.compile(r".*note:.*is clipping its content") + try: + stdout = subprocess.check_output(args) + except subprocess.CalledProcessError as e: + print(e.output) + raise + current_section_header = None + for line in stdout.splitlines(): + if ibtool_section_re.match(line): + current_section_header = line + elif not ibtool_re.match(line): + if current_section_header: + print(current_section_header) + current_section_header = None + print(line) + return 0 + + def _ConvertToBinary(self, dest): + subprocess.check_call( + ["xcrun", "plutil", "-convert", "binary1", "-o", dest, dest] + ) + + def _CopyStringsFile(self, source, dest): + """Copies a .strings file using iconv to reconvert the input into UTF-16.""" + input_code = self._DetectInputEncoding(source) or "UTF-8" + + # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call + # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints + # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing + # semicolon in dictionary. + # on invalid files. Do the same kind of validation. + import CoreFoundation # noqa: PLC0415 + + with open(source, "rb") as in_file: + s = in_file.read() + d = CoreFoundation.CFDataCreate(None, s, len(s)) + _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None) + if error: + return + + with open(dest, "wb") as fp: + fp.write(s.decode(input_code).encode("UTF-16")) + + def _DetectInputEncoding(self, file_name): + """Reads the first few bytes from file_name and tries to guess the text + encoding. Returns None as a guess if it can't detect it.""" + with open(file_name, "rb") as fp: + try: + header = fp.read(3) + except Exception: + return None + if header.startswith((b"\xfe\xff", b"\xff\xfe")): + return "UTF-16" + elif header.startswith(b"\xef\xbb\xbf"): + return "UTF-8" + else: + return None + + def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys): + """Copies the |source| Info.plist to the destination directory |dest|.""" + # Read the source Info.plist into memory. + with open(source) as fd: + lines = fd.read() + + # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild). + plist = plistlib.readPlistFromString(lines) + if keys: + plist.update(json.loads(keys[0])) + lines = plistlib.writePlistToString(plist) + + # Go through all the environment variables and replace them as variables in + # the file. + IDENT_RE = re.compile(r"[_/\s]") + for key in os.environ: + if key.startswith("_"): + continue + evar = "${%s}" % key + evalue = os.environ[key] + lines = lines.replace(lines, evar, evalue) + + # Xcode supports various suffices on environment variables, which are + # all undocumented. :rfc1034identifier is used in the standard project + # template these days, and :identifier was used earlier. They are used to + # convert non-url characters into things that look like valid urls -- + # except that the replacement character for :identifier, '_' isn't valid + # in a URL either -- oops, hence :rfc1034identifier was born. + evar = "${%s:identifier}" % key + evalue = IDENT_RE.sub("_", os.environ[key]) + lines = lines.replace(lines, evar, evalue) + + evar = "${%s:rfc1034identifier}" % key + evalue = IDENT_RE.sub("-", os.environ[key]) + lines = lines.replace(lines, evar, evalue) + + # Remove any keys with values that haven't been replaced. + lines = lines.splitlines() + for i in range(len(lines)): + if lines[i].strip().startswith("${"): + lines[i] = None + lines[i - 1] = None + lines = "\n".join(line for line in lines if line is not None) + + # Write out the file with variables replaced. + with open(dest, "w") as fd: + fd.write(lines) + + # Now write out PkgInfo file now that the Info.plist file has been + # "compiled". + self._WritePkgInfo(dest) + + if convert_to_binary == "True": + self._ConvertToBinary(dest) + + def _WritePkgInfo(self, info_plist): + """This writes the PkgInfo file from the data stored in Info.plist.""" + plist = plistlib.readPlist(info_plist) + if not plist: + return + + # Only create PkgInfo for executable types. + package_type = plist["CFBundlePackageType"] + if package_type != "APPL": + return + + # The format of PkgInfo is eight characters, representing the bundle type + # and bundle signature, each four characters. If that is missing, four + # '?' characters are used instead. + signature_code = plist.get("CFBundleSignature", "????") + if len(signature_code) != 4: # Wrong length resets everything, too. + signature_code = "?" * 4 + + dest = os.path.join(os.path.dirname(info_plist), "PkgInfo") + with open(dest, "w") as fp: + fp.write(f"{package_type}{signature_code}") + + def ExecFlock(self, lockfile, *cmd_list): + """Emulates the most basic behavior of Linux's flock(1).""" + # Rely on exception handling to report errors. + fd = os.open(lockfile, os.O_RDONLY | os.O_NOCTTY | os.O_CREAT, 0o666) + fcntl.flock(fd, fcntl.LOCK_EX) + return subprocess.call(cmd_list) + + def ExecFilterLibtool(self, *cmd_list): + """Calls libtool and filters out '/path/to/libtool: file: foo.o has no + symbols'.""" + libtool_re = re.compile( + r"^.*libtool: (?:for architecture: \S* )?file: .* has no symbols$" + ) + libtool_re5 = re.compile( + r"^.*libtool: warning for library: " + + r".* the table of contents is empty " + + r"\(no object file members in the library define global symbols\)$" + ) + env = os.environ.copy() + # Ref: + # http://www.opensource.apple.com/source/cctools/cctools-809/misc/libtool.c + # The problem with this flag is that it resets the file mtime on the file to + # epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone. + env["ZERO_AR_DATE"] = "1" + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env) + err = libtoolout.communicate()[1].decode("utf-8") + for line in err.splitlines(): + if not libtool_re.match(line) and not libtool_re5.match(line): + print(line, file=sys.stderr) + # Unconditionally touch the output .a file on the command line if present + # and the command succeeded. A bit hacky. + if not libtoolout.returncode: + for i in range(len(cmd_list) - 1): + if cmd_list[i] == "-o" and cmd_list[i + 1].endswith(".a"): + os.utime(cmd_list[i + 1], None) + break + return libtoolout.returncode + + def ExecPackageIosFramework(self, framework): + # Find the name of the binary based on the part before the ".framework". + binary = os.path.basename(framework).split(".")[0] + module_path = os.path.join(framework, "Modules") + if not os.path.exists(module_path): + os.mkdir(module_path) + module_template = ( + "framework module %s {\n" + ' umbrella header "%s.h"\n' + "\n" + " export *\n" + " module * { export * }\n" + "}\n" % (binary, binary) + ) + + with open(os.path.join(module_path, "module.modulemap"), "w") as module_file: + module_file.write(module_template) + + def ExecPackageFramework(self, framework, version): + """Takes a path to Something.framework and the Current version of that and + sets up all the symlinks.""" + # Find the name of the binary based on the part before the ".framework". + binary = os.path.basename(framework).split(".")[0] + + CURRENT = "Current" + RESOURCES = "Resources" + VERSIONS = "Versions" + + if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)): + # Binary-less frameworks don't seem to contain symlinks (see e.g. + # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle). + return + + # Move into the framework directory to set the symlinks correctly. + pwd = os.getcwd() + os.chdir(framework) + + # Set up the Current version. + self._Relink(version, os.path.join(VERSIONS, CURRENT)) + + # Set up the root symlinks. + self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary) + self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES) + + # Back to where we were before! + os.chdir(pwd) + + def _Relink(self, dest, link): + """Creates a symlink to |dest| named |link|. If |link| already exists, + it is overwritten.""" + if os.path.lexists(link): + os.remove(link) + os.symlink(dest, link) + + def ExecCompileIosFrameworkHeaderMap(self, out, framework, *all_headers): + framework_name = os.path.basename(framework).split(".")[0] + all_headers = [os.path.abspath(header) for header in all_headers] + filelist = {} + for header in all_headers: + filename = os.path.basename(header) + filelist[filename] = header + filelist[os.path.join(framework_name, filename)] = header + WriteHmap(out, filelist) + + def ExecCopyIosFrameworkHeaders(self, framework, *copy_headers): + header_path = os.path.join(framework, "Headers") + if not os.path.exists(header_path): + os.makedirs(header_path) + for header in copy_headers: + shutil.copy(header, os.path.join(header_path, os.path.basename(header))) + + def ExecCompileXcassets(self, keys, *inputs): + """Compiles multiple .xcassets files into a single .car file. + + This invokes 'actool' to compile all the inputs .xcassets files. The + |keys| arguments is a json-encoded dictionary of extra arguments to + pass to 'actool' when the asset catalogs contains an application icon + or a launch image. + + Note that 'actool' does not create the Assets.car file if the asset + catalogs does not contains imageset. + """ + command_line = [ + "xcrun", + "actool", + "--output-format", + "human-readable-text", + "--compress-pngs", + "--notices", + "--warnings", + "--errors", + ] + is_iphone_target = "IPHONEOS_DEPLOYMENT_TARGET" in os.environ + if is_iphone_target: + platform = os.environ["CONFIGURATION"].split("-")[-1] + if platform not in ("iphoneos", "iphonesimulator"): + platform = "iphonesimulator" + command_line.extend( + [ + "--platform", + platform, + "--target-device", + "iphone", + "--target-device", + "ipad", + "--minimum-deployment-target", + os.environ["IPHONEOS_DEPLOYMENT_TARGET"], + "--compile", + os.path.abspath(os.environ["CONTENTS_FOLDER_PATH"]), + ] + ) + else: + command_line.extend( + [ + "--platform", + "macosx", + "--target-device", + "mac", + "--minimum-deployment-target", + os.environ["MACOSX_DEPLOYMENT_TARGET"], + "--compile", + os.path.abspath(os.environ["UNLOCALIZED_RESOURCES_FOLDER_PATH"]), + ] + ) + if keys: + keys = json.loads(keys) + for key, value in keys.items(): + arg_name = "--" + key + if isinstance(value, bool): + if value: + command_line.append(arg_name) + elif isinstance(value, list): + for v in value: + command_line.append(arg_name) + command_line.append(str(v)) + else: + command_line.append(arg_name) + command_line.append(str(value)) + # Note: actool crashes if inputs path are relative, so use os.path.abspath + # to get absolute path name for inputs. + command_line.extend(map(os.path.abspath, inputs)) + subprocess.check_call(command_line) + + def ExecMergeInfoPlist(self, output, *inputs): + """Merge multiple .plist files into a single .plist file.""" + merged_plist = {} + for path in inputs: + plist = self._LoadPlistMaybeBinary(path) + self._MergePlist(merged_plist, plist) + plistlib.writePlist(merged_plist, output) + + def ExecCodeSignBundle(self, key, entitlements, provisioning, path, preserve): + """Code sign a bundle. + + This function tries to code sign an iOS bundle, following the same + algorithm as Xcode: + 1. pick the provisioning profile that best match the bundle identifier, + and copy it into the bundle as embedded.mobileprovision, + 2. copy Entitlements.plist from user or SDK next to the bundle, + 3. code sign the bundle. + """ + substitutions, overrides = self._InstallProvisioningProfile( + provisioning, self._GetCFBundleIdentifier() + ) + entitlements_path = self._InstallEntitlements( + entitlements, substitutions, overrides + ) + + args = ["codesign", "--force", "--sign", key] + if preserve == "True": + args.extend(["--deep", "--preserve-metadata=identifier,entitlements"]) + else: + args.extend(["--entitlements", entitlements_path]) + args.extend(["--timestamp=none", path]) + subprocess.check_call(args) + + def _InstallProvisioningProfile(self, profile, bundle_identifier): + """Installs embedded.mobileprovision into the bundle. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple containing two dictionary: variables substitutions and values + to overrides when generating the entitlements file. + """ + source_path, provisioning_data, team_id = self._FindProvisioningProfile( + profile, bundle_identifier + ) + target_path = os.path.join( + os.environ["BUILT_PRODUCTS_DIR"], + os.environ["CONTENTS_FOLDER_PATH"], + "embedded.mobileprovision", + ) + shutil.copy2(source_path, target_path) + substitutions = self._GetSubstitutions(bundle_identifier, team_id + ".") + return substitutions, provisioning_data["Entitlements"] + + def _FindProvisioningProfile(self, profile, bundle_identifier): + """Finds the .mobileprovision file to use for signing the bundle. + + Checks all the installed provisioning profiles (or if the user specified + the PROVISIONING_PROFILE variable, only consult it) and select the most + specific that correspond to the bundle identifier. + + Args: + profile: string, optional, short name of the .mobileprovision file + to use, if empty or the file is missing, the best file installed + will be used + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + + Returns: + A tuple of the path to the selected provisioning profile, the data of + the embedded plist in the provisioning profile and the team identifier + to use for code signing. + + Raises: + SystemExit: if no .mobileprovision can be used to sign the bundle. + """ + profiles_dir = os.path.join( + os.environ["HOME"], "Library", "MobileDevice", "Provisioning Profiles" + ) + if not os.path.isdir(profiles_dir): + print( + "cannot find mobile provisioning for %s" % (bundle_identifier), + file=sys.stderr, + ) + sys.exit(1) + provisioning_profiles = None + if profile: + profile_path = os.path.join(profiles_dir, profile + ".mobileprovision") + if os.path.exists(profile_path): + provisioning_profiles = [profile_path] + if not provisioning_profiles: + provisioning_profiles = glob.glob( + os.path.join(profiles_dir, "*.mobileprovision") + ) + valid_provisioning_profiles = {} + for profile_path in provisioning_profiles: + profile_data = self._LoadProvisioningProfile(profile_path) + app_id_pattern = profile_data.get("Entitlements", {}).get( + "application-identifier", "" + ) + for team_identifier in profile_data.get("TeamIdentifier", []): + app_id = f"{team_identifier}.{bundle_identifier}" + if fnmatch.fnmatch(app_id, app_id_pattern): + valid_provisioning_profiles[app_id_pattern] = ( + profile_path, + profile_data, + team_identifier, + ) + if not valid_provisioning_profiles: + print( + "cannot find mobile provisioning for %s" % (bundle_identifier), + file=sys.stderr, + ) + sys.exit(1) + # If the user has multiple provisioning profiles installed that can be + # used for ${bundle_identifier}, pick the most specific one (ie. the + # provisioning profile whose pattern is the longest). + selected_key = max(valid_provisioning_profiles, key=lambda v: len(v)) + return valid_provisioning_profiles[selected_key] + + def _LoadProvisioningProfile(self, profile_path): + """Extracts the plist embedded in a provisioning profile. + + Args: + profile_path: string, path to the .mobileprovision file + + Returns: + Content of the plist embedded in the provisioning profile as a dictionary. + """ + with tempfile.NamedTemporaryFile() as temp: + subprocess.check_call( + ["security", "cms", "-D", "-i", profile_path, "-o", temp.name] + ) + return self._LoadPlistMaybeBinary(temp.name) + + def _MergePlist(self, merged_plist, plist): + """Merge |plist| into |merged_plist|.""" + for key, value in plist.items(): + if isinstance(value, dict): + merged_value = merged_plist.get(key, {}) + if isinstance(merged_value, dict): + self._MergePlist(merged_value, value) + merged_plist[key] = merged_value + else: + merged_plist[key] = value + else: + merged_plist[key] = value + + def _LoadPlistMaybeBinary(self, plist_path): + """Loads into a memory a plist possibly encoded in binary format. + + This is a wrapper around plistlib.readPlist that tries to convert the + plist to the XML format if it can't be parsed (assuming that it is in + the binary format). + + Args: + plist_path: string, path to a plist file, in XML or binary format + + Returns: + Content of the plist as a dictionary. + """ + try: + # First, try to read the file using plistlib that only supports XML, + # and if an exception is raised, convert a temporary copy to XML and + # load that copy. + return plistlib.readPlist(plist_path) + except Exception: + pass + with tempfile.NamedTemporaryFile() as temp: + shutil.copy2(plist_path, temp.name) + subprocess.check_call(["plutil", "-convert", "xml1", temp.name]) + return plistlib.readPlist(temp.name) + + def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix): + """Constructs a dictionary of variable substitutions for Entitlements.plist. + + Args: + bundle_identifier: string, value of CFBundleIdentifier from Info.plist + app_identifier_prefix: string, value for AppIdentifierPrefix + + Returns: + Dictionary of substitutions to apply when generating Entitlements.plist. + """ + return { + "CFBundleIdentifier": bundle_identifier, + "AppIdentifierPrefix": app_identifier_prefix, + } + + def _GetCFBundleIdentifier(self): + """Extracts CFBundleIdentifier value from Info.plist in the bundle. + + Returns: + Value of CFBundleIdentifier in the Info.plist located in the bundle. + """ + info_plist_path = os.path.join( + os.environ["TARGET_BUILD_DIR"], os.environ["INFOPLIST_PATH"] + ) + info_plist_data = self._LoadPlistMaybeBinary(info_plist_path) + return info_plist_data["CFBundleIdentifier"] + + def _InstallEntitlements(self, entitlements, substitutions, overrides): + """Generates and install the ${BundleName}.xcent entitlements file. + + Expands variables "$(variable)" pattern in the source entitlements file, + add extra entitlements defined in the .mobileprovision file and the copy + the generated plist to "${BundlePath}.xcent". + + Args: + entitlements: string, optional, path to the Entitlements.plist template + to use, defaults to "${SDKROOT}/Entitlements.plist" + substitutions: dictionary, variable substitutions + overrides: dictionary, values to add to the entitlements + + Returns: + Path to the generated entitlements file. + """ + source_path = entitlements + target_path = os.path.join( + os.environ["BUILT_PRODUCTS_DIR"], os.environ["PRODUCT_NAME"] + ".xcent" + ) + if not source_path: + source_path = os.path.join(os.environ["SDKROOT"], "Entitlements.plist") + shutil.copy2(source_path, target_path) + data = self._LoadPlistMaybeBinary(target_path) + data = self._ExpandVariables(data, substitutions) + if overrides: + for key in overrides: + if key not in data: + data[key] = overrides[key] + plistlib.writePlist(data, target_path) + return target_path + + def _ExpandVariables(self, data, substitutions): + """Expands variables "$(variable)" in data. + + Args: + data: object, can be either string, list or dictionary + substitutions: dictionary, variable substitutions to perform + + Returns: + Copy of data where each references to "$(variable)" has been replaced + by the corresponding value found in substitutions, or left intact if + the key was not found. + """ + if isinstance(data, str): + for key, value in substitutions.items(): + data = data.replace("$(%s)" % key, value) + return data + if isinstance(data, list): + return [self._ExpandVariables(v, substitutions) for v in data] + if isinstance(data, dict): + return {k: self._ExpandVariables(data[k], substitutions) for k in data} + return data + + +def NextGreaterPowerOf2(x): + return 2 ** (x).bit_length() + + +def WriteHmap(output_name, filelist): + """Generates a header map based on |filelist|. + + Per Mark Mentovai: + A header map is structured essentially as a hash table, keyed by names used + in #includes, and providing pathnames to the actual files. + + The implementation below and the comment above comes from inspecting: + http://www.opensource.apple.com/source/distcc/distcc-2503/distcc_dist/include_server/headermap.py?txt + while also looking at the implementation in clang in: + https://llvm.org/svn/llvm-project/cfe/trunk/lib/Lex/HeaderMap.cpp + """ + magic = 1751998832 + version = 1 + _reserved = 0 + count = len(filelist) + capacity = NextGreaterPowerOf2(count) + strings_offset = 24 + (12 * capacity) + max_value_length = max(len(value) for value in filelist.values()) + + out = open(output_name, "wb") + out.write( + struct.pack( + "=20.0.0" + } + }, + "node_modules/@google-cloud/common": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-5.0.2.tgz", + "integrity": "sha512-V7bmBKYQyu0eVG2BFejuUjlBt+zrya6vtsKdY+JxMM/dNntPF41vZ9+LhOshEUH01zOHEqBSvI7Dad7ZS6aUeA==", + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "^4.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "extend": "^3.0.2", + "google-auth-library": "^9.0.0", + "html-entities": "^2.5.2", + "retry-request": "^7.0.0", + "teeny-request": "^9.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/precise-date": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-4.0.0.tgz", + "integrity": "sha512-1TUx3KdaU3cN7nfCdNf+UVqA/PSX29Cjcox3fZZBtINlRrXVTmUkQnCKv2MbBUbCopbK4olAT1IHl76uZyCiVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/projectify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", + "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/promisify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz", + "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@google-cloud/spanner": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@google-cloud/spanner/-/spanner-7.21.0.tgz", + "integrity": "sha512-SrlHgXmSaEbGhdimxcB0FgNsW9J931JBBveoGW43clQHVNcDJuKRoG+240inbSRZoW8JIwwEHToXYU5YGO3VGg==", + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/common": "^5.0.0", + "@google-cloud/precise-date": "^4.0.0", + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "4.0.0", + "@grpc/proto-loader": "^0.7.0", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.26.0", + "@opentelemetry/core": "^1.27.0", + "@opentelemetry/semantic-conventions": "^1.25.1", + "@types/big.js": "^6.0.0", + "@types/stack-trace": "0.0.33", + "arrify": "^2.0.0", + "big.js": "^6.0.0", + "checkpoint-stream": "^0.1.1", + "duplexify": "^4.1.1", + "events-intercept": "^2.0.0", + "extend": "^3.0.2", + "google-auth-library": "^9.0.0", + "google-gax": "4.4.1", + "grpc-gcp": "^1.0.0", + "is": "^3.2.1", + "lodash.snakecase": "^4.1.1", + "merge-stream": "^2.0.0", + "p-queue": "^6.0.2", + "protobufjs": "^7.0.0", + "retry-request": "^7.0.0", + "split-array-stream": "^2.0.0", + "stack-trace": "0.0.10", + "stream-events": "^1.0.4", + "teeny-request": "^9.0.0", + "through2": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", + "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", + "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.3", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.30.1.tgz", + "integrity": "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", + "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", + "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-e2cOW9YlVzFY2iScnGBBkplKsrn2CsObHQ2Hiw4V1sSyiGbgWL8IyqE3zFi1Pt5o1pdAtYkDAIsF3KKUPjdzaA==", + "license": "MIT" + }, + "node_modules/@types/caseless": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", + "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", + "license": "MIT" + }, + "node_modules/@types/duplexify": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.5.tgz", + "integrity": "sha512-fB56ACzlW91UdZ5F3VXplVMDngO8QaX5Y2mjvADtN01TT2TMy4WjF0Lg+tFDvt4uMBeTe4SgaD+qCrA7dL5/tA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/pumpify": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/pumpify/-/pumpify-1.4.5.tgz", + "integrity": "sha512-BGVAQyK5yJdfIII230fVYGY47V63hUNAhryuuS3b4lEN2LNwxUXFKsEf8QLDCjmZuimlj23BHppJgcrGvNtqKg==", + "license": "MIT", + "dependencies": { + "@types/duplexify": "*", + "@types/node": "*" + } + }, + "node_modules/@types/request": { + "version": "2.48.13", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.13.tgz", + "integrity": "sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==", + "license": "MIT", + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.5" + } + }, + "node_modules/@types/stack-trace": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.33.tgz", + "integrity": "sha512-O7in6531Bbvlb2KEsJ0dq0CHZvc3iWSR5ZYMtvGgnHA56VgriAN/AU2LorfmcvAl2xc9N5fbCTRyMRRl8nd74g==", + "license": "MIT" + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/checkpoint-stream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/checkpoint-stream/-/checkpoint-stream-0.1.2.tgz", + "integrity": "sha512-eYXIcydL3mPjjEVLxHdi1ISgTwmxGJZ8vyJ3lYVvFTDRyTOZMTbKZdRJqiA7Gi1rPcwOyyzcrZmGLL8ff7e69w==", + "license": "MIT", + "dependencies": { + "@types/pumpify": "^1.4.1", + "events-intercept": "^2.0.0", + "pumpify": "^1.3.5", + "split-array-stream": "^1.0.0", + "through2": "^2.0.3" + } + }, + "node_modules/checkpoint-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/checkpoint-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/checkpoint-stream/node_modules/split-array-stream": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/split-array-stream/-/split-array-stream-1.0.3.tgz", + "integrity": "sha512-yGY35QmZFzZkWZ0eHE06RPBi63umym8m+pdtuC/dlO1ADhdKSfCj0uNn87BYCXBBDFxyTq4oTw0BgLYT0K5z/A==", + "license": "MIT", + "dependencies": { + "async": "^2.4.0", + "is-stream-ended": "^0.1.0" + } + }, + "node_modules/checkpoint-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/checkpoint-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=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==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=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==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/events-intercept": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/events-intercept/-/events-intercept-2.0.0.tgz", + "integrity": "sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/form-data": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz", + "integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "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==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "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==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/google-auth-library": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-gax": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz", + "integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.10.9", + "@grpc/proto-loader": "^0.7.13", + "@types/long": "^4.0.0", + "abort-controller": "^3.0.0", + "duplexify": "^4.0.0", + "google-auth-library": "^9.3.0", + "node-fetch": "^2.7.0", + "object-hash": "^3.0.0", + "proto3-json-serializer": "^2.0.2", + "protobufjs": "^7.3.2", + "retry-request": "^7.0.0", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/grpc-gcp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/grpc-gcp/-/grpc-gcp-1.0.1.tgz", + "integrity": "sha512-06r73IoGaAIpzT+DRPnw7V5BXvZ5mjy1OcKqSPX+ZHOgbLxT+lJfz8IN83z/sbA3t55ZX88MfDaaCjDGdveVIA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/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==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.2.tgz", + "integrity": "sha512-a2xr4E3s1PjDS8ORcGgXpWx6V+liNs+O3JRD2mb9aeugD7rtkkZ0zgLdYgw0tWsKhsdiezGYptSiMlVazCBTuQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", + "license": "MIT" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/proto3-json-serializer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz", + "integrity": "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==", + "license": "Apache-2.0", + "dependencies": { + "protobufjs": "^7.2.5" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/protobufjs": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/pumpify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/pumpify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/pumpify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/retry-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", + "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", + "license": "MIT", + "dependencies": { + "@types/request": "^2.48.8", + "extend": "^3.0.2", + "teeny-request": "^9.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/split-array-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/split-array-stream/-/split-array-stream-2.0.0.tgz", + "integrity": "sha512-hmMswlVY91WvGMxs0k8MRgq8zb2mSen4FmDNc5AFiTWtrBpdZN6nwD6kROVe4vNL+ywrvbCKsWVCnEd4riELIg==", + "license": "MIT", + "dependencies": { + "is-stream-ended": "^0.1.4" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "license": "MIT", + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", + "license": "MIT" + }, + "node_modules/teeny-request": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", + "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", + "license": "Apache-2.0", + "dependencies": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.9", + "stream-events": "^1.0.5", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/teeny-request/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==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/teeny-request/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==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "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" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json index 46cd6f40..c0912c12 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json @@ -1,12 +1,18 @@ { - "name": "napi", + "name": "napi-spanner", "version": "1.0.0", "main": "index.js", + "engines": { + "node": ">=20.0.0" + }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "node-gyp rebuild", + "test": "node test.js", + "setup": "node setup_db.js" + }, + "dependencies": { + "@google-cloud/spanner": "^7.19.1", + "node-addon-api": "^8.0.0" }, - "keywords": [], - "author": "", - "license": "ISC", - "description": "" + "gypfile": true } diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/setup_db.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/setup_db.js new file mode 100644 index 00000000..14d1321a --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/setup_db.js @@ -0,0 +1,46 @@ +const { Spanner } = require('@google-cloud/spanner'); + +const projectId = 'span-cloud-testing'; +const instanceId = 'gargsurbhi-testing'; +const databaseId = `test-db-koffi-${Math.floor(Math.random() * 1000)}`; + +const spanner = new Spanner({ projectId }); +const instance = spanner.instance(instanceId); + +async function setupDatabase() { + console.log(`Setting up Spanner Database: ${databaseId}...`); + try { + const [database, operation] = await instance.createDatabase(databaseId, { + schema: [ + `CREATE TABLE Singers ( + SingerId INT64 NOT NULL, + FirstName STRING(1024), + LastName STRING(1024), + IsActive BOOL, + Balance FLOAT64 + ) PRIMARY KEY (SingerId)` + ], + }); + + console.log(`Database creation initiated. Waiting for operation...`); + await operation.promise(); + console.log(`Database ${database.id} created with Schema.`); + + console.log('Inserting dummy data...'); + const table = database.table('Singers'); + await table.insert([ + { SingerId: 1, FirstName: 'Marc', LastName: 'Richards', IsActive: true, Balance: 100.50 }, + { SingerId: 2, FirstName: 'Catalina', LastName: 'Smith', IsActive: false, Balance: 250.75 }, + { SingerId: 3, FirstName: 'Alice', LastName: 'Trentor', IsActive: true, Balance: 0.10 } + ]); + console.log('Dummy data inserted successfully!'); + + // Save DB name to file so the test can pick it up + require('fs').writeFileSync('./test-db.txt', databaseId); + + } catch (err) { + console.error('ERROR:', err); + } +} + +setupDatabase().catch(console.error); diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/cpp/addon.cc b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/cpp/addon.cc new file mode 100644 index 00000000..481d72e1 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/cpp/addon.cc @@ -0,0 +1,294 @@ +#include +#include +#include "../../../../../shared/libspanner.h" + +// +// Worker 1: CreatePool asynchronously +// +class CreatePoolWorker : public Napi::AsyncWorker { +public: + CreatePoolWorker(Napi::Function& callback, std::string userAgent, std::string connStr) + : AsyncWorker(callback), userAgent_(userAgent), connStr_(connStr), result_({0, 0, 0, 0, nullptr}) {} + + void Execute() override { + GoString goUserAgent = {userAgent_.c_str(), (ptrdiff_t)userAgent_.length()}; + GoString goConnStr = {connStr_.c_str(), (ptrdiff_t)connStr_.length()}; + result_ = CreatePool(goUserAgent, goConnStr); + } + + void OnOK() override { + Napi::Env env = Env(); + Napi::Object obj = Napi::Object::New(env); + obj.Set("r0", Napi::Number::New(env, result_.r0)); + obj.Set("r1", Napi::Number::New(env, result_.r1)); + obj.Set("r2", Napi::Number::New(env, result_.r2)); + obj.Set("r3", Napi::Number::New(env, result_.r3)); + + if (result_.r4 != nullptr && result_.r3 > 0) { + obj.Set("r4", Napi::Buffer::Copy(env, (uint8_t*)result_.r4, result_.r3)); + } else { + obj.Set("r4", env.Null()); + } + Callback().Call({env.Null(), obj}); + } + +private: + std::string userAgent_; + std::string connStr_; + CreatePool_return result_; +}; + +Napi::Value CreatePoolWrapper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + std::string ua = info[0].As(); + std::string cs = info[1].As(); + Napi::Function cb = info[2].As(); + CreatePoolWorker* worker = new CreatePoolWorker(cb, ua, cs); + worker->Queue(); + return env.Undefined(); +} + +// +// Worker 2: ClosePool asynchronously +// +class ClosePoolWorker : public Napi::AsyncWorker { +public: + ClosePoolWorker(Napi::Function& callback, int64_t poolId) + : AsyncWorker(callback), poolId_(poolId), result_({0, 0, 0, 0, nullptr}) {} + + void Execute() override { + result_ = ClosePool(poolId_); + } + + void OnOK() override { + Napi::Env env = Env(); + Napi::Object obj = Napi::Object::New(env); + obj.Set("r1", Napi::Number::New(env, result_.r1)); + Callback().Call({env.Null(), obj}); + } +private: + int64_t poolId_; + ClosePool_return result_; +}; + +Napi::Value ClosePoolWrapper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + int64_t pid = info[0].As().Int64Value(); + Napi::Function cb = info[1].As(); + ClosePoolWorker* worker = new ClosePoolWorker(cb, pid); + worker->Queue(); + return env.Undefined(); +} + +// +// Worker 3: CreateConnection asynchronously +// +class CreateConnectionWorker : public Napi::AsyncWorker { +public: + CreateConnectionWorker(Napi::Function& callback, int64_t poolId) + : AsyncWorker(callback), poolId_(poolId), result_({0, 0, 0, 0, nullptr}) {} + + void Execute() override { + result_ = CreateConnection(poolId_); + } + + void OnOK() override { + Napi::Env env = Env(); + Napi::Object obj = Napi::Object::New(env); + obj.Set("r0", Napi::Number::New(env, result_.r0)); + obj.Set("r1", Napi::Number::New(env, result_.r1)); + obj.Set("r2", Napi::Number::New(env, result_.r2)); + obj.Set("r3", Napi::Number::New(env, result_.r3)); + + if (result_.r4 != nullptr && result_.r3 > 0) { + obj.Set("r4", Napi::Buffer::Copy(env, (uint8_t*)result_.r4, result_.r3)); + } else { + obj.Set("r4", env.Null()); + } + Callback().Call({env.Null(), obj}); + } +private: + int64_t poolId_; + CreateConnection_return result_; +}; + +Napi::Value CreateConnectionWrapper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + int64_t pid = info[0].As().Int64Value(); + Napi::Function cb = info[1].As(); + CreateConnectionWorker* worker = new CreateConnectionWorker(cb, pid); + worker->Queue(); + return env.Undefined(); +} + +// +// Worker 4: CloseConnection asynchronously +// +class CloseConnectionWorker : public Napi::AsyncWorker { +public: + CloseConnectionWorker(Napi::Function& callback, int64_t poolId, int64_t connId) + : AsyncWorker(callback), poolId_(poolId), connId_(connId), result_({0, 0, 0, 0, nullptr}) {} + + void Execute() override { + result_ = CloseConnection(poolId_, connId_); + } + + void OnOK() override { + Napi::Env env = Env(); + Napi::Object obj = Napi::Object::New(env); + obj.Set("r1", Napi::Number::New(env, result_.r1)); + Callback().Call({env.Null(), obj}); + } +private: + int64_t poolId_, connId_; + CloseConnection_return result_; +}; + +Napi::Value CloseConnectionWrapper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + int64_t pid = info[0].As().Int64Value(); + int64_t cid = info[1].As().Int64Value(); + Napi::Function cb = info[2].As(); + CloseConnectionWorker* worker = new CloseConnectionWorker(cb, pid, cid); + worker->Queue(); + return env.Undefined(); +} + +// +// Worker 5: Execute asynchronously +// +class ExecuteWorker : public Napi::AsyncWorker { +public: + ExecuteWorker(Napi::Function& callback, int64_t poolId, int64_t connId, std::string payload) + : AsyncWorker(callback), poolId_(poolId), connId_(connId), payload_(payload), result_({0, 0, 0, 0, nullptr}) {} + + void Execute() override { + GoSlice goPayload = {(void*)payload_.data(), (ptrdiff_t)payload_.length(), (ptrdiff_t)payload_.length()}; + result_ = ::Execute(poolId_, connId_, goPayload); + } + + void OnOK() override { + Napi::Env env = Env(); + Napi::Object obj = Napi::Object::New(env); + obj.Set("r0", Napi::Number::New(env, result_.r0)); + obj.Set("r1", Napi::Number::New(env, result_.r1)); + obj.Set("r2", Napi::Number::New(env, result_.r2)); + obj.Set("r3", Napi::Number::New(env, result_.r3)); + if (result_.r4 != nullptr && result_.r3 > 0) { + obj.Set("r4", Napi::Buffer::Copy(env, (uint8_t*)result_.r4, result_.r3)); + } else { + obj.Set("r4", env.Null()); + } + Callback().Call({env.Null(), obj}); + } +private: + int64_t poolId_, connId_; + std::string payload_; + Execute_return result_; +}; + +Napi::Value ExecuteWrapper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + int64_t pid = info[0].As().Int64Value(); + int64_t cid = info[1].As().Int64Value(); + + Napi::Buffer buffer = info[2].As>(); + std::string payload(reinterpret_cast(buffer.Data()), buffer.Length()); + + Napi::Function cb = info[3].As(); + ExecuteWorker* worker = new ExecuteWorker(cb, pid, cid, payload); + worker->Queue(); + return env.Undefined(); +} + +// +// Worker 6: Next asynchronously +// +class NextWorker : public Napi::AsyncWorker { +public: + NextWorker(Napi::Function& callback, int64_t poolId, int64_t connId, int64_t rowsId, int32_t numRows, int32_t encodeOtp) + : AsyncWorker(callback), poolId_(poolId), connId_(connId), rowsId_(rowsId), numRows_(numRows), encodeOtp_(encodeOtp), result_({0, 0, 0, 0, nullptr}) {} + + void Execute() override { + result_ = ::Next(poolId_, connId_, rowsId_, numRows_, encodeOtp_); + } + + void OnOK() override { + Napi::Env env = Env(); + Napi::Object obj = Napi::Object::New(env); + obj.Set("r0", Napi::Number::New(env, result_.r0)); + obj.Set("r1", Napi::Number::New(env, result_.r1)); + obj.Set("r2", Napi::Number::New(env, result_.r2)); + obj.Set("r3", Napi::Number::New(env, result_.r3)); + if (result_.r4 != nullptr && result_.r3 > 0) { + obj.Set("r4", Napi::Buffer::Copy(env, (uint8_t*)result_.r4, result_.r3)); + } else { + obj.Set("r4", env.Null()); + } + Callback().Call({env.Null(), obj}); + } +private: + int64_t poolId_, connId_, rowsId_; + int32_t numRows_, encodeOtp_; + Next_return result_; +}; + +Napi::Value NextWrapper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + int64_t pid = info[0].As().Int64Value(); + int64_t cid = info[1].As().Int64Value(); + int64_t rid = info[2].As().Int64Value(); + int32_t num = info[3].As().Int32Value(); + int32_t encode = info[4].As().Int32Value(); + Napi::Function cb = info[5].As(); + + NextWorker* worker = new NextWorker(cb, pid, cid, rid, num, encode); + worker->Queue(); + return env.Undefined(); +} + +// Memory Release (Synchronous as it is just freeing RAM via GC) +Napi::Value NativeRelease(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + if (info.Length() < 1 || !info[0].IsNumber()) return env.Null(); + int64_t pid = info[0].As().Int64Value(); + Release(pid); + return env.Undefined(); +} + +// CloseRows dummy/missing implementation for POC length if needed, or we just rely on GC. +Napi::Value CloseRowsWrapper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + if (info.Length() < 3) return env.Null(); + int64_t pid = info[0].As().Int64Value(); + int64_t cid = info[1].As().Int64Value(); + int64_t rid = info[2].As().Int64Value(); + + // N-API sync close implementation + CloseRows(pid, cid, rid); + + // invokeAsync appends a callback at the end of properties + if (info.Length() >= 4 && info[3].IsFunction()) { + Napi::Object obj = Napi::Object::New(env); + obj.Set("r1", Napi::Number::New(env, 0)); + Napi::Function cb = info[3].As(); + cb.Call({env.Null(), obj}); // Mock empty GoReturnTuple callback + } + return env.Undefined(); +} + +Napi::Object Init(Napi::Env env, Napi::Object exports) { + exports.Set("CreatePool", Napi::Function::New(env, CreatePoolWrapper)); + exports.Set("ClosePool", Napi::Function::New(env, ClosePoolWrapper)); + exports.Set("CreateConnection", Napi::Function::New(env, CreateConnectionWrapper)); + exports.Set("CloseConnection", Napi::Function::New(env, CloseConnectionWrapper)); + exports.Set("Execute", Napi::Function::New(env, ExecuteWrapper)); + exports.Set("Next", Napi::Function::New(env, NextWrapper)); + + exports.Set("CloseRows", Napi::Function::New(env, CloseRowsWrapper)); + exports.Set("Release", Napi::Function::New(env, NativeRelease)); + + return exports; +} + +NODE_API_MODULE(spanner_napi, Init) diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/bindings.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/bindings.js new file mode 100644 index 00000000..67fd452a --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/bindings.js @@ -0,0 +1,14 @@ +/** + * In N-API, there is no need for 'bindings' mapping types like 'int64' and 'pointer' + * because the C++ addon already handles all V8 type conversions directly. + * We simply export the names of the C++ functions that the wrappers will use. + */ +module.exports = { + CreatePool: 'CreatePool', + ClosePool: 'ClosePool', + CreateConnection: 'CreateConnection', + CloseConnection: 'CloseConnection', + Execute: 'Execute', + Next: 'Next', + CloseRows: 'CloseRows' +}; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/utils.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/utils.js new file mode 100644 index 00000000..ad1f471f --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/utils.js @@ -0,0 +1,48 @@ +const addon = require('../../build/Release/spanner_napi.node'); + +/** + * Normalizes C++ responses to look structurally identical to what Koffi did. + * Koffi returned: { r0: int, r1: int, r2: int, r3: int, r4: pointer/buffer } + */ +function invokeAsync(funcName, constructor1, constructor2, ...args) { + return new Promise((resolve, reject) => { + const callback = (err, result) => { + if (err) { + return reject(err); + } + // Parse Go Error Codes identically to Koffi + if (result.r1 !== 0) { + if (result.r4 && result.r3 > 0) { + const errorJson = result.r4.toString('utf8'); + try { + const parsed = JSON.parse(errorJson); + return reject(new Error(parsed.message || errorJson)); + } catch (e) { + return reject(new Error(errorJson)); + } + } + return reject(new Error(`Native Spanner Error Code: ${result.r1}`)); + } + + // Normal Execution Success + resolve({ + objectId: result.r2, // The new OID (Rows OID, Connection OID) + pinnerId: result.r0, // The GC lock + protobufBytes: result.r4 // The protobuf payload + }); + }; + + // Call the C++ add-on method with arguments and callback + addon[funcName](...args, callback); + }); +} + +/** + * Synchronous direct export for GC memory release + */ +const Release = addon.Release; + +module.exports = { + invokeAsync, + Release +}; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/connection.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/connection.js new file mode 100644 index 00000000..83908ae6 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/connection.js @@ -0,0 +1,87 @@ +const { CreateConnection, CloseConnection, Execute } = require('../ffi/bindings.js'); +const { invokeAsync } = require('../ffi/utils.js'); +const { spannerLib } = require('./spannerlib.js'); +const { Rows } = require('./rows.js'); +const { spanner_v1 } = require('@google-cloud/spanner/build/protos/protos.js'); + +class Connection { + /** + * @param {import('./pool.js').Pool} pool + */ + static async create(pool) { + const c = new Connection(); + c.pool = pool; + + const handled = await invokeAsync( + CreateConnection, + c, // Self reference for GC memory watcher + spannerLib, // Watcher + pool.oid + ); + + c.oid = handled.objectId; + return c; + } + + constructor() { + this.pool = null; + + /** + * The Object ID (OID). + * The global identifier for this specific Connection inside the Go engine. + * @type {Number|null} + */ + this.oid = null; + + /** + * The Memory Pinner ID. + * The exact GC lock holding this Connection's memory intact in Go. + * We pass this to native `Release()` via the Registry to stop leaks. + * @type {Number|null} + */ + this.pinnerId = null; + + this.closed = false; + } + + /** + * Natively executes a SQL query on Node's background LibUV thread while V8 proceeds! + * Integrates raw JS Protobuf definitions (from @google-cloud/spanner package). + */ + async executeSql(sqlString) { + if (this.closed) throw new Error("Connection is already closed"); + + const requestObj = { sql: sqlString, session: "poc/dummy" }; + const { google } = require('@google-cloud/spanner/build/protos/protos.js'); + const ExecuteSqlRequestProto = google.spanner.v1.ExecuteSqlRequest; + const serializedPb = ExecuteSqlRequestProto.encode(requestObj).finish(); + + // 2. Transmit the standard protobuf binary buffer over CGO FFI seamlessly + const handled = await invokeAsync( + Execute, + null, // Rows gets constructed afterward + null, + this.pool.oid, + this.oid, + serializedPb + ); + + return new Rows(this, handled.objectId); + } + + /** + * Release the connection back to the pool asynchronously + */ + async close() { + if (!this.closed) { + this.closed = true; + try { + await invokeAsync(CloseConnection, this, spannerLib, this.pool.oid, this.oid); + } finally { + spannerLib.unregister(this, this.pinnerId); + } + } + } +} + +module.exports = { Connection }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/pool.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/pool.js new file mode 100644 index 00000000..d7b811ae --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/pool.js @@ -0,0 +1,80 @@ +const { CreatePool, ClosePool } = require('../ffi/bindings.js'); +const { invokeAsync } = require('../ffi/utils.js'); +const { spannerLib } = require('./spannerlib.js'); +const { Connection } = require('./connection.js'); + +class Pool { + /** + * Initializes a Pool object by invoking the underlying CGO `CreatePool`. + * Because FFI async spans the Go initialization process, we use `static async create` + * to safely handle promises natively inside JS. + */ + static async create(userAgent, connectionString) { + const p = new Pool(); + const handled = await invokeAsync( + CreatePool, + p, // Ref instance for memory registry + spannerLib,// Our Memory manager + userAgent, + connectionString + ); + + p.oid = handled.objectId; + return p; + } + + constructor() { + /** + * The Object ID (OID). + * This is a unique identifier generated by the underlying Go Spanner driver + * to represent this specific Pool instance in its internal state map. + * We pass this OID back to Go when we execute operations (like executeSql) + * so Go knows which active Pool/Connection instance to use. + * @type {Number|null} + */ + this.oid = null; + + /** + * The Memory Pinner ID. + * Because Go Garbage Collection might move or delete objects currently + * being used by Node.js over FFI, Go "pins" the memory in place and + * returns a Pinner ID. We must explicitly invoke Go's `Release(pinnerId)` + * when this object is closed to prevent CGO memory leaks. + * @type {Number|null} + */ + this.pinnerId = null; + + /** + * State flag tracking whether this Pool has been explicitly closed. + * @type {Boolean} + */ + this.closed = false; + } + + /** + * Creates or borrows a new Connection within this Pool asynchronously. + * @returns {Promise} + */ + async createConnection() { + if (this.closed) throw new Error("Pool is already closed"); + return await Connection.create(this); + } + + /** + * Closes the underlying Go Spanner pool and explicitly drops memory pinned on Go's end. + */ + async close() { + if (!this.closed) { + this.closed = true; + try { + // Background execution of close logic + await invokeAsync(ClosePool, this, spannerLib, this.oid); + } finally { + // Explicitly unregister from the GC watcher, guaranteeing immediate cleanup + spannerLib.unregister(this, this.pinnerId); + } + } + } +} + +module.exports = { Pool }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/rows.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/rows.js new file mode 100644 index 00000000..9d0f089d --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/rows.js @@ -0,0 +1,72 @@ +const { CloseRows, Next } = require('../ffi/bindings.js'); +const { invokeAsync } = require('../ffi/utils.js'); +const { spannerLib } = require('./spannerlib.js'); +const { google } = require('@google-cloud/spanner/build/protos/protos.js'); + +class Rows { + /** + * @param {import('./connection.js').Connection} conn + * @param {Number} objectId - The OID identifying these rows inside the Go Driver + */ + constructor(conn, objectId) { + this.conn = conn; + + /** + * The Object ID (OID). + * Used to execute operations like `.next()` against THIS specific ResultSet inside Go. + * @type {Number|null} + */ + this.oid = objectId; + + this.closed = false; + + // FinalizationRegistry could optionally be mapped to this via + // spannerLib.register(this, pinnerId_from_execute) + // For the POC, we won't fully map the Rows Pinner unless needed + // by the Next() function iterator. + } + + /** + * Iterates to the next result chunk. + * In a full implementation, it would call `Next(poolId, connId, rowsId, ...)` natively. + */ + async next() { + if (this.closed) throw new Error("Rows object is already closed"); + + // Go Signature: Next(poolId, connId, rowsId, numRows, encodeRowOption) + // We pass 1 for numRows, and 0 for encodeRowOption as per POC defaults + const handled = await invokeAsync(Next, null, null, this.conn.pool.oid, this.conn.oid, this.oid, 1, 0); + + // Handle EOF case (The chunk buffer is perfectly empty or contains no message) + if (!handled.protobufBytes || handled.protobufBytes.length === 0) { + return null; // Signals end of rows to the caller + } + + // The returned message contains a google.protobuf.ListValue according to the spec! + // We natively unpack those bytes matching standard Protobuf conventions. + const listValueProto = google.protobuf.ListValue; + const decodedList = listValueProto.decode(handled.protobufBytes); + + // This converts the complex generic Protobuf ListValue deeply into native Javascript! + const jsonRecord = listValueProto.toObject(decodedList, { + longs: String, // Ensure Int64 types from Spanner decode as Strings instead of mangled JS doubles + enums: String, + bytes: String, + }); + + return jsonRecord.values || []; + } + + /** + * Closes the rows object safely, waiting on the network. + */ + async close() { + if (!this.closed) { + this.closed = true; + // Native FFI execution in the background + await invokeAsync(CloseRows, null, spannerLib, this.conn.pool.oid, this.conn.oid, this.oid); + } + } +} + +module.exports = { Rows }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/spannerlib.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/spannerlib.js new file mode 100644 index 00000000..7f070d1e --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/spannerlib.js @@ -0,0 +1,51 @@ +const { Release } = require('../ffi/utils.js'); + +class SpannerLib { + constructor() { + this.activePinners = new Set(); + + // FinalizationRegistry automatically guarantees that V8 Garbage Collection + // dropping an object triggers this callback, where we gracefully + // wipe the matching Go pointer from memory via `Release(id)`. + this.registry = new FinalizationRegistry((pinnerId) => { + if (pinnerId && pinnerId > 0) { + Release(pinnerId); + this.activePinners.delete(pinnerId); + } + }); + } + + /** + * Registers a JavaScript object with this Memory Tracker. + * When JS garbage collects `refInstance`, `pinnerId` is automatically natively released. + */ + register(refInstance, pinnerId) { + if (pinnerId > 0) { + this.activePinners.add(pinnerId); + this.registry.register(refInstance, pinnerId, refInstance); + } + } + + unregister(refInstance, pinnerId) { + if (pinnerId > 0) { + Release(pinnerId); + this.registry.unregister(refInstance); + this.activePinners.delete(pinnerId); + } + } + + /** + * Fallback shutdown function to crash-stop everything not collected yet. + */ + releaseAll() { + for (const pinnerId of this.activePinners) { + Release(pinnerId); + } + this.activePinners.clear(); + } +} + +// Global Singleton +const spannerLib = new SpannerLib(); + +module.exports = { spannerLib }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test-db.txt b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test-db.txt new file mode 100644 index 00000000..89c9bdd6 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test-db.txt @@ -0,0 +1 @@ +test-db-koffi-136 \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test.js new file mode 100644 index 00000000..62de5264 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test.js @@ -0,0 +1,58 @@ +const { Pool, cleanup } = require('./index.js'); +const { performance } = require('perf_hooks'); +const fs = require('fs'); + +async function runTest() { + console.log("=================================================="); + console.log(" Spanner Shared Library POC (PRODUCTION ASYNC) "); + console.log("==================================================\n"); + + let pool, connection, rows; + + // Read the database name created by setup_db.js + let dbName = "dummy-testing-db"; + try { + dbName = fs.readFileSync('./test-db.txt', 'utf8').trim(); + } catch (e) { } + + const dbPath = `projects/span-cloud-testing/instances/gargsurbhi-testing/databases/${dbName}`; + + try { + console.log(`[JS-App] 1. Creating Pool attached to: \n -> ${dbPath}`); + pool = await Pool.create("nodejs-koffi-poc", dbPath); + console.log(`Pool created: OID ${pool.oid}`); + + console.log("\n[JS-App] 2. Creating Database Connection..."); + connection = await pool.createConnection(); + console.log(`Connection created: OID ${connection.oid}`); + + console.log("\n[JS-App] 3. Executing SQL using pure Nodejs @google-cloud/spanner Protobufs..."); + const sqlQuery = "SELECT SingerId, FirstName, Balance, IsActive FROM Singers"; + console.log(` -> Serializing FFI payload for: "${sqlQuery}"`); + + const startTime = performance.now(); + rows = await connection.executeSql(sqlQuery); + console.log(`Executed SQL successfully in ${(performance.now() - startTime).toFixed(3)}ms (Rows OID: ${rows.oid})`); + + console.log("\n[JS-App] 4. Fetching ResultSet Native Types (Int, String, Float, Bool)..."); + let nextRow; + while ((nextRow = await rows.next()) !== null) { + // nextRow is an array of Value protobuf objects (Google Protobuf Structs) + console.log(" - Fetched native row chunk ->"); + console.log(" " + JSON.stringify(nextRow)); + } + + } catch (err) { + console.error("Test execution caught an expected Native Error:"); + console.error(" -> " + err.message); + } finally { + console.log("\n[JS-App] 5. Graceful Async Cleanup..."); + if (rows) await rows.close(); + if (connection) await connection.close(); + if (pool) await pool.close(); + cleanup(); + console.log("Cleaned up gracefully."); + } +} + +runTest().catch(console.error); From 978eca7b59fbecb55bb8bde9d7d5f5ef3fbab899 Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Tue, 7 Apr 2026 16:03:52 +0530 Subject: [PATCH 3/9] IPC changes --- spannerlib/grpc-server/build-protos.sh | 31 +- .../spannerlib-nodejs-poc/ipc/README.md | 32 + .../spannerlib-nodejs-poc/ipc/index.js | 9 + .../ipc/package-lock.json | 1964 +++++++++++++++++ .../spannerlib-nodejs-poc/ipc/package.json | 21 +- .../spannerlib-nodejs-poc/ipc/setup_db.js | 46 + .../ipc/src/grpc/bindings.js | 35 + .../ipc/src/grpc/utils.js | 21 + .../ipc/src/lib/connection.js | 52 + .../spannerlib-nodejs-poc/ipc/src/lib/pool.js | 33 + .../spannerlib-nodejs-poc/ipc/src/lib/rows.js | 86 + .../spannerlib-nodejs-poc/ipc/test-db.txt | 1 + .../spannerlib-nodejs-poc/ipc/test.js | 67 + .../spannerlib-nodejs-poc/koffi/package.json | 2 +- 14 files changed, 2387 insertions(+), 13 deletions(-) create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/README.md create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/index.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package-lock.json create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/setup_db.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/grpc/bindings.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/grpc/utils.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/connection.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/pool.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/rows.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/test-db.txt create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/ipc/test.js diff --git a/spannerlib/grpc-server/build-protos.sh b/spannerlib/grpc-server/build-protos.sh index c91a4862..e29827fe 100755 --- a/spannerlib/grpc-server/build-protos.sh +++ b/spannerlib/grpc-server/build-protos.sh @@ -1,13 +1,31 @@ +#!/bin/bash + PATH="${PATH}:${HOME}/go/bin" -git submodule add git@github.com:googleapis/googleapis.git -ln -sf "${PWD}"/google/spannerlib googleapis/google/spannerlib + +# 1. Clean up and fetch dependencies +# We DO NOT delete googleapis at the end because Node.js needs it at runtime +if [ ! -d "googleapis" ]; then + echo "Fetching dependency protos..." + git clone --depth 1 https://github.com/googleapis/googleapis.git +fi + +# Link local proto into the structure +mkdir -p googleapis/google/spannerlib/v1 +ln -sf "${PWD}/google/spannerlib/v1/spannerlib.proto" "googleapis/google/spannerlib/v1/spannerlib.proto" + cd googleapis || exit 1 + +# 2. Go generation +echo "Generating Go..." protoc \ --go_out=../ \ --go_opt=paths=source_relative \ --go-grpc_out=../ \ --go-grpc_opt=paths=source_relative \ google/spannerlib/v1/spannerlib.proto + +# 3. Java generation +echo "Generating Java..." protoc \ --java_out=../../wrappers/spannerlib-java/src/main/java/ \ --plugin=protoc-gen-java-grpc=/Users/loite/protoc-gen-grpc-java-1.75.0-osx-aarch_64.exe \ @@ -15,7 +33,8 @@ protoc \ --java-grpc_opt=paths=source_relative \ google/spannerlib/v1/spannerlib.proto -# dotnet add package Grpc.Tools --version 2.76.0 +# 4. C# generation +echo "Generating C#..." protoc \ --csharp_out=../../wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/ \ --plugin=protoc-gen-csharp_grpc=/Users/loite/.nuget/packages/grpc.tools/2.76.0/tools/macosx_x64/grpc_csharp_plugin \ @@ -24,7 +43,7 @@ protoc \ --csharp_grpc_opt=no_server \ --proto_path=. \ google/spannerlib/v1/spannerlib.proto + cd .. || exit 1 -rm googleapis/google/spannerlib -git rm googleapis -f -rm ../../.gitmodules +echo "Code generation complete for Go, Java, and C#." +echo "Node.js will use dynamic loading via @grpc/proto-loader." diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/README.md b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/README.md new file mode 100644 index 00000000..f85f119d --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/README.md @@ -0,0 +1,32 @@ +# Spanner NodeJS gRPC/IPC Wrapper + +This directory contains a proof-of-concept for a NodeJS wrapper for the Go Spanner library that uses IPC via a gRPC client to communicate with a Go gRPC server. + +## Architecture + +The wrapper consists of three main parts: + +1. **Go gRPC Server**: A server written in Go that exposes the Spanner library's functionality over a gRPC interface. This server is located in `spannerlib/grpc-server`. It must be running for this wrapper to function. + +2. **Node.js gRPC Client**: A client written in Node.js that communicates with the Go gRPC server. It uses the `@grpc/grpc-js` and `@grpc/proto-loader` packages to interact with the server. The client is defined in `src/grpc/`. + +3. **JavaScript Wrapper**: A high-level JavaScript API that provides `Pool`, `Connection`, and `Rows` classes. This abstracts away the gRPC communication and provides a clean, async/await-based interface that is identical to the Koffi and N-API POCs. + +## How to Run + +1. **Start the Go gRPC server**: + ```sh + cd spannerlib/grpc-server + go run server.go localhost:50051 tcp + ``` + +2. **Install Node.js dependencies**: + ```sh + cd spannerlib/wrappers/spannerlib-nodejs-poc/ipc + npm install + ``` + +3. **Run the test**: + ```sh + npm test + ``` diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/index.js b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/index.js new file mode 100644 index 00000000..d119a11f --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/index.js @@ -0,0 +1,9 @@ +const { Pool } = require('./src/lib/pool.js'); +const { Connection } = require('./src/lib/connection.js'); +const { Rows } = require('./src/lib/rows.js'); + +module.exports = { + Pool, + Connection, + Rows +}; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package-lock.json b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package-lock.json new file mode 100644 index 00000000..ab597553 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package-lock.json @@ -0,0 +1,1964 @@ +{ + "name": "ipc-spanner", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ipc-spanner", + "version": "1.0.0", + "dependencies": { + "@grpc/grpc-js": "^1.10.1", + "@grpc/proto-loader": "^0.7.3", + "google-protobuf": "^3.21.2" + }, + "devDependencies": { + "@google-cloud/spanner": "^7.19.1", + "grpc-tools": "^1.12.4" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@google-cloud/common": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-5.0.2.tgz", + "integrity": "sha512-V7bmBKYQyu0eVG2BFejuUjlBt+zrya6vtsKdY+JxMM/dNntPF41vZ9+LhOshEUH01zOHEqBSvI7Dad7ZS6aUeA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "^4.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "extend": "^3.0.2", + "google-auth-library": "^9.0.0", + "html-entities": "^2.5.2", + "retry-request": "^7.0.0", + "teeny-request": "^9.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/precise-date": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-4.0.0.tgz", + "integrity": "sha512-1TUx3KdaU3cN7nfCdNf+UVqA/PSX29Cjcox3fZZBtINlRrXVTmUkQnCKv2MbBUbCopbK4olAT1IHl76uZyCiVA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/projectify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", + "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/promisify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz", + "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@google-cloud/spanner": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@google-cloud/spanner/-/spanner-7.21.0.tgz", + "integrity": "sha512-SrlHgXmSaEbGhdimxcB0FgNsW9J931JBBveoGW43clQHVNcDJuKRoG+240inbSRZoW8JIwwEHToXYU5YGO3VGg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/common": "^5.0.0", + "@google-cloud/precise-date": "^4.0.0", + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "4.0.0", + "@grpc/proto-loader": "^0.7.0", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.26.0", + "@opentelemetry/core": "^1.27.0", + "@opentelemetry/semantic-conventions": "^1.25.1", + "@types/big.js": "^6.0.0", + "@types/stack-trace": "0.0.33", + "arrify": "^2.0.0", + "big.js": "^6.0.0", + "checkpoint-stream": "^0.1.1", + "duplexify": "^4.1.1", + "events-intercept": "^2.0.0", + "extend": "^3.0.2", + "google-auth-library": "^9.0.0", + "google-gax": "4.4.1", + "grpc-gcp": "^1.0.0", + "is": "^3.2.1", + "lodash.snakecase": "^4.1.1", + "merge-stream": "^2.0.0", + "p-queue": "^6.0.2", + "protobufjs": "^7.0.0", + "retry-request": "^7.0.0", + "split-array-stream": "^2.0.0", + "stack-trace": "0.0.10", + "stream-events": "^1.0.4", + "teeny-request": "^9.0.0", + "through2": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", + "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", + "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.3", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz", + "integrity": "sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "consola": "^3.2.3", + "detect-libc": "^2.0.0", + "https-proxy-agent": "^7.0.5", + "node-fetch": "^2.6.7", + "nopt": "^8.0.0", + "semver": "^7.5.3", + "tar": "^7.4.0" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.30.1.tgz", + "integrity": "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", + "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", + "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@types/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-e2cOW9YlVzFY2iScnGBBkplKsrn2CsObHQ2Hiw4V1sSyiGbgWL8IyqE3zFi1Pt5o1pdAtYkDAIsF3KKUPjdzaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/caseless": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", + "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/duplexify": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.5.tgz", + "integrity": "sha512-fB56ACzlW91UdZ5F3VXplVMDngO8QaX5Y2mjvADtN01TT2TMy4WjF0Lg+tFDvt4uMBeTe4SgaD+qCrA7dL5/tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", + "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/pumpify": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/pumpify/-/pumpify-1.4.5.tgz", + "integrity": "sha512-BGVAQyK5yJdfIII230fVYGY47V63hUNAhryuuS3b4lEN2LNwxUXFKsEf8QLDCjmZuimlj23BHppJgcrGvNtqKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/duplexify": "*", + "@types/node": "*" + } + }, + "node_modules/@types/request": { + "version": "2.48.13", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.13.tgz", + "integrity": "sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.5" + } + }, + "node_modules/@types/stack-trace": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.33.tgz", + "integrity": "sha512-O7in6531Bbvlb2KEsJ0dq0CHZvc3iWSR5ZYMtvGgnHA56VgriAN/AU2LorfmcvAl2xc9N5fbCTRyMRRl8nd74g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/checkpoint-stream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/checkpoint-stream/-/checkpoint-stream-0.1.2.tgz", + "integrity": "sha512-eYXIcydL3mPjjEVLxHdi1ISgTwmxGJZ8vyJ3lYVvFTDRyTOZMTbKZdRJqiA7Gi1rPcwOyyzcrZmGLL8ff7e69w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/pumpify": "^1.4.1", + "events-intercept": "^2.0.0", + "pumpify": "^1.3.5", + "split-array-stream": "^1.0.0", + "through2": "^2.0.3" + } + }, + "node_modules/checkpoint-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/checkpoint-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/checkpoint-stream/node_modules/split-array-stream": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/split-array-stream/-/split-array-stream-1.0.3.tgz", + "integrity": "sha512-yGY35QmZFzZkWZ0eHE06RPBi63umym8m+pdtuC/dlO1ADhdKSfCj0uNn87BYCXBBDFxyTq4oTw0BgLYT0K5z/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^2.4.0", + "is-stream-ended": "^0.1.0" + } + }, + "node_modules/checkpoint-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/checkpoint-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=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==", + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/events-intercept": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/events-intercept/-/events-intercept-2.0.0.tgz", + "integrity": "sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/form-data": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz", + "integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/google-auth-library": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-gax": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz", + "integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.10.9", + "@grpc/proto-loader": "^0.7.13", + "@types/long": "^4.0.0", + "abort-controller": "^3.0.0", + "duplexify": "^4.0.0", + "google-auth-library": "^9.3.0", + "node-fetch": "^2.7.0", + "object-hash": "^3.0.0", + "proto3-json-serializer": "^2.0.2", + "protobufjs": "^7.3.2", + "retry-request": "^7.0.0", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/google-protobuf": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.4.tgz", + "integrity": "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==", + "license": "(BSD-3-Clause AND Apache-2.0)" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/grpc-gcp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/grpc-gcp/-/grpc-gcp-1.0.1.tgz", + "integrity": "sha512-06r73IoGaAIpzT+DRPnw7V5BXvZ5mjy1OcKqSPX+ZHOgbLxT+lJfz8IN83z/sbA3t55ZX88MfDaaCjDGdveVIA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/grpc-tools": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/grpc-tools/-/grpc-tools-1.13.1.tgz", + "integrity": "sha512-0sttMUxThNIkCTJq5qI0xXMz5zWqV2u3yG1kR3Sj9OokGIoyRBFjoInK9NyW7x5fH7knj48Roh1gq5xbl0VoDQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^2.0.0" + }, + "bin": { + "grpc_tools_node_protoc": "bin/protoc.js", + "grpc_tools_node_protoc_plugin": "bin/protoc_plugin.js" + } + }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.2.tgz", + "integrity": "sha512-a2xr4E3s1PjDS8ORcGgXpWx6V+liNs+O3JRD2mb9aeugD7rtkkZ0zgLdYgw0tWsKhsdiezGYptSiMlVazCBTuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/proto3-json-serializer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz", + "integrity": "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "protobufjs": "^7.2.5" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/protobufjs": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/pumpify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/pumpify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/pumpify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/retry-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", + "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/request": "^2.48.8", + "extend": "^3.0.2", + "teeny-request": "^9.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/split-array-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/split-array-stream/-/split-array-stream-2.0.0.tgz", + "integrity": "sha512-hmMswlVY91WvGMxs0k8MRgq8zb2mSen4FmDNc5AFiTWtrBpdZN6nwD6kROVe4vNL+ywrvbCKsWVCnEd4riELIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream-ended": "^0.1.4" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "dev": true, + "license": "MIT", + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tar": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", + "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/teeny-request": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", + "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.9", + "stream-events": "^1.0.5", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/teeny-request/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/teeny-request/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/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==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package.json b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package.json index 4e5cedba..549dd8cc 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package.json +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/package.json @@ -1,12 +1,21 @@ { - "name": "ipc", + "name": "ipc-spanner", "version": "1.0.0", "main": "index.js", + "engines": { + "node": ">=20.0.0" + }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "node test.js", + "setup": "node setup_db.js" + }, + "dependencies": { + "@grpc/grpc-js": "^1.10.1", + "google-protobuf": "^3.21.2", + "@grpc/proto-loader": "^0.7.3" }, - "keywords": [], - "author": "", - "license": "ISC", - "description": "" + "devDependencies": { + "@google-cloud/spanner": "^7.19.1", + "grpc-tools": "^1.12.4" + } } diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/setup_db.js b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/setup_db.js new file mode 100644 index 00000000..2387d2ca --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/setup_db.js @@ -0,0 +1,46 @@ +const { Spanner } = require('@google-cloud/spanner'); + +const projectId = 'span-cloud-testing'; +const instanceId = 'gargsurbhi-testing'; +const databaseId = `test-db-ipc-${Math.floor(Math.random() * 1000)}`; + +const spanner = new Spanner({ projectId }); +const instance = spanner.instance(instanceId); + +async function setupDatabase() { + console.log(`Setting up Spanner Database: ${databaseId}...`); + try { + const [database, operation] = await instance.createDatabase(databaseId, { + schema: [ + `CREATE TABLE Singers ( + SingerId INT64 NOT NULL, + FirstName STRING(1024), + LastName STRING(1024), + IsActive BOOL, + Balance FLOAT64 + ) PRIMARY KEY (SingerId)` + ], + }); + + console.log(`Database creation initiated. Waiting for operation...`); + await operation.promise(); + console.log(`Database ${database.id} created with Schema.`); + + console.log('Inserting dummy data...'); + const table = database.table('Singers'); + await table.insert([ + { SingerId: 1, FirstName: 'Marc', LastName: 'Richards', IsActive: true, Balance: 100.50 }, + { SingerId: 2, FirstName: 'Catalina', LastName: 'Smith', IsActive: false, Balance: 250.75 }, + { SingerId: 3, FirstName: 'Alice', LastName: 'Trentor', IsActive: true, Balance: 0.10 } + ]); + console.log('Dummy data inserted successfully!'); + + // Save DB name to file so the test can pick it up + require('fs').writeFileSync('./test-db.txt', databaseId); + + } catch (err) { + console.error('ERROR:', err); + } +} + +setupDatabase().catch(console.error); diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/grpc/bindings.js b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/grpc/bindings.js new file mode 100644 index 00000000..5d8a8a74 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/grpc/bindings.js @@ -0,0 +1,35 @@ +const grpc = require('@grpc/grpc-js'); +const protoLoader = require('@grpc/proto-loader'); +const path = require('path'); + +// Define paths to the proto and the googleapis dependency folder +// Note: Adjusted to point from 'ipc/src/grpc/bindings.js' back to 'grpc-server/' +const PROTO_ROOT = path.resolve(__dirname, '../../../../../grpc-server'); +const PROTO_PATH = path.join(PROTO_ROOT, 'google/spannerlib/v1/spannerlib.proto'); +const GOOGLEAPIS_PATH = path.join(PROTO_ROOT, 'googleapis'); + +// Load the proto file at runtime +const packageDefinition = protoLoader.loadSync(PROTO_PATH, { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + includeDirs: [GOOGLEAPIS_PATH, PROTO_ROOT] // Resolves all 'google/api/...' imports +}); + +// Load the package definition into gRPC +const protoDescriptor = grpc.loadPackageDefinition(packageDefinition); + +// The SpannerLib service definition is now available through the descriptor +const SpannerLib = protoDescriptor.google.spannerlib.v1.SpannerLib; + +const client = new SpannerLib('localhost:50051', grpc.credentials.createInsecure()); + +// We export the v1 package which contains all message constructors (CommitRequest, etc.) +const messages = protoDescriptor.google.spannerlib.v1; + +module.exports = { + client, + messages +}; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/grpc/utils.js b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/grpc/utils.js new file mode 100644 index 00000000..3e814137 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/grpc/utils.js @@ -0,0 +1,21 @@ +const { client, messages } = require('./bindings'); +const { Status } = require('@grpc/grpc-js/build/src/constants'); + +function invokeAsync(funcName, request) { + return new Promise((resolve, reject) => { + // Bind the method to the client instance to preserve `this` context. + const method = client[funcName].bind(client); + method(request, (err, response) => { + if (err) { + // gRPC returns an error object, not a non-zero status code on error. + return reject(new Error(err.details || `gRPC Error Code: ${err.code}`)); + } + resolve(response); + }); + }); +} + +module.exports = { + invokeAsync, + messages +}; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/connection.js b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/connection.js new file mode 100644 index 00000000..4baced42 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/connection.js @@ -0,0 +1,52 @@ +const { invokeAsync } = require('../grpc/utils'); +const { Rows } = require('./rows'); + +class Connection { + constructor(pool, connectionId) { + this.pool = pool; + this.connectionId = connectionId; + } + + async execute(sql) { + const executeRequest = { + connection: { + pool: { id: this.pool.poolId }, + id: this.connectionId + }, + execute_sql_request: { + sql: sql + } + }; + // 1. Execute the SQL to get a Rows identifier + const rowsResult = await invokeAsync('execute', executeRequest); + const rowsId = rowsResult.id; + + // 2. Create the request object for the metadata call + const metadataRequest = { + connection: { + pool: { id: this.pool.poolId }, + id: this.connectionId + }, + id: rowsId + }; + // 3. Fetch the metadata to get column names + const metadata = await invokeAsync('metadata', metadataRequest); + + // 4. Extract the column names from the metadata response + const columnNames = metadata.row_type.fields.map(field => field.name); + + // 5. Return a new Rows object, now equipped with the column names + return new Rows(this, rowsId, columnNames); + } + + async close() { + const request = { + pool: { id: this.pool.poolId }, + id: this.connectionId + }; + await invokeAsync('closeConnection', request); + this.connectionId = null; + } +} + +module.exports = { Connection }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/pool.js b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/pool.js new file mode 100644 index 00000000..aa743e30 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/pool.js @@ -0,0 +1,33 @@ +const { invokeAsync } = require('../grpc/utils'); +const { Connection } = require('./connection'); + +class Pool { + constructor(poolId) { + this.poolId = poolId; + } + + static async create(connectionString, userAgent) { + const request = { + connection_string: connectionString, + user_agent_suffix: userAgent, + }; + const res = await invokeAsync('createPool', request); + return new Pool(res.id); + } + + async createConnection() { + const request = { + pool: { id: this.poolId } + }; + const res = await invokeAsync('createConnection', request); + return new Connection(this, res.id); + } + + async close() { + const request = { id: this.poolId }; + await invokeAsync('closePool', request); + this.poolId = null; + } +} + +module.exports = { Pool }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/rows.js b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/rows.js new file mode 100644 index 00000000..07aa176f --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/src/lib/rows.js @@ -0,0 +1,86 @@ +const { invokeAsync } = require('../grpc/utils'); + +const ENCODING_PROTOBUF = 1; + +/** + * Parses a `ListValue` plain object and a list of column names into a + * single key-value row object. + * @param {object} listValue The ListValue object from the gRPC response. + * @param {string[]} columnNames An array of column names from the metadata. + * @returns {object|null} A key-value object representing the row, or null. + */ +function parseRowToObject(listValue, columnNames) { + if (!listValue || !listValue.values || listValue.values.length === 0) { + return null; // This signifies the end of the result set. + } + + const rowObject = {}; + listValue.values.forEach((value, index) => { + const columnName = columnNames[index]; + const kind = value.kind; + let parsedValue; + + switch (kind) { + case 'nullValue': + parsedValue = null; + break; + case 'numberValue': + parsedValue = value.numberValue; + break; + case 'stringValue': + parsedValue = value.stringValue; + break; + case 'boolValue': + parsedValue = value.boolValue; + break; + default: + parsedValue = undefined; + } + rowObject[columnName] = parsedValue; + }); + return rowObject; +} + +class Rows { + constructor(connection, rowsId, columnNames) { + this.connection = connection; + this.rowsId = rowsId; + this.columnNames = columnNames; // Store the column names + } + + /** + * Fetches the next row from the result set. + * @returns {Promise} A promise that resolves to a row object, or null if there are no more rows. + */ + async next() { + const request = { + rows: { + connection: { + pool: { id: this.connection.pool.poolId }, + id: this.connection.connectionId + }, + id: this.rowsId + }, + fetch_options: { + num_rows: 1, // Always fetch one row at a time. + encoding: ENCODING_PROTOBUF + } + }; + const res = await invokeAsync('next', request); + return parseRowToObject(res, this.columnNames); + } + + async close() { + const request = { + connection: { + pool: { id: this.connection.pool.poolId }, + id: this.connection.connectionId + }, + id: this.rowsId + }; + await invokeAsync('closeRows', request); + this.rowsId = null; + } +} + +module.exports = { Rows }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/test-db.txt b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/test-db.txt new file mode 100644 index 00000000..b81840bc --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/test-db.txt @@ -0,0 +1 @@ +test-db-ipc-975 \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/test.js b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/test.js new file mode 100644 index 00000000..d2f5ed70 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/ipc/test.js @@ -0,0 +1,67 @@ +const { Pool } = require('./index.js'); +const { performance } = require('perf_hooks'); +const fs = require('fs'); + +async function runTest() { + console.log("=================================================="); + console.log(" Spanner NodeJS gRPC/IPC Wrapper Test "); + console.log("==================================================\n"); + + let pool, connection, rows; + + // Read the database name created by setup_db.js + let dbName = "dummy-testing-db"; + try { + dbName = fs.readFileSync('./test-db.txt', 'utf8').trim(); + } catch (e) { + console.log("test-db.txt not found, using default. Run `npm run setup` to create a new test database."); + } + + const dbPath = `projects/span-cloud-testing/instances/gargsurbhi-testing/databases/${dbName}`; + + try { + console.log(`[JS-App] 1. Creating Pool attached to: \n -> ${dbPath}`); + pool = await Pool.create(dbPath, "nodejs-ipc-poc"); + console.log(`Pool created: ID ${pool.poolId}`); + + console.log("\n[JS-App] 2. Creating Database Connection..."); + connection = await pool.createConnection(); + console.log(`Connection created: ID ${connection.connectionId}`); + + console.log("\n[JS-App] 3. Executing SQL..."); + const sqlQuery = "SELECT SingerId, FirstName, Balance, IsActive FROM Singers"; + console.log(` -> Query: "${sqlQuery}"`); + + const startTime = performance.now(); + rows = await connection.execute(sqlQuery); + console.log(`Executed SQL successfully in ${(performance.now() - startTime).toFixed(3)}ms (Rows ID: ${rows.rowsId})`); + + console.log("\n[JS-App] 4. Fetching result set..."); + let row; + const results = []; + while ((row = await rows.next()) !== null) { + results.push(row); + } + + console.log(" - Fetched rows ->"); + console.log(JSON.stringify(results, null, 2)); + + // Example of accessing a property on the first row + if (results.length > 0) { + console.log(`\nExample access: results[0].FirstName is "${results[0].FirstName}"`); + } + + } catch (err) { + console.error("Test execution failed:"); + console.error(" -> " + err.message); + console.error(err.stack); + } finally { + console.log("\n[JS-App] 5. Graceful Cleanup..."); + if (rows) await rows.close(); + if (connection) await connection.close(); + if (pool) await pool.close(); + console.log("Cleaned up gracefully."); + } +} + +runTest().catch(console.error); diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package.json b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package.json index 93eb6ab8..9926d836 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package.json +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/package.json @@ -6,7 +6,7 @@ "node": ">=20.0.0" }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "node test.js" }, "keywords": [], "author": "", From b70dd93c934454152b52d5a30c2ff9c63e4ad6b5 Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Thu, 9 Apr 2026 11:16:52 +0530 Subject: [PATCH 4/9] koffi with metadata method --- .../koffi/src/ffi/bindings.js | 1 + .../koffi/src/ffi/utils.js | 5 + .../koffi/src/lib/connection.js | 30 ++++- .../koffi/src/lib/rows.js | 125 +++++++++++------- .../spannerlib-nodejs-poc/koffi/test.js | 19 ++- 5 files changed, 121 insertions(+), 59 deletions(-) diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/bindings.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/bindings.js index f0e5a656..fbaa1f19 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/bindings.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/bindings.js @@ -40,6 +40,7 @@ module.exports = { CreateConnection: lib.func('CreateConnection', GoReturnTuple, ['int64']), CloseConnection: lib.func('CloseConnection', GoReturnTuple, ['int64', 'int64']), Execute: lib.func('Execute', GoReturnTuple, ['int64', 'int64', GoSlice]), + Metadata: lib.func('Metadata', GoReturnTuple, ['int64', 'int64', 'int64']), Next: lib.func('Next', GoReturnTuple, ['int64', 'int64', 'int64', 'int32', 'int32']), CloseRows: lib.func('CloseRows', GoReturnTuple, ['int64', 'int64', 'int64']), Release: lib.func('Release', 'int32', ['int64']) diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/utils.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/utils.js index ed72b80a..b2a236ea 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/utils.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/ffi/utils.js @@ -1,5 +1,8 @@ const { koffi } = require('./bindings.js'); +const ENCODING_JSON = 0; +const ENCODING_PROTOBUF = 1; + class SpannerLibError extends Error { constructor(code, message) { super(`Spanner Native Error (Code ${code}): ${message}`); @@ -67,6 +70,8 @@ function invokeAsync(koffiFunc, refInstance, pinManager, ...args) { } module.exports = { + ENCODING_JSON, + ENCODING_PROTOBUF, SpannerLibError, toGoString, toGoSlice, diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/connection.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/connection.js index a7e4955a..94e5d746 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/connection.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/connection.js @@ -1,4 +1,4 @@ -const { CreateConnection, CloseConnection, Execute } = require('../ffi/bindings.js'); +const { CreateConnection, CloseConnection, Execute, Metadata } = require('../ffi/bindings.js'); const { toGoSlice, invokeAsync } = require('../ffi/utils.js'); const { spannerLib } = require('./spannerlib.js'); const { Rows } = require('./rows.js'); @@ -56,17 +56,37 @@ class Connection { const ExecuteSqlRequestProto = google.spanner.v1.ExecuteSqlRequest; const serializedPb = ExecuteSqlRequestProto.encode(requestObj).finish(); - // 2. Transmit the standard protobuf binary buffer over CGO FFI seamlessly - const handled = await invokeAsync( + // 1. Execute the SQL to get a Rows identifier + const rowsResult = await invokeAsync( Execute, - null, // Rows gets constructed afterward + null, null, this.pool.oid, this.oid, toGoSlice(serializedPb) ); + const rowsId = rowsResult.objectId; + + // 2. Fetch the metadata to get column names + const metadataResult = await invokeAsync( + Metadata, + null, + null, + this.pool.oid, + this.oid, + rowsId + ); + + // 3. Decode the metadata protobuf to get column names and types + const ResultSetMetadataProto = google.spanner.v1.ResultSetMetadata; + const metadata = ResultSetMetadataProto.decode(metadataResult.protobufBytes); + const columnInfo = metadata.rowType.fields.map(field => ({ + name: field.name, + typeCode: field.type.code + })); - return new Rows(this, handled.objectId); + // 4. Return a new Rows object, now equipped with the column info + return new Rows(this, rowsId, columnInfo); } /** diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/rows.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/rows.js index 9d0f089d..abdadd92 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/rows.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/src/lib/rows.js @@ -1,70 +1,99 @@ -const { CloseRows, Next } = require('../ffi/bindings.js'); -const { invokeAsync } = require('../ffi/utils.js'); +const { Next, CloseRows } = require('../ffi/bindings.js'); +const { invokeAsync, ENCODING_PROTOBUF } = require('../ffi/utils.js'); const { spannerLib } = require('./spannerlib.js'); const { google } = require('@google-cloud/spanner/build/protos/protos.js'); +const ListValue = google.protobuf.ListValue; +const Value = google.protobuf.Value; + +/** + * Parses a binary `ListValue` protobuf message into a key-value row object, + * using type information from the query metadata. + * @param {Buffer} buffer The binary buffer from the Go library. + * @param {Array<{name: string, typeCode: number}>} columnInfo An array of objects with column names and types. + * @returns {object|null} + */ +function parseRowToObject(buffer, columnInfo) { + if (!buffer || buffer.length === 0) { + return null; // End of result set + } + + const listValue = ListValue.decode(buffer); + const rowObject = {}; + const values = listValue.values; + + columnInfo.forEach((column, index) => { + const value = values[index]; + const columnName = column.name; + let parsedValue; + + // The decoded `value` object has a 'kind' oneof field. + // We check which property is set to get the primitive value. + switch (value.kind) { + case 'nullValue': + parsedValue = null; + break; + case 'numberValue': + parsedValue = value.numberValue; + break; + case 'stringValue': + parsedValue = value.stringValue; + break; + case 'boolValue': + parsedValue = value.boolValue; + break; + default: + parsedValue = undefined; + } + rowObject[columnName] = parsedValue; + }); + + return rowObject; +} class Rows { /** - * @param {import('./connection.js').Connection} conn - * @param {Number} objectId - The OID identifying these rows inside the Go Driver + * @param {import('./connection.js').Connection} connection + * @param {Number} oid + * @param {Array<{name: string, typeCode: number}>} columnInfo */ - constructor(conn, objectId) { - this.conn = conn; - - /** - * The Object ID (OID). - * Used to execute operations like `.next()` against THIS specific ResultSet inside Go. - * @type {Number|null} - */ - this.oid = objectId; - + constructor(connection, oid, columnInfo) { + this.connection = connection; + this.oid = oid; + this.pinnerId = null; this.closed = false; - - // FinalizationRegistry could optionally be mapped to this via - // spannerLib.register(this, pinnerId_from_execute) - // For the POC, we won't fully map the Rows Pinner unless needed - // by the Next() function iterator. + this.columnInfo = columnInfo; // Store column names and types } /** - * Iterates to the next result chunk. - * In a full implementation, it would call `Next(poolId, connId, rowsId, ...)` natively. + * Fetches the next row from the result set. + * @returns {Promise} A promise that resolves to a row object, or null if there are no more rows. */ async next() { - if (this.closed) throw new Error("Rows object is already closed"); - - // Go Signature: Next(poolId, connId, rowsId, numRows, encodeRowOption) - // We pass 1 for numRows, and 0 for encodeRowOption as per POC defaults - const handled = await invokeAsync(Next, null, null, this.conn.pool.oid, this.conn.oid, this.oid, 1, 0); - - // Handle EOF case (The chunk buffer is perfectly empty or contains no message) - if (!handled.protobufBytes || handled.protobufBytes.length === 0) { - return null; // Signals end of rows to the caller - } - - // The returned message contains a google.protobuf.ListValue according to the spec! - // We natively unpack those bytes matching standard Protobuf conventions. - const listValueProto = google.protobuf.ListValue; - const decodedList = listValueProto.decode(handled.protobufBytes); + if (this.closed) throw new Error("Rows are already closed"); - // This converts the complex generic Protobuf ListValue deeply into native Javascript! - const jsonRecord = listValueProto.toObject(decodedList, { - longs: String, // Ensure Int64 types from Spanner decode as Strings instead of mangled JS doubles - enums: String, - bytes: String, - }); + const handled = await invokeAsync( + Next, + null, + null, + this.connection.pool.oid, + this.connection.oid, + this.oid, + 1, // Fetch one row at a time + ENCODING_PROTOBUF + ); - return jsonRecord.values || []; + // The result for `Next` is a binary `ListValue` protobuf message. + return parseRowToObject(handled.protobufBytes, this.columnInfo); } - /** - * Closes the rows object safely, waiting on the network. - */ async close() { if (!this.closed) { this.closed = true; - // Native FFI execution in the background - await invokeAsync(CloseRows, null, spannerLib, this.conn.pool.oid, this.conn.oid, this.oid); + try { + await invokeAsync(CloseRows, this, spannerLib, this.connection.pool.oid, this.connection.oid, this.oid); + } finally { + spannerLib.unregister(this, this.pinnerId); + } } } } diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test.js b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test.js index 62de5264..ee70ea67 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/koffi/test.js @@ -34,12 +34,19 @@ async function runTest() { rows = await connection.executeSql(sqlQuery); console.log(`Executed SQL successfully in ${(performance.now() - startTime).toFixed(3)}ms (Rows OID: ${rows.oid})`); - console.log("\n[JS-App] 4. Fetching ResultSet Native Types (Int, String, Float, Bool)..."); - let nextRow; - while ((nextRow = await rows.next()) !== null) { - // nextRow is an array of Value protobuf objects (Google Protobuf Structs) - console.log(" - Fetched native row chunk ->"); - console.log(" " + JSON.stringify(nextRow)); + console.log("\n[JS-App] 4. Fetching ResultSet as Objects..."); + let row; + const results = []; + while ((row = await rows.next()) !== null) { + results.push(row); + } + + console.log(" - Fetched rows ->"); + console.log(JSON.stringify(results, null, 2)); + + // Example of accessing a property on the first row + if (results.length > 0) { + console.log(`\nExample access: results[0].FirstName is "${results[0].FirstName}"`); } } catch (err) { From 2c59157da25f8bdb2f9d129621c13e013c097666 Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Thu, 9 Apr 2026 14:06:54 +0530 Subject: [PATCH 5/9] napi fix --- .../spannerlib-nodejs-poc/napi/README.md | 48 ++ .../spannerlib-nodejs-poc/napi/binding.gyp | 66 +- .../spannerlib-nodejs-poc/napi/build/Makefile | 352 -------- .../build/Release/.deps/Release/nothing.a.d | 1 - .../obj.target/spanner_napi/src/cpp/addon.o.d | 19 - .../Release/.deps/Release/spanner_napi.node.d | 1 - .../napi/build/Release/nothing.a | Bin 984 -> 0 bytes .../obj.target/spanner_napi/src/cpp/addon.o | Bin 447392 -> 0 bytes .../napi/build/Release/spanner_napi.node | Bin 103584 -> 0 bytes .../napi/build/binding.Makefile | 6 - .../napi/build/config.gypi | 506 ------------ .../napi/build/gyp-mac-tool | 766 ------------------ .../napi/build/spanner_napi.target.mk | 195 ----- .../spannerlib-nodejs-poc/napi/package.json | 2 +- 14 files changed, 85 insertions(+), 1877 deletions(-) create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/README.md delete mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Makefile delete mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/nothing.a.d delete mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d delete mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/spanner_napi.node.d delete mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/nothing.a delete mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/obj.target/spanner_napi/src/cpp/addon.o delete mode 100755 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/spanner_napi.node delete mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/binding.Makefile delete mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi delete mode 100755 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/gyp-mac-tool delete mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/spanner_napi.target.mk diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/README.md b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/README.md new file mode 100644 index 00000000..8d25cb31 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/README.md @@ -0,0 +1,48 @@ +# N-API POC for the Real Spanner Shared Library + +This directory contains a Proof of Concept (POC) demonstrating how to use Node.js N-API to build a C++ addon that interacts **directly** with the compiled `go-sql-spanner` C-Shared Library. + +By using N-API, we create a high-performance bridge between Node.js and the native Go driver. This involves writing a thin C++ wrapper that is compiled into a `.node` binary. + +## Architecture + +The wrapper consists of three main parts: + +1. **Go Shared Library (`libspanner.so`)**: The core Go database driver, compiled into a standard C-style shared library. +2. **C++ Addon (`spanner_napi.node`)**: A C++ layer written using the `node-addon-api` package. It loads `libspanner.so` and exposes its functions to the Node.js runtime. All asynchronous calls are handled using `Napi::AsyncWorker` to prevent blocking the Node.js event loop. +3. **JavaScript Wrapper**: A high-level JavaScript API that provides `Pool`, `Connection`, and `Rows` classes. This abstracts away the C++ addon and provides a clean, async/await-based interface to the end-user. + +## How to Build and Run + +### Step 1: Install Dependencies +This step will download the necessary Node.js packages and automatically compile the C++ addon using `node-gyp`. + +```bash +# From within the 'napi' directory +npm install +``` + +The `npm install` command triggers the `build` script in `package.json`, which performs several critical actions: +- It runs `node-gyp rebuild` to compile the C++ source in `src/cpp/addon.cc` into `build/Release/spanner_napi.node`. +- The `binding.gyp` file copies `libspanner.so` into the `build/Release` directory. +- The `build` script then runs `install_name_tool` to permanently link `spanner_napi.node` to `libspanner.so`, making the addon self-contained and portable on macOS without requiring `DYLD_LIBRARY_PATH`. + +### Step 2: Set Up the Test Database +The test script requires a Cloud Spanner database. A setup script is provided to create a temporary one for you. + +```bash +# This will create a new database and write its name to 'test-db.txt' +npm run setup +``` + +### Step 3: Run the Test +Execute the test script to verify the full workflow. This will use the compiled addon to connect to Spanner and run a query. + +```bash +npm test +``` + +## Key Findings & Advantages +- **High Performance:** N-API provides a direct, high-performance bridge between the Node.js V8 engine and the native Go code. +- **Robust Asynchronous Operations:** By using `Napi::AsyncWorker`, all blocking I/O (database calls) happens on a background thread, keeping the Node.js event loop free. +- **Self-Contained Binary:** The build process correctly bundles the addon and its `.so` dependency, creating a portable binary that does not require environment variables to run. diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp index ad7f52bb..1847c6c2 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp @@ -1,42 +1,48 @@ { - "targets": [ + 'targets': [ { - "target_name": "spanner_napi", - "sources": [ "src/cpp/addon.cc" ], - "include_dirs": [ - "> $(depfile) -# Add extra rules as in (2). -# We remove slashes and replace spaces with new lines; -# remove blank lines; -# delete the first line and append a colon to the remaining lines. -sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ - grep -v '^$$' |\ - sed -e 1d -e 's|$$|:|' \ - >> $(depfile) -rm $(depfile).raw -endef - -# Command definitions: -# - cmd_foo is the actual command to run; -# - quiet_cmd_foo is the brief-output summary of the command. - -quiet_cmd_cc = CC($(TOOLSET)) $@ -cmd_cc = $(CC.$(TOOLSET)) -o $@ $< $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c - -quiet_cmd_cxx = CXX($(TOOLSET)) $@ -cmd_cxx = $(CXX.$(TOOLSET)) -o $@ $< $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c - -quiet_cmd_objc = CXX($(TOOLSET)) $@ -cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< - -quiet_cmd_objcxx = CXX($(TOOLSET)) $@ -cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< - -# Commands for precompiled header files. -quiet_cmd_pch_c = CXX($(TOOLSET)) $@ -cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< -quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ -cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< -quiet_cmd_pch_m = CXX($(TOOLSET)) $@ -cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< -quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ -cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< - -# gyp-mac-tool is written next to the root Makefile by gyp. -# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd -# already. -quiet_cmd_mac_tool = MACTOOL $(4) $< -cmd_mac_tool = /Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3 gyp-mac-tool $(4) $< "$@" - -quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ -cmd_mac_package_framework = /Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3 gyp-mac-tool package-framework "$@" $(4) - -quiet_cmd_infoplist = INFOPLIST $@ -cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" - -quiet_cmd_touch = TOUCH $@ -cmd_touch = touch $@ - -quiet_cmd_copy = COPY $@ -# send stderr to /dev/null to ignore messages when linking directories. -cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@") - -quiet_cmd_symlink = SYMLINK $@ -cmd_symlink = ln -sf "$<" "$@" - -quiet_cmd_alink = LIBTOOL-STATIC $@ -cmd_alink = rm -f $@ && /Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3 gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) - -quiet_cmd_link = LINK($(TOOLSET)) $@ -cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) - -quiet_cmd_solink = SOLINK($(TOOLSET)) $@ -cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) - -quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ -cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) - - -# Define an escape_quotes function to escape single quotes. -# This allows us to handle quotes properly as long as we always use -# use single quotes and escape_quotes. -escape_quotes = $(subst ','\'',$(1)) -# This comment is here just to include a ' to unconfuse syntax highlighting. -# Define an escape_vars function to escape '$' variable syntax. -# This allows us to read/write command lines with shell variables (e.g. -# $LD_LIBRARY_PATH), without triggering make substitution. -escape_vars = $(subst $$,$$$$,$(1)) -# Helper that expands to a shell command to echo a string exactly as it is in -# make. This uses printf instead of echo because printf's behaviour with respect -# to escape sequences is more portable than echo's across different shells -# (e.g., dash, bash). -exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' - -# Helper to compare the command we're about to run against the command -# we logged the last time we ran the command. Produces an empty -# string (false) when the commands match. -# Tricky point: Make has no string-equality test function. -# The kernel uses the following, but it seems like it would have false -# positives, where one string reordered its arguments. -# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ -# $(filter-out $(cmd_$@), $(cmd_$(1)))) -# We instead substitute each for the empty string into the other, and -# say they're equal if both substitutions produce the empty string. -# .d files contain ? instead of spaces, take that into account. -command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ - $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) - -# Helper that is non-empty when a prerequisite changes. -# Normally make does this implicitly, but we force rules to always run -# so we can check their command lines. -# $? -- new prerequisites -# $| -- order-only dependencies -prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) - -# Helper that executes all postbuilds until one fails. -define do_postbuilds - @E=0;\ - for p in $(POSTBUILDS); do\ - eval $$p;\ - E=$$?;\ - if [ $$E -ne 0 ]; then\ - break;\ - fi;\ - done;\ - if [ $$E -ne 0 ]; then\ - rm -rf "$@";\ - exit $$E;\ - fi -endef - -# do_cmd: run a command via the above cmd_foo names, if necessary. -# Should always run for a given target to handle command-line changes. -# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. -# Third argument, if non-zero, makes it do POSTBUILDS processing. -# Note: We intentionally do NOT call dirx for depfile, since it contains ? for -# spaces already and dirx strips the ? characters. -define do_cmd -$(if $(or $(command_changed),$(prereq_changed)), - @$(call exact_echo, $($(quiet)cmd_$(1))) - @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" - $(if $(findstring flock,$(word 2,$(cmd_$1))), - @$(cmd_$(1)) - @echo " $(quiet_cmd_$(1)): Finished", - @$(cmd_$(1)) - ) - @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) - @$(if $(2),$(fixup_dep)) - $(if $(and $(3), $(POSTBUILDS)), - $(call do_postbuilds) - ) -) -endef - -# Declare the "all" target first so it is the default, -# even though we don't have the deps yet. -.PHONY: all -all: - -# make looks for ways to re-generate included makefiles, but in our case, we -# don't have a direct way. Explicitly telling make that it has nothing to do -# for them makes it go faster. -%.d: ; - -# Use FORCE_DO_CMD to force a target to run. Should be coupled with -# do_cmd. -.PHONY: FORCE_DO_CMD -FORCE_DO_CMD: - -TOOLSET := target -# Suffix rules, putting all outputs into $(obj). -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD - @$(call do_cmd,objc,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD - @$(call do_cmd,objcxx,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD - @$(call do_cmd,cc,1) - -# Try building from generated source, too. -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD - @$(call do_cmd,objc,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD - @$(call do_cmd,objcxx,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD - @$(call do_cmd,cc,1) - -$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD - @$(call do_cmd,cxx,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD - @$(call do_cmd,objc,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD - @$(call do_cmd,objcxx,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD - @$(call do_cmd,cc,1) -$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD - @$(call do_cmd,cc,1) - - -ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ - $(findstring $(join ^,$(prefix)),\ - $(join ^,node_modules/node-addon-api/nothing.target.mk)))),) - include node_modules/node-addon-api/nothing.target.mk -endif -ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ - $(findstring $(join ^,$(prefix)),\ - $(join ^,spanner_napi.target.mk)))),) - include spanner_napi.target.mk -endif - -quiet_cmd_regen_makefile = ACTION Regenerating $@ -cmd_regen_makefile = cd $(srcdir); /Users/gargsurbhi/.npm/_npx/c463d28440264a05/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1" "-Dnode_gyp_dir=/Users/gargsurbhi/.npm/_npx/c463d28440264a05/node_modules/node-gyp" "-Dnode_lib_file=/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi -I/Users/gargsurbhi/.npm/_npx/c463d28440264a05/node_modules/node-gyp/addon.gypi -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/common.gypi "--toplevel-dir=." binding.gyp -Makefile: $(srcdir)/../../../../../../../.npm/_npx/c463d28440264a05/node_modules/node-gyp/addon.gypi $(srcdir)/../../../../../../../Library/Caches/node-gyp/22.17.1/include/node/common.gypi $(srcdir)/binding.gyp $(srcdir)/build/config.gypi $(srcdir)/node_modules/node-addon-api/node_api.gyp - $(call do_cmd,regen_makefile) - -# "all" is a concatenation of the "all" targets from all the included -# sub-makefiles. This is just here to clarify. -all: - -# Add in dependency-tracking rules. $(all_deps) is the list of every single -# target in our tree. Only consider the ones with .d (dependency) info: -d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) -ifneq ($(d_files),) - include $(d_files) -endif diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/nothing.a.d b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/nothing.a.d deleted file mode 100644 index 05726278..00000000 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/nothing.a.d +++ /dev/null @@ -1 +0,0 @@ -cmd_Release/nothing.a := rm -f Release/nothing.a && /Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3 gyp-mac-tool filter-libtool libtool -static -o Release/nothing.a Release/obj.target/nothing/node_modules/node-addon-api/nothing.o diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d deleted file mode 100644 index b0f2800a..00000000 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d +++ /dev/null @@ -1,19 +0,0 @@ -cmd_Release/obj.target/spanner_napi/src/cpp/addon.o := c++ -o Release/obj.target/spanner_napi/src/cpp/addon.o ../src/cpp/addon.cc '-DNODE_GYP_MODULE_NAME=spanner_napi' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_GLIBCXX_USE_CXX11_ABI=1' '-D_FILE_OFFSET_BITS=64' '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-DOPENSSL_NO_PINSHARED' '-DOPENSSL_THREADS' '-DBUILDING_NODE_EXTENSION' -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/src -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/openssl/config -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/openssl/openssl/include -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/uv/include -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/zlib -I/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/deps/v8/include -I/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api -I../../../shared -O3 -gdwarf-2 -fno-strict-aliasing -mmacosx-version-min=10.15 -arch arm64 -Wall -Wendif-labels -W -Wno-unused-parameter -std=gnu++17 -stdlib=libc++ -fno-rtti -MMD -MF ./Release/.deps/Release/obj.target/spanner_napi/src/cpp/addon.o.d.raw -c -Release/obj.target/spanner_napi/src/cpp/addon.o: ../src/cpp/addon.cc \ - /Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi.h \ - /Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/node_api.h \ - /Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/js_native_api.h \ - /Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/js_native_api_types.h \ - /Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/node_api_types.h \ - /Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi-inl.h \ - /Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi-inl.deprecated.h \ - ../src/cpp/../../../../../shared/libspanner.h -../src/cpp/addon.cc: -/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi.h: -/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/node_api.h: -/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/js_native_api.h: -/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/js_native_api_types.h: -/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1/include/node/node_api_types.h: -/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi-inl.h: -/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/node_modules/node-addon-api/napi-inl.deprecated.h: -../src/cpp/../../../../../shared/libspanner.h: diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/spanner_napi.node.d b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/spanner_napi.node.d deleted file mode 100644 index 6b70bfb7..00000000 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/.deps/Release/spanner_napi.node.d +++ /dev/null @@ -1 +0,0 @@ -cmd_Release/spanner_napi.node := c++ -bundle -Wl,-rpath,/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/../../../shared -undefined dynamic_lookup -Wl,-search_paths_first -mmacosx-version-min=10.15 -arch arm64 -L./Release -stdlib=libc++ -o Release/spanner_napi.node Release/obj.target/spanner_napi/src/cpp/addon.o Release/nothing.a /Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi/../../../shared/libspanner.so diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/nothing.a b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/nothing.a deleted file mode 100644 index b0eec0554db93862fb8b47d5e29c57dd48e2bf09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 984 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%0DE}g_&uaN7yy&V6_bN-~{ z%C}gBtTLh+ArBZ)gOFJx@`Y?MqP&n@M${|hStA-0a>$5Ag&Z@YDIuqgXkN$#BU%=+ zU_=Pph7pCGHvdP1*MZ=fac7i6Drzz&s?&0%$)p1GyoTw-SjAXmH5c@xm>U=$Fnv0^ z&V>NZtZHWtVqjw6#ki+jjFJZm#&nGPJ3#4{QweRI5D-i%BmywTJBd(GC>au=R8R~g zas_lzLV!?k63`f85hpQ)2oA4SGS~Qe&T%FNUTg^(w+uR?19TDr!t5N!!3}{lFg{?W z;#UrwIiQ`n15q-mxx*FoVw5~k26eEU$3UQ%o8(Fk z0%kRS<&<#772$4au+Qof=mG6aD}s$RK2D!{#oWO7fSHaTbXbpA4uU?f9qfc-*j&VM z5YPrD7lok(+7-cJabjFM;{# z9(%1gVFR>*sg1(KcvN4Ek}F1W1|O-L)m`#|QmwaL&VfB6)}}{CUGatLf@v5rY>D46 zthY2uzQiuo@V(56ptm16i>3T;YeS8I98n($}I+knoOOZ3Z)A^gzOu zKo86XqX*Jn5*Gp6K7^&a^!XPwZ-Kta@!~kb6tQ& zvguw~G;nds2NBEaKKXzdG$NOSTcSFCOQ;!aIP%Y@CxxGh$iXj&JjojuFiR0-@T;~m zn2m@s_*8Z1Nq`KdLWFP+e6_6%=0HRle1okFrYWKfzSUL+laDBa@3ED^^hK1xkK4-A z!pzvh1z|4O!h$d>ws1q3O!I(1T-2f*$Q2OkYt9>nXGL{huDo#p4LI80fP{Z>_BZ_kX(H&{8A5eZcfdJC&5G(m ze3N>q%@$p@KFIMaDO=z)X`E(|9a@wFnYW;u!E_ltkmI(Vs|er%{EsoG!$o7_yleA@ zZKYRYbykPbSuY6htT6%Ecv~258c8615e3s2m}#R2a?aKRGjH@jF4=lumW>|B4O`Du z1PjuYHM#QO1ih)d*}5fUS~u5>9`%WcE#W=9i!;=h1$slb=GO~ki*C(FEB!{~>KfvZ z*^kutAXl|02XaG1LAJoO{W45*uGT8VzDYyZg6tL%MWYJzj8Ox*XsLlNXtks8X;X`8 zK~{^K+yH3fdacX#Ngud)IB6O?Xh?;~vVnnW3)`%wuM+C1=v07j$DqBZ$>D!VS9XAUC3oE%7a`JQQ#n$u6M&U@A4U~wP@&OkQcP56Tn#w+zAqGu>;O?0b27l z^ihzewUcNK&@oOj)dF}#13QWd`l2&?jU;JJn&l}N{kh4aFxUCye zN)ndViF0lX$HW>9(3xjOL<<_&nQ7#1&@>G4oEGKAg*^7256qg;1G#SN zfoXUTT*-lK5mC@Cm^GufE~NT*+7x7khyqhEl|~Qb0b37Dt8a3h=;m z7(I~aZJ_7sQln6FD4CXivMxp7Z5MWScG2Z0u5GT5| zGd@uE$L}V(G$Sbdo9yTjFQ&EC?cxCe9+sreU5tsLOGdY7yYkm3ZI0-U<>1bm z5uwdBX*0(A1cPFYxt((rg^82D;Rp^LC;&67y>S*8yuh+TDUXIXMiq>SFF;}c0RyMv z^l37JLwy3wVEjJK3Cg@&38g`-v++@|8Vu=$!UuU?i*g_*?X?5Ug3)u88=yyx$yK0? zh_ylSfik6moizcsmyHR?{RhI1P@RLU5mB)EgXuAPAbV{+F#Sf)6(Oh&YZD*jtQO@! z&e^SjSv7hf*K9qP3nkhs0qsITlUv#wALN1e>hOZB6;TjgFs()pWSgz$a-l?fC7}Oh zP~iAk-KS=dmG28(h_!nG&KZs4gY4I$9LPaCTwn@D59F$?2L^t{nC(Z!{=9~E4!=!N z-TFB&L8P*hNxJI*vcpd9fH3v%zk-YdyheljAp5i^2NF#L0}0Hq(E~XxqCgMK1)~RY z#nuA@|6^1Jyl>RdM?u=5ISN++&3-xGoTw8}Akq@(8qHT>0`w-`1s~oH8j-8vHc>^d z$ybDZCO*ohsBXnKK}3&8(NV)7N3|#ia@;CSXE0kuxl69)%6~rH{Cv7w_`ZnT6{CCv zFR6|`pYAOJBjK^<(=IUdWLE5{-yo|GhQ@pt5VA?G!FT{OXY@c`u=T(!8$FPzJHjRc zJTMg^q;^5p+j?LcjULEuTMtaH(E~YZ>w!6M^gu4!dSD7h4`liSRzJX0ijevNvcc8^ z(`58Op0V}7oHcqN$80??lSU8ZlC1}3)#!n&kYB?T@y-na@dGWBtvSac&CmM>Z|ULQ zi5O$}v0C)A6SRTRsRB%lRj(jUY-(qGIJ2nd3g`5SE}?AjLulaV1&Yu5^b{NZ^+Sj4j#2E>R?gYPzR4X7j>{Gd#HoQ z7!Y-^7!ptikMSYuU@=^v4jyAi)WKpXK^;8Cm8gToFoQaHj5$#Uiy;Vg@EDJx4i>`` z>fkX}MI9`LF4Vze9E-YZRIST6NY#d#JQ6`yiOf^SP{CLS;|y3p8<<=aCdPmT3Wj|` z4P{-Of^LQGfRC2bdLeZV@{Cv;|Bt#FhUz}kFe26vzu_9OZjdVn8?>*Hk72KYy+oXx z0NTLhqA)RX0+c%KpgSkfZPFd^(ej!2p=lIr&@=$_Rb@X_*8{Lu7@wejDX6Q~ZDh7qxh-XZ#~ z(KamB<8tL-gPzgI$FS$co;FTS0BvA$QJ5Gx0m`U$(47c5Ka*;~ZC zOT+kpDa5a-yjUA&oMC`!k7*cwSH_P&tOo>zBLjL!Be&uZj6*J~ML*HV^ojY1hVcP2 z9zQZTna%4Hnh&z_&d>!a)ryXbpX&lJI0bc{>L847| zpxM>hqO`IiR}M7jRqa71nge#6d@PH(f$;&;q`h_yrAbk}U`#;P+@oK#tpbu2{m=1?_4x$O9U>6C}I~(gX(W#d!G`tjs|$Hz$}W3t8%64sQ|sD-EW0k$Oo&%gR`%aKZ8wchXm!kHYxk5SW zN}wEdCJ-7&LMrOcx|CyDTA)=S4chd*HQFGnMcZSUt2y-2K>L8M($(YK2_Qx_IyudV zP?Hh4d;toAOjS{gasp-4quo1!SrY+>QBK8e9V~9^U~yXqi`#Nm7}`Q~P&DAt-=IFC zUO@SX#IaYdp|ZpPu?U1w4`Y=b@?R_PTsxrQAN@FDG$5=NZ7)vQMY~SV?*ZMU^Xe?S zmPkxu{5aNCm>}YP(i-_XCgivg%?UYgLUt zBih92{#BUF3i`5X1!Vn)LKo@C(&ZlvvKC>bul+EK46Y$ubq(|6V>sb0~2KCg6Rv$?gm`~AkT;>$Tye)qX%-z)&nzR z^gzzqdSEgi*6o7aFQTAbFf&GPR>%uR1hQb8f>|+oAh&EiFzO@P6_6Do3S0qGY4kwu zxAnl(7(I{;wjP+Q(F5t*dafaatS;!RHiN9!S;&J#;JHi9U>1xX$aO1Q&0w~S9!Ml8 zzynjOL!JkT-UfPcyEL!6bQI)y?LsF=)Eq+}1%nXAxI4Qjt*q$QoU_7Jm;im%w1V)@ z={`9dhIOSj$sy&b8;n=j96F1N5N9jtrub+(VC8AXl}h6C@f4mQ66GHRn^I5*;Z6PxiJ}7-U zSbo2dND(Op>!7e;!N8c+ZSi; z7Q62>IWLJq`gtKa`Ft8IVi?@sB)O|3(szd%RdS_S3S^BI{-S;1BAieURf?lmmI*^2P@tp{es=z-j@^}uWzJrjqJibmstL}5j)o;qDE*1kqL4M*V!Y5l7M7qrLD z5<@4izyzu$E@h-56lIl2eM%6xl#mI_iLPHkT#BU z1*#Bx7}IkWSJVG8CN<(%y-!qv$_=@L25A~^yrKcA#Q_4@*wbZ7CMjY8R z`iU+W$l|7k_CcP%FEpk!fSeXlFet&y8$FPVwjP**(F3_=>w#%))a`=o5>e1Dm~Nv7 z@~o`~rqAes9J2LXAxeppRdS`UR)Mb8eQItHa#D*rXN5!rX!xU(Y4L!;>V-zf==ccV z;V7%Q{LDyemD&Lx?ll?FIUz@l2tKVF5!}n@*!l3X!H8TQAxbp@OueWCeMC3bipHu< zOezrz1cFUn&D9E|uc2!}=8Xq?LHBF5Ru^)ks2Zo8bH-UQF|9aF2E=4cuGHr==xLEr z2_X?JCS1-57Aa>mwk)dsTKty94*n61gJ0UsP+1$yp)$jL3z8Ic3oV6XcPm(3lDUWUGjRl>p2c zqX+V=tp{eo=z(0e^}rO29>{fDFK(AMbeEbz!sTFE1q1(RV*%1`&pFc~gqym(qae`) zw|5i_8ll%CLE7y(Uynq7&`6AzVPS$e@E$7ii5_lYQemSaXO=>~bi-^Y^=&V+A9!`KHfWKL%;mMH*41%jwBmtKlLj=%F)hl0 z92ZeAuE5M1J&Eq zbae9|Ypg6ZgQ+umAd#Q|4@{TQ1Bu=SdU3my*8U#_xuQj#AW?G+eH08r7~_SfN`c(3 zq1}W3%1wY?V_HG@w~WXY8CbVylN^HHql50;mDY)MlU!+{ssepPBOi?-vzp7n1~E4< zK43bugUbiS4b z6L@fSkpYTn*!dzJRC~0qK7x55eq!PFoS?{&0Hbz&yLd=|N8~EnbHZNOF2=-rMrO~L z$BhALb4+(E2X{7%2yI#mk*oZM#d=(>ToF;2I8`zd!J%avF!K_D7+Z6Afn}QtCmP-u z$Bpyi3sBg9z`&_EeVUHoPzL}r9KTNsf^tEwgwiP1P4Q7irCz4=LhOTF)}kE96%p}j zAAgg~hY$Ct|b3laDF31*J4@`&A z136&pff+Pbkn82VZ*eT|b^ zKpU7`6edP$fr0{w^ZPHM>+25qXnEa;T%kE4s>Xlkp&zPkrWHhNzaDPRITF@q1cieQ zx>qB&VqQZ1#mPyRnD=WKA26-)9o!Vv%tK)eX_Wz4r$srC4I+xQK0vue@_}56rmH19`#L1G8-OK&GVf1OLEOh>-dLvfkDM(`fWScH4Sj z&KfmSCD^L-nnUSS$f<sDmAdL<~H}hp2R>T+(N*vm$I?|(!yy%|nK{h~MyxSYMDU2OIQ?Mm~m(2lf(iasp@rlZ(Q{$O%y9wSz-h6O_`02Hj=d0Us@= z^k&34@h*wA@!y#fsIHoZ5wZIC4X=xJN_L|hY|vGD(|Qd1HSEXYEG=9T1V%;ED4mN0CBOk+_HzjVx$qAqh zOfCu&BPT$q(+;}F33Quu2Yj@=7(XNZVs_jWdi^1#-)H1DKxpVb~OFnTl34zBM2z;wR$r%X#9gsjm z9d&?YK@J|76Bw{aB-FtptD+7TNrpOjWIX0UZAl`wCRffGXr)7U41L9ziIZAD8<<=a zCPr$3f&z)N0fp|SDF?KCPWQ=K4jW=^{CBPoP)(Uu5U~X#G8Gt7(K>{6m6&j_L04;- zR?JJNzc@Lm5c2~X#s`ej^MNxmm^!A73CIO4%7MHfqFCz#pl39W)0-(#oz*7Jw*ud= zCWuu*_r(X9{$yA!G-g0%L=;38%zmQ>vc}ePRbPqrN+vpZ10Ckn3)d(^n96$yZ7K$`uGWH6})M*a4aP6f&9zc|b%#M!}35 zJ&;qj9++992XfWc1G8cDK<@kX(3PNFFf}5i4H-z^)&tXK^g#C8dSHf(9>{5156qm= z1G#4Ff!Q>AAgh1F>IawuBBXwRY_avgbQnF51GXNRVWS6f#?}L~VDvz4*m_`8o2~

{*SIJ(^7&cBAQ81IvpB1cSgt_BkC7&z=+NXIbuZTg`6~^ zSs~|)Xi>-|BU%-5&4{*yRMJ0kwL-{BBib)yjSNB;z|p!0$tF;XD4U_qf-T#7<;EVabj6JUM z^8zJ1PWaaflk6q7D`%3U%`<>fkZvL>(-K zAk@KQJc>G43{R+o$5<70uo${f2ajaJ0>DC1yNt~?S!Z|N~|3>A!ZFwTGlw1LS* zVPXtepkUa?IqX1pLwCSO%WLrm`MOve|DA^&s4CfR)6NDFtJW*Cb9Tvyb+ueM*r4k) z@-gf+u$PFF6F?i7TofioPJmLS9URKK3JtmkbO(I2+!8-DHDYc2cjg4D^`>D&Y#@Ha zS+Q=BD+e2NmqtE@{TlXTadHA^1Cxuw#K;Lyj%WwnIe~76?tqV$XX1yZO{|Uo&YVEC z+cb=bt;cV;SF8u+%E1Obs*#Uj&)Xs!%{Vy$w1LS*VPfP2DE-<&cTS*tPItgZ%lq}_ z**S#_i?#9JnG>jvnT8Ru*7yxii}eM$Qm|`4FKgtZHL~+*l`E^cW)MKnYZ&KKsbUjn z7+_+Y%|)G!k$L#IsD1T;azMHq;}PGgSZ`<)r~6Rd(k9MY!I?TMOCygD&@FnoJT@yu zfFoL*VN@^XM>LENn7Q~h)g;!&8D|)v+G-kx-<$CphIO}~aF;>%XyjHLf^o==6Pdi2 z_h}d(FoW?O9FmjSm_DKTAeXc#2eKfd-~{a&ZBX9SI6lbM_RyGa9)RogntxF`QyMxqC*-^lEeW}7L~BB>8xejWCM7-*e5H_8 zMpPr@0V8SkS#`(7qZKUdWAe|M1w*O8PTYaV@5P38>Pl{itWo$=vJrX%cEjMWoeLfPP?3|I451DlH7V*~QKC=>k9rk#uqa=sgGVikI#`r8)WM_9 zMI9{49_rvR21Fe!h6L2XV|<7@SPU1agU8qrb+8ypPzR53CF)=?%%Bb)V@}k;VhBPV zJjSD_gT?TKI`~l;eWDI_OvF$JKeb)m4Aqc|4%iwQ2Mu!NkqFw?W8@er80%o10SjmY zlZ(Q{7_dOWu#a<-2D(kU13p^L%E*i{$Q#Al`0v~sLbb&-jEMEbZ@5FOd*sT&20fsW zk72KYy+oXx0NTLhqA)RX0+ep;;7~R!FY|x2(4gC=JK&?`@%W)RE7rz;XHK9xXc|Vu zmg6@(EY{<4vxUz<2v!I^qkOn7{N z9@j9(D#h<6xyBhrgJM3aVSK<;#Sg=XSQ}@YVSws+(=hx#62DG->a1AmLr02L^t{ zm;zR%X*5B(IUub7EygBvy$Gc_TZH1A2a8esVie~@QH=7h=gWQx0z%5CBl_!vV3EXf zd7}ri$JPVWYxF=4*m|a4Ar+DqK%Egq+w$Jx{ql8t%aYeUbN0Ib@ziw{Q<87wMVJ4cM+jf`F@qW?jw8lkYpE=d-i;U$n;?^d7V#rr~(3iV24H<^0 z2rcgr<+of*Kx|h}zP@#@N3GsTUWG_|jro9gJ!@1N39~ocw5{bE_ikfvGRk}QT)QW; zhfS)CkX^bX=-1ocN8RK$8!~riD2_Su{g=wfvpOPfW0+}qWeWo)NLtBGvc@bqR_?14ZXhH0es+8Of1SckLDJdab<&ReM<1 zI~Di`BTn40htvBZW5sc3kirg%?!$IrQ;$AkbfvKGj$krkHWlDvzTAq<0sL(M0xEFMAD&nj%i)FDPlhOeM+VCOoc%=D-}-BKJbx0QKCeN z=48>=p9*W7L-Ok~#qQxL_BZs{qi@3tuS`R{V}F%AD7qHIAc_2l)zcsW}UTt4?9Dq5vJe{aA&^)6cH`#jcQ>C@f~f%qAZ zr*F&y&w4imOL{-)DfREY_jx=5KDM`dPo8}Gg2x_)E7uq4JIDu!ra=bw_r=T-{XwV^ zCa5U)e<)c0KWAS8=2XpvowU>GFbgxl0HvMbc3^;E9Yj`9Py`e~SwvZ7Q9uy^*^v$) z0s;a83W6(wh#+n#q9_W8`+^%Txa;@1ub?6->i?dTq)pR~|M&m%JiX`Uyzetzmi2tusZ z0aCz1tU)Tdqd=YWMG@i#&Y$Dq3$d2sQymAV*TE+Zi*8KB&H9_-K1cBgUWnV`c4V<$wh$BaXV z#HP4rR1K=oJFPTv_<9Pl8ReiPwbHvl!Fi5#skbCsDM*N|TzX@7w?(3oZsYLy&f_b0 zkH)#=i7LF8oS=EAD!h+V#^wFC2`S0%1GZB6(WTgKMW9s=>gqlFALY)_Y2UaDQKSXH8kkD6tsr$btSY$ zUKRhg6tuSRT}Wsc=u;_ZE#bS8(1(D&n}W7b*UNVy(99XAS*qLzh~J`S6@OK&Nz_;~ zU1NlvWcYN&eK$fg)M%)r{*SY&_(y3?)^TvEP?MI~890u`l@2tMIp;%NhP23?08I^? zWfbP-zKnj-k49XW+Zy6$Eb&xto|o|lWXS)QkBz!l!NheIGtpXIN16}o1@xt6EQB+t>h{^c)5BPI1T22rtSW&PV z^s4|%e{X-$dYlBRgZr_+o#xhNr(KZ}1vh~k0WAG}`~}UC*u%l*`HMM>AFMD$T~__h zDiaz9q_|lbR>&n3sM1$=^{NyKEV99d38NESy=~Or1{dMdbLHsl2B!rhO%uLH*bJ^# zy8haHjtx>NRK+vR^06pA&0@T0GxAo%GdSStb!ho`a{CWjpzvtsvV_#{W&DWI8&@x1 zJW+6a6t@u|>G%7+J*7e{#pU#WoG}#Q(0=luV4@l&WldVPQ&qBi(fhHkIA`3P^LfkZ$zPZ?H4^nL}DL#6izT&r%4G?bZQ zbpxPBYr-l!P#?WpqAov1}y#k{9aQen3osmX?VJBj|18R7t(*O-`j~q$6D}L z;QI4|jWtxmb>R&HRF|Ttof6=^fW{FNN`d|Xw1o1ilj5*{6CvIus3--x3(#h&-MRs4 zrB*BPeg`xHQ&oRS3Uqc;bd%`C{q<9zI{^KTkH5JKMSab%vVo8Pgg~NZ)g8i@I(n`l zv~md|x*6C{WZXIxI|lub=D<3oVw0d}yVER8M4y2=+5#r0C#hRNbtS30+G_7=sQ#)A zb@#w`FD2K~AwbU%b)Bl|=ykUkpqjIKI>Dvr_mP_Yr$Ol!*qE0%5MU^wH zh?g1qvVW%w?@z;ARXNj&cx-1K$EM2Zs;ztnrauRtt(jzRJqeeaURw90?M}s;$OxGC zX3~VxVsgfG5Yc5I%?^X~Sf({vpxaz{p8z}YG+_HOsSXkjgx3M;>C`zsl>#j_(6gBo zQNpY6J^<9d3#?wsr1_=oushT@(lF>Xw^;FhPk6T)(%UX6evNe5zc$QwD`g6=)9E_T zLoSK#a_wmmNIfwr^nc)ztiV1tq|aQE8(6ch+TDLEWeV>qL;Bn$S%JL_(mYIE{a?8x zE3oF>H0ei|=(oQr&6Zy z`kkTkltJgNumZaeq*nD1ScXfo0;_SRCgr#!H?Z-BnO7-Oc&`~!zDu$KJD~^G>+2)1 z>MqF&Y>gq+aY=4qKNx1DQYI#RXX!kPU6K{p10Xe^yV48Z`Lcb(>W4&?o*HlB;_)s< zGe;R_vwvsWkCR7?O&iySN-VsLUOM--E}qC;G0!#3_W#b*_xv58|Ba9T!k{w|iRPS* zsUbf8Q9-L`E13h;N2I=()Ot;bd)T7GP@j1Ypi7N2J$o+c2knD|Od_KQtqiFEiuOZW zw>Oa4#zp}p&7i!7fJamExf$v|2-;&VsL3a%4_<%b<9|BEXeQKe6ZE`m^aZq?`T}{y zH7e-=^_>JAbfKahP*>{*=snk86xw-&d~6x|6*;HO$R`B%f;l6!#X4nihpS$I4XQPL3D z48kw4aJH}PAWG(e|2^4^`rmDWgVB)j@sImoZ6bXCm&}3Ddt^AvF%%_VLw)8DK=T|( zSMWu^o+o_1g;TdINmCm2@O)zF%T%qE{2YV$l2df+UO%hQUR9T2J`?ie%`Jb zByHbs0;SnQ_OVJBMOi?(^gYKI?a+~ zMA0&*=us%YB_Jnmti1jPWz$>$Ri&vmvQTD?+W{F#XfGC_%!-i|<bFTjwmI>FQMK2&T@yWTxDhq`z%IPBVd%>LZ(DG;JQpDX` zQguJT=k)e#C(cfI5{H~KU?1N3GDviv+zgj8_lF$fJdg9DS8<>ybMqvgK>SRk&G7uZcQKcwE(Cck!VL$3upzk)|9N6s%d`%>~zAKG5xMP+`GETs35T?yL- zEUWkkyymy1^2+cKsHIS<_LeF#0sscLh3bV({z>vuV#ZAruIx^>?Wi?HC^PMJxC;vJ zEI6gNJoy*PTT8Uli5y44-AMCW#{7n|Al@+Z>q>7GjOZm#{#e(@dm9kFL&+bP0yTh| z-l61ANr5hhn%?W=$7KC_$x-}-S2_G%C%>`ueg%i#>*UXMdETi|FCl1t3bYDpdJU7m zC_0p!W(MvLoOcARx`I6 z=12d|v~xdZY(8^s=tdFV>3G6%bYHr7B6r1HX_(*rJ5v|?BhcxQpMS)yQYyA4HNsPp zNx!+I^AVgTO)#Y6E-Bt^Xy&7a>GL_4G0qg8M6XJ#V)@xF$qKBmAr-hJE3g|4sisSc zXQu=EuVF?iW#Zclcx=$BSblw%WCcdU1SU0cNmgK=7*e@Qasz9PYr*c?RLT_IB9IQ@ zlYfd!vI6_Ukh;1gE3me>m)TPfm*fVv#4vkT$`s!FAknH={s5O`1=bY=CJlE6Z3oB)cw)_;| z;X_ZQ9^#R&@zmn^glehn9-!_|w0;}UFWLGJ+Ro5=E+{fLuQ7Jg55*FR*Dx>^QdX;( zL!%ZNyz($?5h>d*#qm0Hm(^+^kFr%rJ%dlRI(=YHxvr&$m&hec+7eZ*cG;W2GcUkt zB$*>}uY}ENLZS@=>mk!-DUz}jWlw^rvfQt;+>nyx5pYzN$sCdUGi)Y}!}hgyxqrt` z^D<&k@lLkt2k>aDf}Lz7r<cCw8DLGNUH39G;Hoov0DK%cUcZI#l-cd|9W zGOx9hZ9>y{l6JD49!K4sY>$zj#7?$CvP-*@?Q#k)v6D@bN7~6&>wnwHM#ZmWC)-HM zGqIDcHAR%z$;Qc~oouX0>|}cwmBrH#+Q~*$nzWORYxUoDvMokndM6t>jx0x76#Y6m zzLV`Ogh%a95h++vFcPJY?_`@e1yceHu&|R&HdEZS?6fLUqTph1<2%`YMX)^i@jE-& z*t@fnP36b|CGBKW`VACl(oVL7UX>zgCz}E{Cyew?wuIg`(mUA{H~>Zws+{DVYz`RN zmhe47Z5LAvu2#DK$vfE;NTp!k>R|cMJK0>C#n3z16yyAr@eK4%wuD}XX76NUP!JxsX=B5&_*jO%c89#cGm+oouev1qRAY zvDywu?_~SFg$O;yc-DmM7Qk3*g0fvK;_V?__iQdG)T*P>q1&!kYm| z?__g}bpVjw$>u`!m&SLpxejB1^iDPxdL5A7$wrNtufA#}Uc+Vaoop^N8<5_~=0a}+ z(mUB4C|bTec_*7{#l(v6rH;-v1ih0jK@ib5f!RCRY%F?h@=i7zs{m&2WMd5Optg6i zX?3F&$vfGU+M5iuyOT}V(({1yPPPUo*cGU{m4d?utetFO+{sMt7wBimR16l86OXu0!Velbooq5NB>z!=QjiqkvzN<7oF5uwm#=O(u6J1>0n7iAAJCkifabRTegC!4ZWEt?j#?VW78T@8m??_^7E59r$r^mrio>I*OX2DLBO||tinEEn5{FDA88SK6sRuLE4(?rlPw*|ayQ>F&r9o0RbcRz_)fNT zMId*=JJ*ngr1ONPZ1AD!aE@MhpheuA%o&wCwkmzEq0e&Zd=2@aO4(+8d?%X|LV{^Uyw%W`Rqj|tTy(p3ysC1h z74Zr~-&8qWwUyc%Fj2_CXKNYZ#fp|qHsF&#woNs#QFY^pn@ zy1)ZrV|*tY6)NFCcq0Mnoop_&(?HK=QbcT}JL2p+;yc-BerY=#3rO!|bBYyjWWw8J zNN>Akk6$BQ_9~mSyLT&P3U8nx9db$ZIMJT&1WE5?t30ryhV+^1$qnp`JL5aq9CvZ1 z@YWjA=dL>|u+KrF^)u{bb39o!)_Jog{pgb7+39lLXqbm9WeV?zA^q%Ro zldbZ=HX71jF3An-Ps9ADQYJdbEjmvbbn>(U+X|B2$>xx(8VhdKq#W0i8`x;W%&U|s zyr&E)-z8ar72h4-$yRw_vka+@>&Xr59m9-N$`sy-+u}RfoII_-mV@N(WaAOJen@<5 zaBC-||qSC3gU@cCy*|WIPbx$wpjsu6iM&WDF2%C!1~bEFis;%`s}UJ!vPKWmIw%AZsU^ z1r>b?Nbh8G{GIk7dZK=`$i+L^lo2n66>SEjce0U!B4=0>Re31Bla1EG5@jkH4@B=| zb8KEW$j?E?rtOaSPBzD8wL$)HY)XCxGUGgit#-1hMq}+{8~bq5PPRm&5+yGHvUalR zi{5N!(oQzpU=<*1Cz}No{Q^kuWYhJkT1rWuN3hgC5b>#{rGABNk74_Z#$KJ`-Zg0{~Htcix zU>v%J?0GWBydr6O3to|6S4mO*iK^evUSM7vM_N<;@`2u`i=siG@V>Eyk`(A-7!^g= z0N{;dizU$wpmvTmfQG)Se}uEHnaDb)4v=n_;l&i4^u)7>A4m=V2?tu5frd05I;``8pjOudh7EO51tZDTiWekS>e+=rwnCnmo@ z!alZsI5+#)))}*e8_Y%hT4Y-VFsjT)#_AW80*;;tg zW;Ug#CZ*n{D^PD{OMt@L0H=C0+ofk}ryp`01v8M2Z)S_PPTI`&4UF_=Hpj?2VS0Qs zn+wGN>CJ2|v>%Y(%=VKL#S^{ts~y_R)^dh=e}m0z4$qqjNN;9yq5XjLW;Pefote6s zO%>nk4~U)w_GUH>-3G|r%%-7l0J)plG<4z>@y%@S^{}g2U7~{cO;4NIW`e9Yv!x?@ zPXgDQ*^+VL1!u)Kv$;@jKzcJ9U0rTMD!S-eK=x)f)kxH4wy%KMo7rrvLo9hSo5HAp z3U59zy_xOpv+V35+?&Stb%}zc&1|p2OmAkR8!!Y3HEge%A`#aF} zW;Ulvso0v-ZjL7XCLI!WMVd6vkdC{gc(R$4n@(yoZ^zK8arx8U0sqDSdXi;ryefJ4Q#z(_O6sEyk9`lo7pO_v9ssLH?uh; zE3i8aX;h`z=}RdVXm^)Z%ES*4fTTCGIeA(&_Mjonay?mrRaqF{%;tDl2KG5sBE=n9>mQx~fqG;FQ<_+Y(@t8jRA zwS*HYrBO{e{YPOMM9I*Y!js?EPy^Z$UoF}PP8#C00KZO_g|iy;qh0hxMx67WuG3+# z2@aSg_}9rs8zWJ;0_an5RFqQ;yzMD8qS+6?LJPSQp7lC%7bmf15ou(YRgt*>w0@$Yg-D&wH`^XYF zbT*kOeYTw+=_A(@=ymx(ji^FZ<*iUy8C%BHY-6!1?v%C_#w&pIsu129<22$rwTw$_ zYYsJJW1_?2;sY6D}^@(5DgVWL**LyWJuM1`QNz0ynih;(ficUhRfZCraY9>PfqfP zGIY6j(Z^~G8M@H*=It=hXxD?6`H31RhQ`V|=O)LH4d?u;SE0$?dPBQRo@!`1h62!d zt59f)*ZEU5oD5BLy?Lt)G}-mw{TC4J6bemG39rLvYKR+}kpe9PMB~%Y%oK;80iy9~ zD3$`X{f`=-hOU%!G40E-1Q6}{3C&M|J^@67(9qRpS{=WLt^ccruAwEaRdgvJ+O!i| zM%kF#h;QNO+rXkNfGxK$;gx-^hP0vU{4dpDIdpG|)kp(vPqEqo zh{n;OU2;3!9P#QBUglRCdP43rkZO9-L4atlO6X~;5+i(nMt2zOSsQyC9z?Y2*J>Y2 z=#Yg8Zxqz@i$S4}oI5B&_nq?VyUr!p{nUf_>POg^V8w%Nkl&f=}KyG)o72nZjB<^{yVjuEmYf5s}>Z!%3vWE)0O-> z2=sP46t)S}^$V})d-akhRN|v8;hd+sZY2`{J&#YQoXqqij~jT&L8u%40H{L(!Zn75 zmghq!`G`hFR!c8g0r(3t>Xr1cSe!w{d)YRjA;#x?0?5a?^&p*0qXu9RM}uKKga*Sfe`OrHn* zzxaf1v~ZRGQK;!1PG}oL>dIK}a4!8ty~7FJZ{g~4KM#oB;e>W3AW_ozSM?4jv^$~I z*K-*ldWRF*p8|ak=)9wVzF|lWq*R2LK}|0iLWeDgha@F$0HQ_y(61K6Ex2C0-_*)@ z=ud)Vy_=Ax?|6s);&jPhNVC^}EK?p0srLu-j%mCK4Xt$JU|dyc;CG#Mj)hy7WU;{u zT%7H(D)-zwXcAbWHDleTf1r>U+S*?=9*S#>CE8Z+nkCwiq@aKp(Mz;50n>V+UZPbH zG4&GdGr-jnZ8v1W=3~fDq%V@9oR~b6#uDx2I5$hQRS#*ir4`9$i`lFbsC*M(iMHo! zi6z>BFjHSOP7|zNqTK+FvqZ}gi56c0nOPNOQC~GyWudU$CE9Pf`s^iI8mBu;v;(M^ zv_#wTJ)B^PmN>jbI|&NCL`zc%R7zwT$PpTzi(JZ(ssu~4X7rCG+V7#&OSEsooT^+e z(XuJ|(e_kfR5w_nZ4x;5efY=nD^-WPz}h6RUZa$ci#81WMQELx95+pfIGj^H5TZ^k z(RvpKm$G#m3=n1O!Jp9a7do~Zd>F?j8D+=O+%cJY13frTrp~^^o=lyAv7eqyeKR(B zGR2UZOpPa2%4CWO)?}*frJAKCQx6&=HJR!kM@2cskY+N~_zi@dJeguuqy>QF$&}Iy zbcdo`z;n9ERDz=%*pn#>YfsM0seaN;rkJRwB6>2VY=6UrOrA_7^pP&)(>wl8d@|LG zibl6=f~1Z0WJ>ApUKMw$CsPT%Duj1Bs)*LSLlNmXwTw$BFOykc3MOeXrJRypM|zua z+QfCr#?k)*r`KL)GNl|)^+y(<>lNixiDoj@2w#+EvYt#Oih!>x0;8X5!(@uu2S<56 z)s67p1*9iapTTFM0HS;)uCSR*VHluj!)28bNgm2?0L@IM?gEV#W<0O7~`D77v;CWxtUDiC%P5wGP&H)R4K|gf@UUDr{Krg>1!95OgY}X`39Qo zdhqa_8#9@53h31cNPb^{$&?EX2BarbPDtJ+KzcIeLf-+RuU%j=MHkb)94BT)dvApyed63^io_XsUm4QpX-RY~wYx6(j~1L~ z6<@kMxrg%}1BrgI6qBhmBy8c%(|CS5oC6cli6GgNDOKp`PN?ZuuFYgh)f2b2=r0D- zlc@xzqK~$#Dw8Htia@=z@TLQ!9dq_%N?o^--GHpgRKl$&$(VhlJsNO%lS>nmsf$3hCQ~Y>iByY4|0&kcbv|+%zb_&LM>waF0d=K4 znNsEiF|J8>f@Dpm6p5~so=oL>8dsAk3s)omDZs7CR3Z~m@**H>GNrDJHJNG^mHg9g zdNO5Sxdni%$&_v%hoGgOcGHt7+n{BMv?o(Gv=ERrnX)7N6p%HUQV@@4N;=k)_GBti zZc%SFAlhbRCR5)cZBM4U)Yo3sWGdlRSLtI0SCc6VS5?}oRA;RwQ;Dp#{Z@mk$&`h& zeUm`Vf%svr(2_@rmvZYjwT?quqJ`g7%DF2lIknUQ6}J7#3NLFGx#g*l|4*2svSksSq0(*r#tQxGxrjI7;XW=8f7#=~r0 zKz<_sK~j_xlcpc^<4<9nn;F?uW45#^BD2iGNQ(0RU|dSG4v86=2Q#y2=0TXL8CjZO z^^ELCaGV(#M7@iBIWsxYb>o{{yz=$vL` zR2}Y|t4Uy;`CQ(h=@Q9j${ZoBnaF=*&(ALSej623kGDQZFX8GN+9=I?GQGW`qxH zmTTsB;gc10WP-Xp;b2sAHq)0iF7zaL2L}YO8^9 zcuBI$vUvu$CfT^r8vtmI5T=(gs;P)Z^+I^q;uF5!QqF^d2DIVTmhvqqX;c)xA+F>` zCK@%Vqmi}ANQ43qjTQj@5}z==hSg1!nuBQcr$M$RBWibYqsd`yNI!;U8LH=5qptze z5F&g}GAtUM710R&QkHGV54uJ#7p``k{6+rej&0D<)^}Px<#l2M>((;p)Bl6a$ZjLlWq};iOGvl%62oECB4y4 z=p%;-^lCQN>qS-NpHSce%5Z{|ya=WA{jZBV)r(LGy()xPze#)%%5iELmr!0Nv-~&X zPW2mo<&^X~(hB3Wi5n>!NB07^7on5`s{Tlo$?#rIm1q{BWYgqDs6-L)Qy#$dA{4a` zju@L_y$Iz(8v*G>D7u*T<@geiexvU~EnB88 zLg|Y*9gtpxa;&0z0NHQ!6KzODj{~CzjCrH4>fAf^g!m%V+^Kexh>&wpUI#75EJDpQ z+#4h{$wW~U*V_+VztK8Ew^CV|o!vVP)_jqH}=R zi%`1qpM_d4LM7ip5o&wtzW0jTXwoM#9f>pWrW(@cX-RY~wY!%Mvx+aBJMQ7UE^XtB zP-#fQyUpPFX`N8?BKk8(G}1F~^i`pw?b{_ULaBP<))t*=Fue$sz*O|nhe5F4=qm#C z()e~VFn1A3UAL09?UNRv5^hDwRe%~|665z6*A z)Ie$xDgmhyl-v#6dZVAfMafqNQj1UtNSPKjJt@8jrLT&9*3mFQ6wNa5e4p;Rbj&?w z0xrLlx=jpE>5cwNpjwMiDyQbuREw_Y7+-`UxAFTTLU4q0D)|=oZXd&;wHBdlgB^gZH~Kad?3}a+Wk)y?khKV;h!H(NC0H)GIhOc@b(f z()J?MV@O+X^b=lnm9{)h<7yGg!c~=S2F_WlMW{s9+CI`n<7yGg!p%r{1ID_veq_eF zO<#_stRFp$YmD`yBcQ7FqsK@=4T%xGe$=EP+8LUoUO!S0G4=Yqj(Bch-*{pkmVc(Y0_(>qo@l^`obt(CbGu zl|ZFL-UK;9!*h{K8B&#C{m6{|v3|4%TD^W$3yV2a<$C>yP05e8rwXIG;q{|Q;L?XR7Z-SqBF5rbV41Zih5HMn?_IU$Sms0 zl$Ku8YVBOomemE9R(py*TR_}6$~I*a4f<^|%C;qYfYRfq=r-6Hw?q`;RQgIwVJ|Gw z7S}$Fer~xt&NICET?RqU?J@yJ(WL@MDHvYLaIDL%3~y(6KfzrN;^^!04UT@%BxB=1 zxQw3M@n%T+;nnCVD1O<)NPUSjNkbpHs+FOawQ9FluQ*UwG*d8E7kU{WuT>7Ph_OWYU9w4Cyx zX65sq>Ly2M=p{gje>&YY2tDWh8o8@(Qm<1gf)r={2Bk_&>TOE3FsXMab&5&hHNLOw zStf=3nZB-rkm4NPr_>me`hZeXP3l8RU5(UF6#hq)T4k`0DYe0*KBv?+llp>EJ5B0K zO6@hN?eIOD1thCp1l4D8RS}ZINcA71!Y^cu zkzz4E_0K??>TxE{&Y~Yc7d^MKlF!e40OvI>25B@%Ie2Nr&8%m0QjIwY+p2o@;M1+M zae6kN(p}l>JUYFYPS5T&l+Gt~2AR6p6Op2>%J|}cSE9SBhJkex@H?IjqdAoO4xD#< z0tZSoETKMVA5!GBVLdEgi*v?LMB(vi@H$cK2y^-(v#|tG#~^xs6=(JQkx%Jf;@BI! zPO5Er7(ei#HM8=;9e)yh^Jt-Z?7(?!~9U2^3>ewe3gSYj6V9x#*qM z8AtpL)KZRLvqTNTqDNrV=hi2MXt7y}=n>}kZG797$x`%fy#6s3x6gSMzh&5X!}Tog zxCHlJ-^QC>X6(*Wkwf3cn}1+z%R8*x`WcJ6zh|-S7>j%TQ^@CiRax9$hs6V>EFLUp z@z6;uc64L$a32%-H!aCD%pSJb0mc5*Jgwq zxPatHc{$4q$=g|8CXayGug!S*7t4tw%TgXMd2ILi;^G?pLBr7S;{n_2!x?qm76{D9?`@;J+{ zW%Vn_@3*py<@fS*mOsj2EDy`6EPs~Qu>3{d&hl5eljTwQGRxoOmn@ITzgYe*Ys@0Q zf5^rx|CF6s9+&5_{7a5w`M129GOTX((m)f$X|x9F3W(gHOoxj zSuBIT5iG0trnAiUEn}JE+sHE4_bAIe-vO5SzW=hU=KF_bbzjX2@?XQ(lx3msG?q1e z16bDbO=el!cOA=+?_QR5e9yBC`~Jf+;`^OtkuQHX`78D{U|HAKk)`MB%QEV_m}QA? zHp_ax>si+KZDm>N+rzSf?=6-MeLt~mVJEXL){rPO5|S&SdcV!|926R&4+`4$$Fo?tQgV-{16vzS`z zN;03;hQ;*$EM`n$G4nbWS8QN0YdeeBODrnhXEFOH7IX01Fz_i{>T&vZT=XfY79VA?BSgd@U#j5vM ztoF|*yEXXs7R0(HBs$mWO5(JBt67};5R3kAusH8K7U$rOu^3*skjzK4U@@{MiwiGdanV&QMy+QtdKZf^@3Oe~ClXyJ1+FGB zxtPV2HY}!|&0^YU7Sm_5n6ZY%%zIf}@hpp3AG3%ZV^L8JBY?hLXE$Ln=X4U?dk$sM zYch+o7qd8LD~sOySoAr>qVHiA{i@)h-naX?B`o@PU~yhw7Uz#;F<>5xfj6=kw4KG^ z7g!AWg2m83SzJ&95Bt8|hc#s}yc>yL3;C+_x_U6D7IA>R7XQtuCBH8v$~AaR3$e5< zi)8~?EMLmv+WT3oc!|ZzZ&<9VvYZUAtIOj0Q&_AXz+%lL7B?(qvG#Tr>mFlq<3ScT z{mkO#ylctJEsa>*+MUI1qgkw9z~c5hSZsKL#l{a<+;Nn}rkX3r{LXR~n|rXh>k<}Q z7O~j6iN)RfSZw=<#XWzrxVLyEncvrr#r?flJTQjE_Ju4S+{EIc{VaBT#^PbQitKi_ zV)4isEFK-oVpojCW9wNwzMsYJ&saQ>a~;|3Y0YBq=`8kLz+(SY7Edo>@ys0%S?xDS zac;kmuhVjjFsgJ$O7=gKj-qe>u8$G1f4A3IbmvRk|I9Bqbyn{6g!S}T^yym7X1#e=>IE;0W-OQ47lPZY9Iq*g{w(aG-ffo6N@?hSpZh0AtYdf)6 zF^I*=sVr8lV{zRc7T15oV)b7v)|9Lz^BdZ-SbGMGbpu%3co~bE=CQctIu^Iy&tm=S zEH-?}Vxw;zdAXxHi#y9$Y;Dit?mjH;8OP$@t61E(j>Y}=kr>kY1r}}U-$bdlr;xay zO>>kFOAKAB<41X_cH;Tk5S(|UEkrajuiBYrWb~ioXt-bXRLsauxCB^LS_=uc#Oi}u z2~n$y%^0EuBaMmXSAb0K>8kSVh>po~jO5e=-_ef8t z$#R5vsh6BF(YzBpJCUAAR-*YrASzOFz>#X?6(A~72SKDy{h=bI`DnaOX~*KfNBTWw z5g}e`q>PE?|AA*G(j#Ogn%Di)L`n`gQjH7-q9Sz=L^`-J7B+Aj(Ryk;Qd%4T_ecdT zm_~?~8YyF<`Am3rA`Ot0XuchYs#9{nk!s{yASzM^QH!djz0kSWt*vgUs|F(S=(<50 zu2;9yNu-GCADB1=({CABMiYCbznQX;VWp>=K{R9jt(LkAj70NIgY-h^ZN11z!iwPm zF943NH#b{0GFMLVl}^6XS8!N;22q0Ua$c_e2TM88{^*HLA~-sLyvlH?6(s9k{IZ08cihpa8qNs}h9<3Ns zZ4G+K%+949D1y@NILgxglvC*_95YI%<9KCODMrvDP>M&C2#U;RBr>w@gUAa!gkwSQ z9RHy8x2cNvYQBhdcJ!LT8UA8;r#g&m#|?SORj0l~Iaqm4XAP%*g)RD^d6( zbd-1SawM|~e?yX}!AVFKc*l_(Pw0hyxc8m*9RycSgci0?`C}nMR7kpv|6?JEstb8F z%-urPQH6XIkXuLv*@dj1Qb^XQLQ+O3U*F{{D?Z_@d6^lY-;E5QeLQwjD zECf+?A)+vM3sI&D(I1do2nE@NXq8e3)~G^ojKW(APh5!A{#WivDg<{I-bRDp=;G>1 z9y9oDF3wld%fsWi6+Xd@{(Z^*`S$SI8ho>hbAaCY2EW_IReTc-e!q*W_?`oP44>c* z7gzZQU)A`dF0S%F(crsXT;)H|;QL%$<-Z&Flq}@`tXn@S|4$A6qKm8iC9WacA8>J% zf7sw}y12@JGVq)52_AOiQ~7T&_^&Rm@_*Xkzq`1~{}Y4%?cyr`ju<-d_4j8u*I%`d ze!#hW!3?MUDSRw&j=x%Z`}x4P;1djI4Bu|IU*TPbvA`C5f+emgec>Kk7T-d@jxkrT zsf)LUL*dnUN8@c=oPNmw|HJ|#r}p>+ySVr>jDOKhjY@)jGiKeK6xz^0q&m6=8C;XW zz4h4`#soKKQ0M&*jK-lL!Ml*mDh%MkMHLa;f@G*InFVjmpl-MyY-EHiBLi>{7ts5k z2cE*CEx0zLOD;X|x>Uyz@4{+9oPlUqgX^{oy~ZxXBiZvfa_UV0 zzL)UZ)8lJ_?uj@QLKAc`~_b_HfmZS#Ud7&9z(rvW#4hgIzWEJ5_TU0^zFJk+F`fsA||;c*6j3 z)$B|Z{Z{sT7diE=1kP3SXnK4jaITuiGJe2L2+Otb_5h<{X>gERe(x9i{0 z9fi7T4?ts5pc+uOCTMKNxoAC{89$4Jck)yzF2=|Aex|tta~{7RcO`UT^}M26Ir1{T z%__WSpgrQSYdw_8R!uyLg~W64v3+Meo60_|HTk|A%$poG^)hZGw0nl0pO3+)AlSt} zh)6W_jgEK$|A-ZzU^g{-x(B_djO@fwc&|a9g~3g*yFcEPExee#1$&U4FD%djU?9e- zvn-W05JUdYasF@1VetXhY4q!PzF}Vgpzbr+g?=*6S4_kp-rwUd{2}yk%_{vPORTb7 zM+3N{c)0j2+gOm-4bUZY!~G;F2X^@xyY#Mvnj7TLiJ#(PD8d!yZ2`^=@@RVeCE!1j z>)+Gk$AML+f#Pxb-;K#x&wWaWt(kzb62EAqqq-3gbvwaqUzn~2)q#e(>=$ArKEd1+ ztMO1@O;FVoXgSnd3Cd4_9)kJ+K?Nz$J5V1XsCo+YC)9;c1FD$KqMX0|ZsIBkE`;xEn&A8up;uCD|yC2<(-2i@g z9;>BvyPo7b!}LlzuSQUJA?RdZyu;E^rwLMw#>e-BpZXGVm_sMuWMI~*IZtEW_7^_B zp99o6ByrU3#9a<YG$2Qp|0fzOaLqS`9s)p2T_kz#NKC@Nr4ADaLCN zj%_GV|3=Ug(#-tA8u}aR5F!gcDNQ5>st0vDg7&09Cqq4gpnZvZQ9GOh_3Z>bCAV!# z4&$D&*sX_8@M#$zEU}fE8+ut)%MT2_@R4Lms<;^$qJq)c}}?=*#`&E zZ+;e&KB#~5`xsSDgh1i7ho0+fq$CB`*RGxghorVhDP z;AbH4eN#r(CnLHBn;H0a2j&VKu>$Zme1aQ;R8+n0%Ol}piY~Z`_2JJkE5bv7Rd-q{ ztEX4s790EqR>Ip3|Fkw6+#39m+~807i!iS2?zZiIVY}yy-8R=w;U57%MzP-;q{6V@ zzd6pRK)Y!{?dm?|R;j%nQ1Nr@fndDVD`@0MK(y);d?-kz$HEXV1XE>)6{Yb^P;Mrt z&nSwN7hZw))n*Ne8@H|~Z^$*+<%5s!kvx69d^vQ|A39ZMJVX(Az(jWA;){a3K2q!> zi{PU{k(colDnAr_Cv(u0yY*d8n&6>KE+(xe;Bv6)JxirrN2xg~@IxEyLwfIEP+yLZ zGAEE5x*Y5;!nm^g*tVO(c6nLa?i1IJ@n{Q!e`?##WZOQ#cvAGA%!lvMd0s`C>sGqT z;Qw`Tb)TPbkq{T*6Z||rm zhV*q>(l&0xMWb}!-?$_ym=1ioA$^;cqyqolkiJVxQuQ=!w9f8_v?LYyK12F3ElCAl zI!0fy!|oMP)7Wmn`HCEIoe&;*kV`+!kbX`}`jYGMc0>9lElFLGrw!@Xv?NvfM!0`D zrlV;|s`Nb!>9@2bF1@-3{-Ad3)At6qQU&4o)}!e zn#qIf@1UexGWZ(OS-!#m`a+5&co69VuQrn0fp5*Ed!4*T+EN{IMHlx59NeaEsh&{d zwrABnmdd{E2NC~X3)K7vES0*`y-}cY$Gkn0)-SnSoQ1-pYYhINZ95oL;XMKDN6KnP zCY6nCM{#&wAX7glAI_v=CZLEiZ2_Ez^*ht!1Az08=F!afuwA>J1Bi$1yBt$IWdL#C z{zPWHZ`W4u0g~wTf_pNlP7?tMF93B5g7&&lv^CU23EF3sUPLc6>ZdHVb-|)5K-f=q zFIWV95nd*hFRUt=YeRIP+j|E3zhEcXf$HmG^ec2u`Zwrt(@Ew9Mq{8;5PaD;Xe9=# zG;{PeL&MGHRUeIYs8FgIsCyxMoQ4lNa2D1Mg?Gzd4Igq~b-V2|@W&2JuN;NKuP4p*s-#$*2lZ5fa#F3ZZQ%lZe18W_)#p&j z>F!rC{nA&We0hP(__96aOHBADLBmCUn#UJb5sHZ%e3sQ=KPm}DX4P|+%HoR-f8K{5 zrG5rR)Iu_!r518VA}g;dG~7aZ_=uTkA>0v0TLI=s&Q6JhdJZqw={CR-*w(Rdhq6013?4hhE{)0Fv2oAL3e;*o-f3T03iTJsXj{Xgp z;~$n1KluudP{CfI;%C)JOJ&F3<~cM2e1fBVv`3j6&l0xtMnFBCpfSF9-=U#pP;VsY z5+7}8wymCn`a^;)_1)<}N1)Dn9?)ezDu-3}VKw7yfC6L9R(gbT?27YubDzm(glxQa3=k1g~Xv_++)l#i|vS%D$4l;EH|? zFSsfrez{I#JKT+r05}z|LknNT$$8KQKce5q@y1~JliTQXS#=-OfpbqrT}z}YLJ;0g z!+9yei4Wm4r`tj8=hXya zAABz>N^1Ot85dr6s233QepUkmmD36JLZ@R*zaV%#5WiH>UeIujm+~{ps=;C+2OFwK z*Q@M7sTx@-i|;K2pME|o*f=vjg+EAkkwZ8NZ#A}79KxLh>H>8#>i7$2tcyu60_HifOAMwM|R1 z0(%F{le%J=`=qo?3M|r&i!c!^W_C);r06vBQ^PzhEi<0GrkCRd4d1riGvfLb7FH zJq4U zyt&j?dp)7PjM&Swf<~{0`gwv@QXTN)GEoN+3KZQd@T%v7 zvx+!89&bUsC-h@VuataC}2$rpcVrZdP91Y2in^6jY$-qGFk3#N{`xk z-1;vRJEM(BJgx*4@p&sRW?Ghd<>#pu3(CJ?-pDmmc7 zQvlsY@ZALStRi6@;q|f6n}I(|oNdIRg)lpZkp}?%M({n^Md-glp(l<-QI|U^2jEu# z@Cn|><?S!ev0^hzRyP%cW$rXGsfl#Z^cXwXKFx)bs;9r@8I_}mB zT%-y9qaHIa@J&+8D$E1$7iN{pf@YjTfqol&fSR3mthc^VGlKEvt&AC0b^+V&O}1-; z6*#`ZGhI8zqXP{dv~AxdTjeuV?^VEtpN>_6@rAF?sBHS_xF0w_9dpy;d6-BrUe(1_ z=R3yW`7Ulf*d8*ZYH3NzQ+_|4Q;oDFt1mwTOnws8PRq2OSvw3fl9p*bvs#|3eR^q` z@!a(@Ycc5j%xVyfKeOy=ecj*aDy9Re7b_=Xh@#&{g_!Qe?qhkVf@q54*~9RGaCIdw)0j%y@Q|@foJw4L&t`|?@&N31N3!V z+p00teF$n5ppb277}Qr0bYcp$9O|`j8f@c2D*TiANv2Aa2tPt0tH~hhkzy?fzGclU z_d>(B)}ahj0%c5*3GZtIf9k;WDAIGxLIlNCotskCTsKu!y{_ddD`r)`rAovqyuNTX zfy!7tKpAk&C_8To)Li@;iQ;Q$BcSKVs#YMrDtZg&7JUQi!vxi~a>OdZc2s7=z%CpM ze0Rl%%e?urD#pznYvMq|X5WLD#df4$=%RRh4`EDPRu|Yxe0*EzL4X)l369Z3Qk*kr zx)e2M0PR4}WS}_*_hQ>5v}1Zym!daLvi%jKh%3bUo>>!!O0O?_-cD90kF1$@SOK%O40ucq=)Dra6GL0c=ZNplD-gt*DeIEtlFW8H&fMyRqzK_kDbyXGWeR{3HH+bnL zea{Apj^Tuf&zWUCMdT$>afzvpWx86VocQ#$C?7t)W>Svrh@JVqX7tkdQrVa5ra4u} zIN8tFf==R9EG{!HdW}{!EXV)6619$xsj0CykTuSO| z(9wTx_6^US=vyH!LGtqEpiIHZqy;!^((&G-rSI;-$#UWiKqkw+8(8$a7eY+hgQHeNP%q!B8Mu9ni)OV#RaI5;1|KdJe)j>)*AdBuhgwg=6@iWRagv^ z?vCJ}NEQ^Y)AB9iw=adY`Ld`wtFF~pxE0*YDKzEbXuXd@4C8jmou#t) z-fiIXwYf1fer;}HJMVEoT){VGQW?0S6eM!nqgEoQtKippfreaX!vcvqn~mS{pgQB$ zOSZvH7_&sZE@1Mb_~HOLAdiVEd4xYYu z)&QqDZSpK6_j^q;t8hBdXH2qS7EMxNq@U9={30OgKReuw6Z$!eppeu4z+-4w*hkRKEvIiC@-K_$oENy1JRgIl{}dF0 z{&}>hEiw<}W7;5NtqH7-$6sI*z*rHTv5wB>@EPS2%UglNNrci_pexP_;+f<(m9g^) z`yvX~HXJHOQZ}0W zB(dGlUMZi&apA>6%#-xRj~H!`tazLFd`5>DC1bRWZVnwP`0zVX=qyHOF?yF)LEq5| z(7XQ3H^-q!zRb3l;Q{8W_~>+iO$em37#}DZ8_*qxP&XXtJKnLgi9*Q=P7b9comKEz z>n1qc3k!d+sjm7Q;irqmmjQRu-^jY+I3Ob9?A(wvS58bsWtRACxxUrhAf=Fk%4RH4G zQ>c((`g^4PN}onjl)j0hEd3BiU+FhE`b&@Em{IE657W}BIA)fHaSWE0;h0t07RM?g zMjHxZQ^`G_(fj#ax@-fV6QX9_*tLYP@;1sC%35_ZpMVHtWqt>dkrCTY6#6D=>~T8V zi$m^9INbCCvV83-{3DahS2}J%f_@S#^8lU}9bYu5SMjhAxxWLr531T;<|7cntQfna zJ2{q*hh>1iZW`l5T}sjyGh=*cPD%QTV~h{f0mSH)b*wu9bXL)a&ggA$?g*T{hR1Q{ zeF*B*%#9uC*-Q`S%uN*35u~UUXWogRI{ths9?#2wFV;5lbqB-*(Od#S@`OJHL_1lZw&*1QHieP2zOPtQSvYOy;aui^h}J+~r^@WJK*p#j74#apq6ruQI*U;mD>_h;{x>xzV|+%s3i={j z;MLv$=s(fM=pT}@m)JN0C|SWyFG4|L#H(09!00|WyOz$5(b+mWI|51tQRc8e@?1e^ zj1NSf!{l1%#wuPU3wl1p_&~{uk4Sg-D(JqVGy2hh7$*s+I8HixhY_Ry&=jNpz!PIi zO;lQdk`89FevmwtjY}S&vpKAz+$xA1;{(~wVcW0BGwsvNrN(y# zUK&S&u`_VmZZOVejPDBio?qYq4i$73qn#1~I;-F_`Wje_4i)rWxjB5sI=%<#i*SLj zaj2lP*haFYvkE%X-Oz;6)9@uPQQ8AXSvnX;U+F{~{iO?V%qU%pW1#dt95YMz;}|SG zgkx6e_c&H5^__)vs?s_*=9HGbGy#dE+rQ2|&bv9RnTO8(pEUuHi3;O?S`Z%Jr74&ItE8y>0BKBr7LmFDBXx-p!6Xe zGfSVrFf(4YN$Aa06wEb?ocG(86-tX^~_Hp0$DLyCeEdq^%qFj^I~)w zqsd|}?SAK7WfuEoD^fBb>g~#4D#U>KgrY z;Ad*4h!GTH5!W(JIL;kY^!1u=ScL|@qAAmnAqXaAwqhaJ?`GVno_b=Q< zvK4-7LFVJDzN#8jc1xshUCnBv@RQ|_0Bs&eSK^|{>AbqQt|q@dKabi}Mh8&$%B(?@ zz*A0kJPQimSXqiStd8fIR0DtgD`m%FNQ!sisiD9AI@yejrJ8(gN=$ zk!!)Am)|lEubp`-S2u(dX12ISJ_49te#;twd9H847cRm~33{HTNDIJP`4||Mm7dgb zCS)IETH28w(esfSLaCGK5q+(}@Z-=09akBw6Fs6=BSmXWrTB%UsK}+kOAM;g93I?U zO{Z02lw}1yn-4ZZpPcsP-Wfmx30_PzV++9Cd8sJlsitR#M={L8aBQ~4K-c-FF1R*ix({W4JSYw16MGo9!-{~q&`>GVsrIQN4@ zH{#)%&+P>Lfp`Yo1l4VIq$b~1mx0NDWf@A!@mImg<@m_PYL<<`1AfnX1u1AHbeZ(6 zI`!x#B%4x2FO&Wi&x_wF-Atu@E85dCifm5TZTwU;S6U8{O=wy;p8l24aU!?42Q@kA z4>&|6@n4aavPpQd97Uarm{5m~_>)a*Etf6eiaM3$@++uX;p|%38ON4L`CT{PkCYysh9KL}f4nYS|1Kj6``<23a^uWNKYF9xrg zft;v|!`~zd#e`6bnCVZpI0dg0oLF2E#R3-fyjC!Vh5noW++adlUu1AQm*6Z^#$sC4WC_u zv)getDS|?qLblft$ebLsP3qHE$o5nzTqV6UN^PC~WKO-w^8YaRKJZ;L%ces8N) z?`mZwN{yw4l|{1JFbttGN`8 z5=9k=D%T}N!p9OR{}Q5HLiOXJ?VAomE6qx{gc?Vcq1KTHHf339z5_qp9@JzkAzFQC z52z@*gxUr{9;4qX1t3EJv_&LiY?+B(LBF{|O^3-SJ`IPZU%`>CIH4&q8*&;+xk;*g zmLyO3YhpXdtqJMSQZ9no3iw-MCIB?BdZp9xUj=GF!rv0xR+_S)=iN+34WNUeAV0uZg()_&xtN}uQQ^+&rR2Ku&stq}# z%8)l2s2<>fYQB_I8S0cC3Pz>Yj!1>Z7|FjCLQ$s7YQC7*GAm!}hss=S{)m*7<^l|| z;gY*RDtR?ubSllE0EWx&0=fJ@CATiW3*_>z2hcA+mp%{0Lg_2bwUGH9pz0(KRGMt? zsTs^;FRYQ0HfV|Aky3I+K3qn>;X=t3Xo7zIt6+o=XbS*2W2z|#d%}g0Cjg`CFJNIm zxG?wuVz&{vC^!MA2oKx~wGHHf!#h@*&*5mg42KSH?|IK5;7y?`R}0CrQbJdQ%fo&n z0zB-q1JiIdFoR5F^CQli*lO)J3$TF<~zam1$Koib-IO$H*2w-M$#<&Eh=}qh4M9X zzmY_C3m4_LkjQS~qGJ2RMaA@qhxSgt6rthqfqmji9iON;Q4+fyCt3JGl{-FBzGfcV zCoU?sPh3=NpSY-)K2dYhV*13DIzCZxs+QSlC-i;}`t?$|;}hj;=COU^qGJ2RMaA}s zi*kKJQ@`PfKh)vk@$goilfH$JnZf(mrzX-fbaoneTB2QDpvh6 zF!-UnlW94E)*t?`4Z2PVq=zyIY_fR|^EG1H_SXG=x2&=f`+R} z?`bmIeiV0{Jlj4^X4}=tJe?lN)9E8S$#nX3o=zvF;OcijQjZ|3ipO=4+4U&0ooCm1 z(rojEn$x3a*D16jHe#Pj^L|I2n_iEQKQ}D^faj)*yUI<<_Xyaz>6AO+yK>erFtiD# zJ&kzi$j+YkA_8`HT}R@PnEbu~ww?T5gOHy=vu03&!thZTjH{SJ%RdNY{tguQdeo0dgDvz2vL_JFrMbX zZ~p_fgBjJOK7o+C)cM+_`XiwQqD!^CT)Nan+NC1Imu!seQV{}lslPyPM&D6>mpUV= zOBF_&hJv=Y?rdB&ev3z?NO@9 z+Lab3bB{uoS`H0!@n=eRX&mzvI9YHg}?scCkFs=IWltGP@4V_)e~Gst%C zQZuFV&eBdiExJpUQ+v1?UFuS3wkxiLVDS3?PY)X8oi9s=w*W-<_lMa_Ob}^CHa+5uNSTe0eaaF$T_3$IKP*j z8`aCsi|S?PNAd^wvR-S-x8-@Buy^t}b#_vRfSeeZVe zd-Yh;ZcA6Ug&ZAppmfE>R6y>EtEAJ{Yv*4O-4$D?9o>$un1_sPPuaSEWKYRLLhdOg z2T4oYh(JVFECj&ZJ}@+~mvqG!5b(QV4T%>bgVSNU%^(ROzbiIq2ET#LP5C4&`bT8Y z!WssKZUvh!pPwP%XOPwo87x9yp9*K#3^Eb&GbjLnOK@76WN;e-(%1h2M->7$(N*r8o_0E9Tu*SGCBo2i*`Y0{pmaGq40iaC51>(M!YgQ zYg~2@@hF6?xVgc<7UO-fh?sh?Z3o$mkm2)`Z5OxU^OUshh%oJfS|yw`h>Z(Q`u!dz zonsc=3)P2x@8MuP@}x7-HcS450Nt5?+HTMbfSd$~m7IwXHZW-q7vgs9Zy@nRM+`|# z@JA}ewPDFEHX)T3;@{ehpoDjZ#a8caCa>K!=!53zuwc_)5uIM%8GY@zNs=LZm}HJQ5!VEBX)Jg>-YyTVx0*kpGnvzWgYNb_AK!>!EfAvMN(xf`?RWB~ z*{$Z!=&k1Twj_OVAxVQAT#6vnmCkENlcY!$JsN^pppV5oLLzs`fx>>YW_iNZH zyH`hfb-0A{nnmXb=a>y-{6Rm&a8HvpevbK#ASXExcKgS8{W1)*m$)18U`4&Djd6*4 zCh8K0SSV*cz`SStEG}_;!8`OvP3B&{;{AcR&J|C0iXR4yZ!YiG%iaYr za(_;O%iacv`Lg$rUiKoym()jI_96th>@7pWjJ}io%U*HRWp7HtFV4@N_)#V(ukpd1Y4DXmD89`@cii zWW5NE!z_V*rucQ}T|>F8m5X85bh#L=UGqP7>$Jh^Ko_`|Xt2P}YIO!%w_bNrd+^ln z6~0!EI9RTgFYvYUy8d#lY~YLIKMs*=;A) zm$L8s>Xl{*LjIK|3yafyrP(n^#^y7R&?^nk1PcK$4Ff|3{p3>i2m=14tcJwvkik%x zZZBou1K?-Spc(82fCvBK8BrOuu!e!5DzN!l`6U8=25Bgnc?r9Lx4;=TgFy)S859D* zC8#}2GWZn%xft(@0kVcQWLB9^FsL>VdR;>MYD2?+rKva+X9GF(CPM82uQCrH-a@#_ zVDD}6=zNKB=OOeKLikMy0iPCxf$K+A^B`Vj#)4Ggon9N;=JZZdHDGwwm)3J5ngF{zrb9F^vH;MRd(Y4!o`4TM6o4#$f; z5hy(msg@yo`Yjila7sI*rC}U=QH4oeXwZVu{k`Y5yhs!%bd?F;+=^F)d zl_@%xG@2OT^z(ZG+zS%=mF^3rYSMN!ZB#ovg;z8HBCm89{;NQXo-mT!Lsx;R=CT5U zp?>}d^J~fPXSPeg0RqG-%@8=bnnNuEaby>vDG%Xt+z43vU!kH2kxKIrWFK>AB0^sv z6zYw@4+wBGMKZ4w6rV+kAE6k2e7qtHZ1W0kFngjdY^Qk)S^Ax(902Y#F9E>4@*wno z=`^(C+&~&$#kT{C!1s5(?Y?sh<;wfck3#C~c4wmy^vf0M?shK_{$iC!?RLM8ku42( zG3M0+E6t6AJ&%U(YV#@nSDNDxZ{g6-M|$3`9C{p~Hb0@<*C86Bl=n@qG*^O47m;dn z2cr%~d^v|cKEm@JV3Uxz>Zz1Cf#i`oSJ!ka}Y z!bnwtyIG`y9zGz}W|0evvsvWAVlQ~RD0jh|SLqta0~;{0sDlT1N#REX{E0;i$^ViP z${ixD_zncP74u$Gwv=atQ1hDXyYjw@D~;GgpdIR5NtEw9C2GS_`KsLCBd9bpkB-=I zbbczE4V=TuF`yrqWfFbT>dn;hkjW?(U{P5!-qIr zF*yM8@F5PB_m$+-pdj}Tab$=fQvq(nQh^#kK7s~!6W@i!X;>~ScEfT}Zo^{F^NEa2`CoanM3C%T! zCB9IH-qbE&#R$Mc>h zo%akt!S?6G5T5`s&wDoMyeC3@Nw5l8=yG3#0P~(+NSM+0E`Q#0chtP6Hfr8;Pt?5U z-l%!ceLU|WcT zLyzRhgeDmU@+UM6B>n~&ECAbPFbX06-mFD4IQbaKpbCMA4AQ!ihJm3buzALG__2{0 z6p*+D89WEJ&ERT;{0zzg;1bM-Yx(By0|X*6sACNSLkH$b2D1?GOVCW>Z;?SV>cVF5 zA^?5{Df>tU%>Zx)87G7@_|+JEYm+n#3{3$$6%9Z17X;D}u(z)v5`TxoyJw?zZ3dkY z@-wK_3C7=u%S;L^vb6|4@-O(`o47^li@ICI2?*-dtFdiX4gDe2pMSnP1 zGI$XIn?cEYXiHQ{^vi@V=x2WDjn!1@U6@(oKNetjGr6o?BE^bQnOxq7$rXo!l+1{w z=bgKthsJ?wGtcT-X7&7;NzoHbE`OfM6&pbK{#EVq)Sh>o`&YP@_B{)!J>|TYAs>*e!<2nU1d_uNPO63El(2-?MrRze z8Gg)4pbr7rtH+=OKAV6PCnP*hDXxi5L06)Afx`PBnID!!JVkO_#8V{m?NcO^b>Qi> zFDe2*Q=Eh&us_iN^s5X&C!8t+(62NA756($Mx0$d;@mMpMx5O=rtmOPAcNT$9n^MV zm?+=_>?M6*nDWP|{5Q-s3&=5E2_0}R6n;@y-UriOYHBrx+nG1zN`M>5-M`@*>q99e zuz?d3+K29kd1rwU@=nM5@JZrLxe+7_0Q1|ip?|{OyGVY@NY8tS_K+Wk84OE0Kpu~ z@y*A=@UDrxu0Ig93jw|U*(Tj5k=FQa(o}nUGK&ts%rT$ciNv46itrcC?B$i7>ooQ) z5g)YS6>fe;X>%L;=$TdYp|#<5qs?kZFI#$3dmd3>+m5EYVO4TV&=H zNE1uqk7q4114m0EYip>LEiy%C%Y`jj7~Rj2OItf;l+uF~`O>C`YuipT;f7dB4N(On z6wt;w9v(o(nqy?LfIpi*kI%LKAqp>54R7>y!ZZIz)*oYx)hYikCE z%vsV<#v{NDrOJ?|ECM7Ow8d=@*tU2tLVjB;1cKY*Bk&71pdS#h4ajCvV|5G+<&2R` z79tRlNdp1eQ6>k$l{S;jfcTlTXeL_$;7kr58=XlSiV7VALsvtg=qF`2O{t!1(MIhTjdczqPIZ`Z6aJTMnTX* zi0ctZ?!XAD>l#9IHCU&36#`og9nX)fh6W(Gu1AB-)vy!+t!rweEu>=~(>?SF1l%%n z$4kqE9W?f&?FU3RgX04bu#VRd2oE^v37u;Jc(qgXfHTJ=-3InYVfGgYVPlS-d&V%e zyZwHvApR{ZKCm;y)1RgR=AZ3pP?`Rm4Znv3cm&ucJD@`aB^wN|9Zn*W9ngW3HBhqN z9q7SGtD;W_dX=_4te3_ZJIox|frq*!Mu(T?1CSGbrg$mz2fk>(0F}Sgq+H;6^jIcm zwa`3=D4X_Wdor!`85AK!Ql<(GY;WIrs+mAO5hoVFiQsk%O}bE=_&*4+6RXTOz|~kl zd)%E~zn$uI@0i3p`4RQfIi8Int;=H_+4$aE>W8oBiYtbvqy9iS|)(DTS! zm8K&?$8qR=C_9})H-UE!LZN36m_UKli?LXX0Df~!>RoWggDDupsT zUjh_wBI*q;z1AYjCG(TD;<^d!W~ir5*AC?`ZOLL7Uk=qN!TB9}Ts z96*TGiufWL(M*WmgvgpCIwl|xp(CXy5NU*XP!XG>5p>4F97u?RE)yMRBfvVAacSqK zkwbB%QrDuNjOvQ_cAK8`dK!LVv3+atT}Clk2iY{Hc*#?qx6mwwN`8IQ8h(A#Lesm* z^Jwe~Jl~$)(74dd1%qGew3c7$w9tGC#&l|6FSMs8P8XTcmwVou)kyMU`!ko|HIn8I zF!-vzo_q2lbKVtr`5C%U;AMW%Q|Y}MumvMlHwX>9(jF^R6V^h6Tlm*ND$Nck`YSUg z(kCCP4SmKi)F0Y@L7?=Iby!<=)l{~}Wn#iOi13!c2}~wV0ja^A0|<^1P`T(GdqbNV zJda*r67%W_A@l2HD(sQ5~}R6eGDG|rq=}UTc-I7-rg*_JDNqq zPuW|LC(&ymE6lY>or9412Y9yUe1i}MK?2p9ad;usjrc14e`nY*!)E5H+fP##EYdSK=Nhl?H}e5!wf#Dns9N ztqUX8f?okz6kHSk~y5P0Dh2A95*@eMw3LgygxJOcNcCS)>PY#bvLFL)%s zSC|K3@|j7nU8EglD^K_#Apvso51ii< zuw9ZeSquzhCt)dg0{H{&dk~0MdN%$CMV_U&VM*PAqtc`0UkOrrYz$b!IZ4!A$anns zld4G(H3>W0;z_Ityz-2kXmezn}r764YtP}H;9VwX zeGEcp#qf2|a`>j?0hDb^k0{^JNwR%9&4)DcVMqh}sk9S97#`_$Wl-?9HXF#fh?s-J zkUD0ghd&>qrqj$#XQBB33~oA~FoP<) zbEltClUu1Kzu7;kvhA_KmG;=+5PFN^O8zV#rFyQ@FfdxE0Ug{^Q*r&#g0Hcn&)Eqd?4(i-b7n*8B`4-4_)`jLbF!=Vx_Sn*W zprA)Tt1eS$U|SGv>E^3Fk4(czoCSh`HW#GyLzJ;qf;F9xU@Q`l2awi~Ipz1!{piz`JsHfOqAwyNHW&y9fptZAB}^Qd9gSh7{^Km1ZlPN8^(1HEF$V zuc;#HI9UJ;W6dFKURx-Qq9F7-*{cXeF)WJ5wxGT-fnz3>#)e zSh5NsT&3u(jdRTWeIZ*Pmf2LdnFrcu(T((nVFBOh+Lt3ekUR}ZA210IBnJ-hyctiR zwiD{x^LgQQ6n>^XU9+LQS6k>fFilO0(6K$SA9Mh+gl>KF!w{SQ9P@e?u+MMBt|RtT zhrPsT1KbjBh<5@LSlKa$8(}fp6E#9Ec$Ha#Le;>7fk!%G5|D5Wo)ZJ7%KQoc8;E~V z#}xY%b++is6`If|DLBtO1KbGV6!?<;@hS%Re422|g$6F^*i~NtQraC>DZkd2;~g6l z$xGEH6aPyaq2EO%e3gh3WD}`As?9e1=eu1+%~mTOr8($Cf267q!CVDA)}9{i@kc5Z z)c63($317^!t8)G(S2Eh3ya6?vLm{Ws5PPob?;xNfauh5U%hPr<@ z+BX_$7nw5bTbDf6#fdM}#AD+prsc;;op#Zk=d3WQma?$Zw<|l*eY(wIawlFRTHPCcp()hymf zG|TfYMySfP#s3D9_V0$Hz|?3e4ZT>hFG7p4YK!HGL;vV`gAm29%1l8Z4_v74S7|~J zQ7Z^NjldiVbh#F1YYALs?x(ng4y-g!K(LlL=OFMJ1$H9vSAv%Q1OJN-p$xDSAT;nn zr;gQJ+g@n^4pIIzU%n5vgL?FYOzf(q%ro`5nF6( z5D(2ox*A03x7=u@ZVXrMQ~mG-H^?i^J3#u%8bulIfNsF<2P^b2g%90?s3=5J+NaZB z(Udl>K|A>sn(Q4>+y2}W=sl9SY5J{A=j-qQ20?m5U?GQE$ivSF2jh19~CKnOSwF;QPN8O5%=7guI$!>(jyzGO?wXqXLT2~4Dqg&MLV+z4@ z?xH+VnkdwrC}s#hQ{~QGl=8EDd5pU#7Zv+1%0ek17|xDl-zo0lQQ#=NklEbKZUh*f;y8)q+o?tByKp2>e>DZ@0kWN1I zn{qHzCZja|%a!uLaw>Sa=vko^U1AsImKYnaXjM;YtD-hy z#~9nHRv2w0;|J&vQ3s4kenXNhHHXc%BLt_ILha4NtR2m#(mV=L`E*d=yRZi&%;aHE#m{cK#e%$EbSq1m_B z@|tdHcm5*j5~GbRb)Yu7g9hTd)W7=)tLd6_!;KNwqzBC~L?NTQ;YFs$O`iR-)?wY> zegn57A0nfA@xgkbfz0lhnM@!Xs?Cr1Zx?%1+!O(`?UIk`yJDw_s(6E>b}MY7@EcX` zG*RVi?y(PKyQtU|=AvR(n2T~NjJG(pi@Bau1^F(*DX!RYii%sb(9VFlL-;#Y?l?vH zn!E3mO0xwu9e$yj3-tX`X&whK{CtB8glq5~K_Jp`2N(H#gA0Ur@Gw4r9)R)-)@K>- zXN-hxhLt^!;L#n*F*cShz*J<`8;B=SsEk6m+Y5GE4e5I{P5B%gJIr<-gamdCHyAme z>!|ZN(!hx~Y2toJ5+^ZcAlhZJ54SerpcwFhq1`8;>s*tR9LVjSs`qn&W4hzuxczKU zZuj6uScc#J{YKIqDEis7IT8JAq1hKvUL79FeQlvRqC%EdhjypA;bKFJl>RIxr#l&6 zWl~{49VCIA?s$lh%*Wv$Bprkh*74vAS}22ma`7r1#4sC&bO%D%tHFdS^aG-J9T^p< z%KT*=IN+inNmDUr_>$t+-|TrmB0zvYAAwmA0rI=!k+f$Jt1@Ny?_shL=+dn(9_&MG zvB^U`l!JtKkPtt(xl6a6HyH0bsv`nLxLGEGUHyq*mu^QXmNJRJdJh?O|B7%md;-i0 z+_^0^tB@yE0bekSJKuum%P{FPogTxiu=pZGcT==8MW@i}1$}G9bi%Wvv}93-2rXII zg^Fg1VWGmVF^!PS3WO$LePW)Wg^42JO!g%>mtobX918WFGpzbNM11ujib4Iu{2t9( ziiK596IC;#Rni#$RkxLxJD9hQRIhx15N7xEl6xGdoF1I>3dDB5W4_(*pi>n1)Ea%3 zYdUQ!BTUDZ>@vg*UXr&{{+YarPr0NdEVvtLjvB1F*yEkE=(Pp6nr<&@7WihQzw`KU z5`QxCR`VRL7AE{E1=|C^j{tsefpg3WcL8`GGGXu@ocy5-tgUi-bB+m-j;*AFjsow2 zj_ZpN6!jRfXZZfh%ViEL{}SIWtVRJvFe zPpOu(eBI~}N69+WQlr#nlTeeo9~Q8vCcPLBBZ&@Ik)}Xyb!^ zQ|O$Zhe@*Oj$?lFZ$q00qtd*G5Fhi)Mu3m`b(}B9{HD+;zbsCIQ$C}?=0korA;5?H zSY;u}_l3&-3shw>LacHlkgW0^aQNgPtE}N9P`MRsR=Gb)>Z@!Zc@L<34s2_sStu$C z!D5w1f#a)e;UrL51~#jF6aiml8t(1Qeo%SFB2{@iLTu#@AX(*K!0}ZUa1yBOyjWD8 zfPhum4A+;FyjM@GUSi4Z3ot58cZ7cA&_4hTplO9F5a>jKYRL9Spp>39-=1X~#ZIAt zGTNxViXJ@2Ef76*KGmE>kDQm%6X&hac={Y@dcg_M^z1p%^5A(%HS$ok!v{&*>(vE| zrZC`92$AwxGAMb8=eH!*3w zLuZ4_$?Fi{9c^G7 zZ+eAE-VJ0Ul?+L_iKyp9*VgEfjaL z3HM+R1Ds0pe68nA;?N9)rgCTyLf0b17HpTCThxO4x}`;1K$C;Oecd|X^a#|l1*amw z7JPvKTfmp|UphYZ5IoFZ4Q%^h8*<(Bhv6TD^AMiFPfGmO@zvK6=G(_z9qD>JgAXet z@L>gexlFV>45+w%owh>3z7IofYOYospNN^>=|*U-Yg0fK1mxOIsbF;cGmyuIk@jE& zAtCpXBNbWnzaVjc@=M1*(t4{Fh)(kU{sKLS%s(czpN2E%m0m4S9fk!e(B#hV0Qoh# zhUt8a7M&M-840clOq1HdAzz+!g zfB+JYg?DQtah1tLtbt-LbUN%|6F`h!b%9u0WQ`-7$S(~yI)SIif^#4Ay!+UKasWfb ze}XLdY6Uz%oE!x1rNH$FJW7GzkmOkkOhylQ1p!=?;My_S9@{swU?L2>5+ z^US-kCDukd4O2(9Jl3rnR%wwBoq(w_d}I=Qd+g;2@b%bB3NEZz2YFcLX7xN{S!8B| z(S_=CHE)6O)w5g-oUMjF-;LgY%2!XG{WnRI*&;Nsz8lWJToyk6;>v0I4|(|fi^?}i zdRi2L+}~B+EP`eQU;zLCe^*%rYJq$H#g)^=o+1kao z;{$!VmpnuLV>O)1V_To@G`1}?DJ$_QFYpEiz9U87+hFjfk0PSyI z)S$`GRz;=R4ZgpH(Gcd-8DQDQSZ-8deOU2YD5lMgN;45ae`BMC6kuZmmn880&5bnN zD_MRE_<{YdZ24XNlGlRBfw20z7_HpM+LQ{cvIe5b1C zX%Ga=-pSY-vpMFdBCuzN*)<5^2B$5!73Mi;JM%)wmxtx{2B^a9R?!QNXpZTA8B+W; znmzsaIXDvcMc@?NIL#PA;V(Ii11v{P1U%_PwTm;DaREWP20Uc$m1Sa=W{z1*h7Jhh z&Ok`N?$qHOc~PBy-HASJc&q7f1ybnOo%#Z!Uw8WAa)jmUP98wGHC0#E zAken^>-BWQlm1x5rNZ8cHj49`ga(rJPP72^9B3E56MY70`A#&oPVPkKnTy~aPqIoB ziX=Iubr56-Bik2X^^qK1dV36Uj|6jkHCIvTHL=Afmiz)imZ%#nw8u_t9+TrsUymi- zCxA?;8ZoeZ0)n~n7=Sgk8rS0&eE;Np2mrf`lpPcUWEUo>@_@<)Df!C{crM8)ryZr5 zA*nIRKZ2AjkAbqI)bo(Yk9}4ny0re_%t)WPV#jAO#MWoEqIP*qpS6<4@tLMp4va z>gOjvuQ1;9UXYcXYP^H#Bb;&#wC5@L)vfvbwpH(OqfKx}xG6q}RL9+HRV+2fJZsw` zr(I|sMl?b}l^GATHyF35`HAOLn*GpzDc4GK5kj*ND$U2g$)bFw(1eo{yI>}IIz%Pe zxZ1h$_SV!%R(zve;ze~`C;a!42 z(OY1F3cpOyMe)l7FN=Da;AP>L3A$i@nc!tnFB4Rw8q_#`nc!vq%LG-Rg{PMZ!Y=zZ z!AX&C6AY2p@isv`kh>PE0WcgdGQq%U-zYd9p(Wr=dFXm9F$0P>3gR(*aGStDA4lk8 z4mF~JzCb8+3j#kNKr4|**(4@zQd1*eFlbw@_k_`=nS2~2M7u5?g4SJOUb@+M+4B(} zJwk`^D-g0>B5f%x_1KT)K5oWI(pg~@)j)0)1$w{9sSAEYQK^Yr4JG*i7D}>dLerMw zrLP5)EuNZv0Z-E-M2E*z{f2Nh-$6oqRh6a$IDen25$>XWD!fe%e7jfWVT~_za6@>n zs_ZcA(Is7gJ+a4)YOK#gM);ZH0th?Yf;$YzmzpaZY&ZRiE*bV{au(EK^RKJjHrgyE zH4F8RCJ)aeg`PJekBJA#{^)gd^uCZ(^}kL%H0W~D~~-vbW!dE(VpW< z8=?;Ir#c11i#}k_tHYmQ%4ohDrOlI1-QxORFU8n-yvILW|Ifhne|pDuSoT-1M>hAG@(HR~6t=4j67?{x!&&!iN-H9!S zEU=;@9%*o;0uSNjEw6-|PPaLvA&< zz$>Q1!&rP8g9dN66xX)p{XTl|s_hGHd0CgY6dT&|n-Jb3{<^knkaEUn2nU|CYm;pI z8n%4~A4hqC`QCj->!SGtTX;P3^+9l-`{{n`Mp(-e^$+*~#f2v8WqIW5gCHGdDWwhE z6iG)fprT*k!yt~Le*`2QMK7goT^B-ou$AUvKpngGXV)7P*+F~$%uAq z@qCp$vWgx#0RGH_mjj!FxM3=P1@DUir_uyp^}JI#L~o@(8=+7a1d1te9Awu};9&%A zM1UWFERZb5Ynfi^h_(5c4?v=tj(ri;WH(t~jo4&;HHk;!SwEkN(Tsw(n#-^rU^-Bk zUU6@e?2bsXJ81{N=qOqlHTl-5rugKuP?^0urlDe&n*BFKbd*Krn7`mwR&e#ms^zTS-idt+!@Y5pm8L=th;T`Eol+xYEJ@-VLWr5JZksZ@e z_D;yZv?-RnV;l0#2N2;zFtlu?A|Q)e&f)=ZMp72pY#V1WO;lHC7C9a9=~q9CR`SR! zO2b(om-~!*XxvHasld01w0^YE82Fi+@3;I`qlJcU7J0$`TfPfiWG26XS{VghQJU(`PdrOCap0S_CS=O;6P(Lao|?||(hwTMdhi%F zPi82my(2S}+ahKtjnru8`7@L+8Y5>YDMP8={6p`nA+$$29$JiaIz7NH zL&t>Bt;QRFH~QMuXX_>CS(qoCv||Dfpy@~E^?m{Xl{S7o| z$T`(#Hq5EYX#WdIC$?!q(wVm->1W}jH=}rx;Y6F1Go08)GkmRG!d&Bhgu5=&Ypj|% z6C=N*daa#r=4d&Eh2px$~X%hiHO(7@~MaECI1{D8svTPA1y22y%QEcB&q2u%(L`e}=Pk@gdRWuO%3=#Lu<8Te&fnW&& z(l_a?MCBHWrHW<nle zd8uMDSiDqG3QojQMMxA+(+r-A9*dMe%a^-L70qP98XAj6d@SX?9|11!R|rImMQO(X zy4D|yj%=2(=o$ogELw*^#8^~72^yluq8j2wj75!zhuVJPk3~3rKID4z#KLW8Ki+xT z$N3A1-jha~)?963=Bh&gIun1m$G-%m#teBu5)ChZROO z@6;TM{{oB|i+MX6r45JiC6w`YLAGcL&Ma(8Y_YWk4M+3I9c3%h6d!p3zVM0SFEz#R z7d0Gf+e1b%8DkWC5wHswyCD)=Jo*c1IECDBZrLsk=i+d~nJD=cX}*Qg4X2SR?_xBZ z-B8aB=RO3u;p9V`-*CL+0K5bZ=do|J;rxIQH=HpDaKkyIC9>gUaS}9~tH9=lb1wq^ zSvy*M!RvM^&57Tt%9{~lmD_-1mCu9YpS7#uBv6^~ov0jwfUmNFfDt8C#UP`LOue3fZ=Pew=f{`L}1^aB2ENqiW)U2_KCn&u-GR8Tft(T2qgDi(I<2c%-{j% z2?Qce1hN=r?*yAq1Rl0C>O|o2NItoDs03V2z7c_l6M>lp*27ss&14?0t~(z?!+zf& z?dOF$n$QOaF2^SwEG zyvn1>y9MLbAAgnc>L3Joym|=%f4mA2@K$u&aldJ|y$d1kw!a}??zZoM<9FLyPJ(XR zW4CnM(-E-UmM(OSB%j+mG!I;EINK43XgC>X+wx}$HFLS))V_*3NmqL$XmeQ zqh#sV)Bd>`3R1GQ-1A%@Zvi&|=mDWWbfemj)ZgU2NPn*|>gSAeYywl<0F0^qL6R&r zb731@jJbxUP)!tC$KrgqF2s6uL#dp5Y?N@!?Z2`#NFp+%gxL!Ia^m-Bn$f?{2Y zP@I~IdOA?~slHq)0mDhS23(Y113-n{@1kNapt~q{0Uh4No3gv01-6-_KIe@^3?=I8 zxnZ9V1m+!F-IkiAa9-Hk#Xll8{sGj-13xW6tN!&;1v_s*?b+_bj&}#3R)g z?QnUav@}ZjBULje!AO=P7~*Mh|=M}y<5%;O|b zc?a06aw7u1$`HvPgUaHLs`5#M*vhU5u*$6n_$q5T2~-Zi1e{eCBH*iRBzYZFqGySf zry#^C9{`e7mVx7|^srE8>Y#ER*sO8~0#+s6S!I#@3EWxznquTxiwy|bJ1cszF5g)V zLxAtBj_-mGy5N}se%7LKoNW}Fh5qk%R;|$g>ds2lW}Yi;?+M(Z%z*)scUI3L9)8wB zQ#7kVvG1%}!D8Q8wSvXCvnnL_t?Co{3TE&XZg^J{ac5P-Vwhb8Hs4vTL%@I5qJiX3 z_YSq)N0MKHK*R---V{#1a&^Jee1UwcM-}QY0ln+QD|GPSkJsSNN_*-o?Xl*n$p9_D zA4akJK}wFmzgDof=+27N@txIMc>K=hKq>4c!RD~SsOB2Yfj?Gl-pZ3CdS}J>63TeC zAS*NlXBM_4w%FQ&F-Y@i*3`wvTxq=5F#0StE8s604y|nu8O3azz<$H+!R5ey&e(+1 z2yAgxcNB06T=*W3S1)4+m&dF3!{b%*g;qyUsCh4XylSD!dmrP~P^9JY>La`WlgF#; z!12ecw37k+0NwVBp4x4*dP%pf28+AxL~#6WTfj-sZ65-gyX}Vv_#;6%$u~pgwb+}s zD(^tRAFpaj-i-08 z_8=XviV?Eo)i8v3y!sevc)a=yobY(n_aa-NSwjE!@v0U2UyWC)wp`SkW_0|_^yu;G zBE-Yvm8KZ12E`t)TESwESFK<%#;Znh-{1R$Zi5*-UVVjtKNF-c(3ro&>?8Zicr^(D zf4s^f`Ig?HmEdynwg*RzSB+ATCUwDUFW+YTl7nWmH zjfnEGs?+$B+6&F-ei(qzQ4>z%FGw%qm(B23p2zdYwfUo|+oZp57n*Pp9povnN1Z0{ zQ763c7S?0mKErsolD-N2Id1-9YN}Y)LnvhUV(J9{m{VU7WcmOM29xYDr-|WXPA-g( zIZd+1oF;~kIk_l4<}@+tnA61YF(((y$DAfc9dlBn2CH$GQQ;^0$DCApF^#SV!4Cl)4_Ld-#p@ z4?plfNY6>JUw3lK2aw+nsaY6K_$(!~TkXnf$9BsKVrS4@Udn24I z^{E;xAPJ*@yFG$(1#&|DM);I|$HZ#&n2dngOM|!^*aVb>b zS24*_Q+y#XD9r8iY+;s~`G?xx#R?aiV-J&hum!>fI2aM7T5Qs=o3hB9lWAm&EXD3D z2A_oHccC_;cboS?+L++W;CzPQp}pID4U!ZH?)N4R)gX9SpWq4ze?u_yfZ($Tw!aO* z-a&eueh&)v3DWm?`cW_~ScIAwOu++#8>iyA2MQh(q=)Iwq+ojRYhVj0*q8NQMZpZ# zTSmb{SZ@Ud4`sc#Q}8g>doKkuS?^;M9Kd>?r{F-=`#J>=58hUacU2%bFfBM9=KLMO z0U5z53s4{g4?l>xyAjMvV{Y5|#v7E@<`j^`J%XZ^|6`pb0U3#8fbS)YO8O zt%dfpj{MZrBNDtHrTGo%h8z)m_zirIU;%L?+&>ey$mKpt z+{rHYDdL7)?i%8*ak(!Nci)&*u#rR?-2`tFx6$SPjkvR2?uW#!aJgHE+dpQOUy$g? z)*@{c-;n&U)^a%h2NE3~Q}io|8luclg@M~4T4|`|M0Bxs#Qj@T0_4zzxVz0=(cN)B z;syc^_aNdfb~PMA+yyT8aN;g=xknNA8$&}Y@oG>KiSR0qQCeb&eKE@Aw0W_GvA$op`mmf#hGhW>gUO zdzV{H+*MKBp5zzQ$zl@KMT=w@s3p+{Q6eN*LEN@cc7gjCaYq>{7CBIg_Y`r@a=FhD zcdW}@N8IzGxTQ$3SEO z)x2*>^iWg+t)!hKdLUXP-u)+us-i?FRN_K#Z*#dFhwzJV@a<%;|mfU98>foiMqrTnMDwF zYc0}F+K%L3xn^`G?hh`vJ8_?m;_67+heS_Ai=?mjC((ydB2?Gm#BCR4mlves4uK#$ zCHMv2_B*H*Z|)`W`bcA<#1E19Rhqp->DAOvkodKqrHh3Pvf^jVb0mINd@`tk zVrxiGm)mi*tv9cLk$W^vUx`W281O%D&>JMkCMM5q>&-jF7!rv@^7n{2RGCC=@@LH_ zkQ{R$(wlm-72#pGYrPzHJvlTB|DQ8!%-1BlpK#XVHRgNb{LSaoo1cmEXQ~2%+1kR1 zP%jyO!x~jD^Xu^*DlqR+lis5W;(y_?^<2pYJdXc=;$h6n3FHmhmr}2yY{G@HUg1Rb z<^Ynf(5fT~FC0Y7m0E#By^IX-a`1O_bq*R3DI`AsLyF@l#e*G1LTYTMtvC53c_dbv z(@0VmSz7DsdQ(7>CscC#4H%!e9Z-?IvL%SOIR}uW#CmfPL7NmxF6~Kjm^6tbk5dvd z)=`2UL*jQ;%n5&{jBFme5lkXQ^=2jk7i$h&*=x*A#H@#6spWbz51icNwVFtaRTVtr zPsY0&!ei5d=OOqYf&+#JFGX+-1y6q7B$W?1F=qoJ6<`j?r{UpU#K^w`PD0E}pq=GJ z+F>Y%K_5bvH%fEjY7I9Ch_{gV%(&w1Bp$DAkIO9$?R%0GwUTJ1{7T}nt;EPNa0eup zw32AT_9Q-C9T?q!k-7_s&s8zkvl!HaB$u|5sNOUZpVvwZl^G-nMb)j}eloHk9gn{g zE{$>$DYB|FCO}$6h=Qm>5dzw8ha~Sp)$SXdaVG??Q?hfSl5uG=-i6?wB)l+6C_39> zhdi%1hR#k9C;hQ-Ec)i+#*_{OK9YJp}4<$j0BRB%gV@c565u6O>Xc8RY2*!h1 zM1n&cK?uxQBse@;5WH*-*03QsDJ@85-iqLWtAc+7cPWCyE%$x|Pst3<2e%%1letYot#oy^iMdQ=J8$kHN zXg((Y-igGY9L*mA-nqn|8qL21ysL;mGnzjWyc>ysZ8X0MyrsmS9nD`3-s8l-C7S;% zc&`$_CYs*}-bch=7|q`X-jBqe6v^*dK~AbS|0Ky;icsse{k6@V_@Ea4PFqGEBfj-q zFYpc_{=HHBdUFJrr_YLH_MB?f=aS@FiiFkoOUef`d*rB`Q$We4k!R4jKT2Z-xaG__ zTVrS9CNbv%jhz)p59VB|vC)C_l$^;L8xu%R&6%dLvjgcpa%O34Y#_Z?&TNgH6G%_X zsYHyf)+5IS(lc@vAw~nj$a4efSzfT+Ex2-lHR|4eNy|YOkNQ*2O3+dy7&V*BeGD-& ze$)^l3RKAodl-mITsgf)R?K-ou^@TD9v&TRtS>6eW|3b{?AQhH^VM>Bd- z1=w51ve_)6JnY>Yhe#LJ>B0OBnn#Td)*+Y(Th16Aq+5o4$mWB~8aOS1ZCbugaoVyE zAUgVRz)XU{dK}+aBzS(9?s_hOxZp~{Q=9EJ7bei{(OSGsWj7wj$L$pX!lOYXpx#U& zS-9u(truNVR71U)L4aAUwD+8je7qn%gK|9(11@^OkT-5axZW(MG~r<*TB%J~ZyqJg zA5<^j&xzIb=4q0>q_VKVn)C${zpUbLQWb9?@kH(2lo}?zMa)TL3OR{QA_eR&i2q9B zB27bglPdX;B$r2JCMvg(P^z!5O2^4p)amCL6W?t6T(PIDoK{>EFvt?DP2zzzd?3JKRn3Au@}RrO{%#03>v`#Hn-bdoPxZ;&0j&^`w#*9^vt|i3H zYBwq3TC)|Dfo){33@?uKlFs9C@l`@k(0(U<_YGp+ttB8KO8qV|OO;u|il&pId`tuD z%?BjDO0(tRn<71zFwkQDPM8wKuxSnu;|5`_R}5cWxPYvu-h4;mX)0zFZLpJUi)iyA zmGx#90q;;C>p9#3Ql&j(+S~)+6!8GoFDUw|7L)6hhxvN5FG-$?l&qzK_a^oX^&mIZ zdefhn<&jt&nX^c;DpCS1!Ixp$I7mkK;T`cp1P4qDegJL>f@k;PE%TYgozX9;0yJgp zfjRR)2{JaFF5HU|qakf;R&O4m=u{m_8^P{L|GbQ+Ay`Yo z=@h3?@67qsP;47{nIzY!@;~nYSm)_8JD@*Tu4wH zF_1cQpsUR!l0O%ghx6&ls#cpRB!4z6k1mFSW)dhf8sytkZ>}f#SCKZLh0P)6H>8m2 z#rM0^V%6&79rvsfw3D}?!44JKyK_pptDHALJ3*PAy}KalUsDR*i>-a3;FyM6Et>wAbm_ufyPb< zq@SI0k;YC8q>s(HQe#+DJ||~}#;~Y7F6U;Aog7F%H)pBFP6?!+m-DE`h6mEm&snFj zQv>PabKch2X@T?$&}=_Je0;VJC{%y8={#e;gyg(}5m=T(ODX#c){o1k?}LBmgOgN< zf59v9Z_xc%&VLGU;AVQiiOeW2{5IYmsc8XzA{vj0cYuw7R zUxgl8MV#~i^b8=g`VPpUQ;}py-vN|(3PeW&Lb2qWnGvxRFIcb%Z<3<49lc(tTl(c& z;-w_mz!;&z4wEbi?J0hY;Bjt`e=7o(ZWdZ3`AmzGUr5sZyXmom$G`PLHQ%7*H%{op zIQiH8&h&jT7Sj)_cl@gpx<+V&&_h(t zrg#0)B>8O?IzrmXIH7*dHuRrLkBI~SH2+O|n7{hPtw+_9FLrA=T>F1-diB#bu~+>x zEsnnww@dJfn;QqOxI~d>2+jHr;Z<+Y(W`!Q{q^tSlO6qot>mZqR7gH^q$b4L8DYj5cWp*H6K-&?%qvsv=f zd{W}*S6oo+nJKshaqv4u@1Einhi`82PwmKzqhE0af>%4#PrhetC|7WMieDi3TA^yk zc(G@22dg(F!U#cMtrBtOk(f#m1v zSKLm)Z|-CfJB7OVErQ!qyyAjEt7)?6t%##vaeW0pLTI5-wJSA_zxEcd`D8iyOqRG? z{{L&d+M(r8J1XMX^Pj@cjH6%ktr7VGp(}-M5Sl3MOY3!RocjHLUEgvk&kCU}LcKWs zXK(SUSN*4Y)qie#Q=IGP46#T1LB8~d8llVL^p8|Y_wT09mh?I<>9|rG$3J_ES3TQB zUyIOPs$bewQ0N9JXH%T={-^bA5IdS3`*uitr_ivyPKEy7^n2=;9&!5L?@h0I`-*<; z=PTmmr?_m9E3P39epZTg*j%BLyV`iU&>j2Ocrev*tVH(~uldwUewxop$Efc)ju_+F|LU4PES6rQ>^F(j2IQkXWEO@m;+qK(%HVSS} z@tIOD*+SKh5n|6O={M`+^dC((LegtGZRf6iMcpi?Txd~ui3|O`_-4`DB6Ni4)qGt2 z6@ptPG${Bqp^Jsq33b!&Enf4fll(LvwbRwVd|%6{7di{8$n>idYGeL?#cdP(2zt#G ze&s@K%>UmcxIM)yZkMD}JGR8JM{$`wY@TYzsyO!a5Zs>P6_+RJ)Q%o;^iLFAkb^?QL_+6k6BE#y1Le?HMk(LZOP=76(5|a0`SgE-}s3Y~yu;+aOeNX>ssd z1h-45;&S8Qdx)J`LKQbI4t|8-CJI&Dv^e;3!7Uc5xVdrg!w>TKH%4fY(Ah#43tb`9 zqW%B>?ewXAtu2{C(+;-r!9smYZD_LK8inp~(hZk%{KoBu4~ z&lalbSN@0ab48EZw@TuBYTxfoKc=58aih@fLI?MEJt6fW@{JC@R~-B_;V%=qLg>mk z_%*^$$*}pQ3GFM?wQ6ti8%2MU&}~9ngu43o7QfliyHnzOTAtsVK3n`$E3`@ImN@=X ze4fZh2rY<%SG_AlzD8)ne+i#@h^?^KO!z|4c>elb?P2cNx=C5`ah@LTG z_hg~2y^1Sx%9$GnUoN;>q1%M2pVmma?Qzm;x_U`hAvjIv+P6k<8-%J|TCO6ghskm3 z=U}-9zkC zyNe_~Q>d21_1Awp{c^EyrO@?4Hwty_-CMlsUFGQA97q4Zi?4I^H^$MwOZa^U*pg)l zEfDIKcW?1Q(Ua=v&yJ&iZ}FAY6_+$~IQS;P?G&0n*xEf!s9TERQlI06ZWg^MaqxSqGyHBRYL3I=-*rXX3?`t=s+C} z5~VyxfqO~3hf=C5|AioJc0u~y~^b!}E$wo}ev9DJJK z_7qPaXr*6BXuVMN>s-laO`QBRU4^6@Cpb-Kwfq0)3U0AbErDe)>fc-ZX3?`n z=ku^z;>~`e#YpQSa?7K2!9l{j((=&;Gr|H;TS3 zLeq}-_*WpbQE0PJEA{{X-t?RDtge4I|Lu}KQS2)cx>)Ecp=*TtmfMh~OA)!2TlMS^ z{?7kL(`TGu%Q0T)WTDMM-STFgXgSM;X6M`Z7@;nH@?PSnon$ps2pw^1X}U{MGJNqGy5Fy+NpJZ?oV$k>?B5a_^FOW}NbBx*meld^DY#UoXLB2vxtT zo%NE>nmGCWx6?O?T`9w*9SB`4)GhD!y~L-Ao;;!Bg-#Tz`P50=%`f#-%gGSBQ{$&u ze)j2>4j1~LPTx!O`#1AfyT?fS@nZKhp{~7(({I&h2rfSkew^stQ+$QsR|stps(xKB z`Rs_3pQdY&bTxw0bZ&Xp3$9V9mP7pzl6spKr~dxi>GgB(eMi`m)eGG&)Gcq8@bev9 z+DI2^K{pwM1IUHyBD*AE--lzddbeyG^hzqfe(_=-1W1w|M=Q??%zP z>RhXFn^0GOli;=~6gIC#Y^7rf#s;^6BAr{A{C7;o(uC)Bk{zrC9$_0%AG zcf`@JxN(A4oaW=|SKMU5tKDnj=+|$trd?b?X{isJgeH-bk*QR98CN|bwd_68BT z23Wb)-9=E*VRp86cVI4NW-mp8iiihl5;dBi8Z}BhV#LIFo2Xzse#UsmgBZMx;pdT< zXc9I5@2jJyx~F@lXS&Jn_wUcXo$l(YSFc{ZdiAR6b=4>0SJSPS`SVHZKu}oFlj5(RAdEv-{w#DN!oy#@lwrXJp*;aLj)7_cgbVpCLYEd%1 zylPf7+tb@o)twxdSrHqTNre*$AQr!|Xh&6lI-EjY86|97BH5`g%Zy7UBUOoTDq7Xi z8;x~pk)Ci`3x%e(woW}M)Yg1*Fw}lhOE47DGTBaq2LPSnY&a7=T~Bs}`ZT%;WwqW! zCfc3QJ1b+!M7I`dPvt_QiL6E$ggW)EaBoaJ^rxfQa7Rq%uk=K3Tu#XY|Rd8^O32xpktXH$!hI`DZM@1-OaK%F&yjFwUD0Z zley<^P|{Ezd(UXL-qP!n=hqSHdWL4g^d3F3e0n&O4YmZTSsLICg<1kNIRr>$M5FX` z6aDj4? z&gn5doR-NX8Y0yBtrkqDlWEZ$TJo+tR24}FJX}CsWXPMPi-@AF z6)Qj^#3!E04st=FyP{?0It&Sl;jTpmAsYS{jat7j0ahV0`=#iGgrmMy&*)i(8ow@M z3t=jPI?&K&kyK=34Ki{J)N^@75qaAnNrMZyQ|Ci&BfG9Bi2r zp(YIjV6a19kY@djXs7IcGG)R05_<%#bLO{YYtd^5YPd2+gN3GPj?7163xRf6d0 zNZ-yZ4Us#4MWqqsT1aaMXUM#m)|Aj|s;dLl)xp+CE11KB1tutZXACuHl`y~b6$PTi zvPuSs3{%CCqQ*!vo(iXRB?W4$tu_?b#2bz59>??zF+I_p?J+0Uc%XBtI&?Ul<}~qE z(rpx8AXz-wXQDI$TH_jp7DyCHrUuo#cp?gQPLy9!Es=P{IeudznGL~^RPu?!j9_8J zzz}uc&dCEc*<^@IAL5yis4og22q2!!M@b*il<-2y^%Zu>qftnj@xnQMt-0uZ8lGW1 zvlgjY8V(HaL^6Q}6YYzJW1(o*By_%dv6hx3xmcKpt{{Wgf*_YejzUxWZxSS^oQ=y= zO0}301*$uBn{EV&P9FTs9Qh@}Ol7?=kJ-$HN058Wbr-=+k7N7%rKF+RT7XGOCj1h6l#6KrJ*? zYG+g?S&iXDs4EjS7;sNg)o!MgkXoJ(3jE={$~h!l4+<`HVzGGeKc4T8HZ936?9h=U))ZrUN{$B zP78n0hKeB!G-%C@P)UOzG@1#~=#>(~Txa+AiG*490v&qD+B%9sTAn0T??g_~w2@to z?LKyy)X$>)V=Jl2qcrVFlt&9OYY()rdQ!?<l>YRo{eE=VpydrP#+4#!^`zh6fK+V4yE0+pyx2Z)MPBYpg9eeijiJ9 znp;D{fGCTWnt;fTs|J~uN)fb(Z5*LnWD+xZq;@Jv$cV@s6VstsG?SIKPmsjBL+_3z zLV0n7x(qZ}6Qg0))W~Pu*7_a<3FD7HW+JACGf_1*UQedm*rJ`aA z8M7mmieNEbgTZi{LOd-0TC`Q8|FbQzEgGA8D+f(pRhEOKA(AgdJgBUq)kUoGMFC}@ zYDni(#)Cu~O=IRYoyjR2m=orJNv!!B4YnNi)M0kT++HZ4tnxHQYzid8%0gHl$s>-1 zl!Yu``;^13{LzqVU%77~P14R%+FN;;>UEkwF`;20Wicr_pdgAH(@LkDS{AmNusTkK z^~Hvn!kTu^tNN~VGNEGX(^yDZG}U#4Bg>USqDMhMd8lZ4!Gwwe2vwM> zRu(=vi4rWgN0bOm6#0#;OlH~8M)P^)@ZAPgJnlEL@wtdvMP_R@_A*8s;t5VYKd8)u4o!FHKut%#x>JRpED?vjm{L8 z&(Fd*%PV&c<6R63)lPgB@BBqyE?1q%^}y6ZD9bB!qau$qYh6%ad4%ndQMoKGNWBL> z7sXp14;pd;T!7b1h`q47P&Vaqx)4qej4p;2b0JtEgJ%tSv_#qP)64W2UrDcLlNa9b zDE8WdHlGo;Wo@U)NalPa8g=F!U(hp-!V^MeO@Z2@^uoA8(@kZOXot`XfwmJymMNk9 zIilP=zs*cEEpq3K*Ro3KhAL%^$3%oW-^@wz!k_%PEU#trAEVuLq-QGg<|Mshw4KWH ziqvL0&nwD;lX~SzbDq0{XCP*Ww64aBD}8|B8xd9K9znES46hl>qA2WPa_5CTf!a(D zT%wkT;33jwDg>ON)i+*=uaA(Ir-^hHLU`qDZ&@O4Gq>#(rDb*%=)ABvADgH0V!|A< z?2#s4kfi1+)ro~bn7(o)a}0CI_QEw2avv;I6F$$jstMb6ve6spBL~yE8|N_(_9_7a zJ9!h=hxnwTm+F$}X#D3FX+G4tB+KNrSC*O~tA`0X zk>wc68TVevZ%QRo45?CpKKQ=zK(E+smi@dce|wZ(+D86zqE{MiF?t~}-_w=r8jsyf zK3YE}NCZ~@R2Or{CjWFFRF{Fvt7ywodRJZfwXmHu2pqa#VVf*rE=D}uGe!aar=yXD~QsI*ypsJM7tjDoEZ!v;~Km1 zTEiS&(Zc+PvT2*(c@`XF(^M=RQT@c@yq#j$&E9w|i_8Ia;8XioF#4eZ%;OFkOW^k{!%h*YvN88UhJ0=^Yg26-0<^1TYCl6pQl-eI`X;-;u8jDB6&h(>v!eR z(9Cx+H408Ve!m@r1Z8&neJr@$C?LA~8_gt!MeC7?#f%`ZUuU@64cu zaHSz}{@D69+k7pIDejr0j7$NvR;w2PQiEDEY)q zO9no%)q+)NM!xXZ8NDAYck*EJi{mEzelgsH)OUV6VfTaG1s$3E;(2~1elb2Dv+vw5 zn1vrzP{_r}uNuh9!>#X%VxauT(oLYb8vK0@{y&I zU#EN09(4-$;G1QW4J!^_dFLJSGI(ds%fvd7m#1PuDH=i{wkc7H#P$kQlZ zex9Zx%AHfZcG0B#3+L&vbAj3={JbqY7s~YByPy=$)nl=sd#PB?1@f(e3gzT+DzBE@ zLK65wBb?Q-i%KGkeLj=D8Fm}Seu}Ec8}`|0Yov`$3MTMgb7+8t)K}i~ zYE%$*>M=d5DoJW?Mt1zI_Z%UY2F_>#-}+-+&Z&sLs;>mM4zm2G`yk=E{cEa(|FpFe{@i0WYF`$^JP^Y(Ea}Gdyn8fm} zA^CcYqU^-%xB3MYzVI zm_Es}FDmd^nN^g*l*Y^+ul*QoFSct*{+_4sJ1)WuQ&P_&T_z<=mc4QTlA&-Rza6vB zM)RY1F0+e#o$KH~RdQzvSd;L|dotaaSEi}UC)3m%>Y3U08KHmhXbO@&&q-xNJZZ3~ zVV?7VpwPDRA@pzYXo3barhS?CP;zvXHQN&!lL5de4II@#i3^vmo-z ziV4cH66<-H`)XPy7n~gEqn5PHI}eJMuxLFj>(q34tObr^!D${Nl;==iwj&l|M|>FD z4NoxMTQ}PbX{(HPjIy?DE^=Le4?Yg;)96RTc`}(yxSKU)#-Vz4W(GUH!gN{*p(z+a z@VQ`|0(`E`-$Qghwm-7$#~iefQ9l#=C9QI<+Nq;?%hdgUHMpl*@un&zR8Kn-Bz2-55{iuI5DAN?Pe_EGY}rnA_7744rL3 zjW*oS#!gxYYWx?c7sYdu2&Tt%w?_?0ZV8O}@>`%FrHWq3dCbU=D4X}lospr#CrkoP zK^WZi1{&Z{YI^_$7VNTxcJHP41rDNMudz7>ZTd_1;t+}4?!PPotQuukU^>xAXIlf) z%dwTlp;yex99uck95AY(zP`48a&Dh-7EKE^C$jC>ynDe+$Qy~N7(vsDIEWD&u(Q0H zXJoQ-vkXlznEz2y>x@k6oEg{>-8BvzgQ3`pGcu(mHXV>rV&Xa)%_(`e%*eEWcGcD| z#sKC~?F~gf4?#z~BrZ6fIl;DJby=4IhjS-Nqa>glGNJG#TM8w4M^LyICY!@M)SOM* zV52=tFB*kXk^r`^UoKN?s{E~iDUl-b)&%*k$Eaa;NQ!x{d)dBAI#h!tQn%Dm`eYQ* z?uZ0M!p)H#4n81(WStimC370P^D#I##57>>=qB!&quY}2c-94#*J;0HTiR`owgBx$ zt;n;0ayu&-uMC|#S>=7v<0V)pVpk}BY(-A!8jPImkH27u9O{c5RKe=ZI0GWUj-0^! zZplYP@O~x70i{F8@j&hM48n7-D<@lzi*P}S4IX2*+2~!&&i2%k+jiutp~^XjWf#XY z9!PvGXE_iT3ZCcSK5I8eI#?+%w$GAuSWjKZ@me%gn;qv+aHnmQ>|@*SyoP3NAKh*j zG`SQ|Zaq1kzyK|scLalBniV=;!IeCl+O*A~3J$eh`mqX5h#Xmu3Gjg3j_OW`3ROx8 z1uL?fSqYf(&sBiZlVVZ=9#^~3<&I5|4X3=!3T_Wq0@1~`TPp!o;Z4>`K;)zoN|m&H zvj{V=WmTp=OU2X}CbNU*$jH;AFA{PfBIF(GIP)1epIL1_E zY6B;9Wpm30p&Y<@V3?`2+XJ6E1S`b?u#P_E=(dcqT2YzDg^1KA^1$H0Ic5l zVOrf-ibKztXp(gehkp_|h_r(+>RUH}VfPhv<7% zr1ndI9>u@la$vb)W{cD#q4_?Oe(COf%sx$p2*gFtJ8<6zN{s#~D|zgJFRe(D=Z~_= zub1tpQ1Um#7rUVQ&}YdL27K(aBud`|K}G0Cw{|Xn9m5%p)z>%J!b{VOWuWT7nOQ757IaxNi)$IK5VRp#u~A-~*kKAVvVx zIK7g~{GPCrgkK`6;Pa0>%i4Uo&4;@z`N%wh&_C{}2>oE6z~>YHEM7`JGSZ6KKaSdB z_Jg%n#D4MElc6Xy_WoBvJG}0Iqihq7k1kq_lxIwZcKi% zJRiA_9CtwO3&Znq`^0bQoX)xI2dxH1W%TOR^04Cc$3!-;k`VY@^zDSwm!X0AfCFDv z9qbM>@C~u`$O67(VF7$CryMn)WZ;KC z2bCaW>>i%KH^29x1m%$1pWKpzFO`4~uBiydp8i%Ac@>`kZKUgvfiDGcJVU^<7cXst zYw*UrpT9r)1^5ltnDP6<8SIi`ke|O3JX#p(a<2`{#RmPJMaV@SUW)-OmuqMF%wqN7 zxg2gX@mdflJSxccD#G?fU(SyIJ}6n*1XP|gkhiJ75BSv$?(H`6_aO_2mQe(`Gr#Yu zTrG#)M*ZHkiSy3N-ceLBS9!|*Mc!!?m z_hK7fhAcA}??{RS$&O`uB+KJ;^(G?OXi}t>NB;=K(QX`SV=Y1;(41K)X#v5?lQn8X zb7nrsWRd8``hG%lW*R4+MG^PbSWSe5N+s~H0vZ*?xraE@qTSe~mm^}gRy?3)2F`q7 zG3dtn9yr8)&QvI|rE`8hZH$u)3%|AEK^;#`r^8go;?5c)P%B+R|iphs-;|s9SRF%L2&{VLna@r$R@NWbHZcXn|B8n5hiPjXfd_XC<5{~+GZQw zo8pwL{v>i7OoS2`5+s9dc1~xCqp3Y<$ho{V7l*%|tnpvM%yl4t&Myl)*+7j_a#0#M z>PTM{B{5VnX$3%S4ffzRif2S!rback*EVSqBkq72m!`fe=^r6)r~~p`NPae5YSOM) z5~l(1|M^in)u`69KLjlhVk(hT;kk#r5(WYbL0>Ma@{}K!ur|~wSjB@)%$ZaM88i2g zA2Tq69bY1&Do?q%LM^r@4V5Nu%_7BLD;ww=2@NgMo)lVSUU;xWUyx?`PU2xo!axlv zrS@=lcNk}@G>Qk9hJjkv17-0xlnr;Y9uCoXA7g~ZlKtqndcj#%^M>5yM4&eXQy^DD zbAExE={i-&|0Z!vhj&Phq7?b1IFJrZACWfFo>q z&KuvV$cj}t$43xeJ3E{SS`Y6*Sf1pvh`CbPzqcz4OX!cpnTivr1DOl@6S6_ul|p%) zM{r*H0)@+qYgf>`NZX;%wX^5|vOrC4cob631e0}2kqVTCBY{@7wi)(fJ5b#)gB=;2 zM>r48BSS_nPy`vpt{&vO?NAUV%QlUO7@i+23CVvGXg~@nxO7TR20FzWWHwXS$Y-*~ zeu!hNldWfu1v+o12)T(69;1Zboi{?BtYNO6=+5?lcz%;tm4Uh$Y{)Ll%DSFVph-T@ z&@=1=rer#(nPVC%I~PR@;V^~>x0+JIpkP6ChEo!z6J{zBbN~_i7uRuAvY0A};G}?# zaAY}8E1$3k*OjyhLX+y&vp6DAgU}bP*R8|ZaT}HFfa4dSdo({#Lne3$b z%pl5dmE1bA&yHyz`y8FNm$Eq(f-5q6H1=EAIh4KtId(hDnQaL>CX1m#Lm#FJlWB|; z?AdFXNW})0G%V0~Do4hu!<^hPCXUsBv5kvZIFrQn!9azwf-d9J*2)BNp?b1Atwvd8 zaf!v@sG1fi5{69pJh{YXcjyo>v36Wi;p`C25tvFsWXmPTgNh3B+w}=Xg|IY2zh%?O zL1jUPc%2ipLT4Mf5}%@H9Tg%kXnQbKYg-+c2C=TvU^EN+Ly!vR;2?68NekbJHl!yy zAvE%oq(G>?o(`RKJelZhm*nqs(evm{0#9rX#OMzU!-2a@X@ZI$@N0mn4! z6z$X#*=TlfQb{MZLfegWK5pQ=yr0*Apwmeu6aB8Ng=%{poNj6vfmtcC2GVsMfYdHg&OG zGx3E##Y%!xt^F&CQU^|)D>xkT#7@4$oC^{>k3yaIvSY$w+RUy@WzP35R|?~UOrx{L z470jhaGAsz8|wR`9BenlDw8zl5A(}Ki00oX=6iIdJ}?EE3->Hh^f7v0r!Mm$j|TOb z@O$ghNQ(*-{tr1_0 zrNfDCJxDm)8t4x^V;?@TaL)oyYE1c#s>p|F=I^G;)z2kmY5q#8+$`}S6I-jvDZKo) zXo=vxMSA)GzTA?!`~1CJ?CMA31wVc-H-i#BeJ?i)wG4$md@mD!4H_P%jG0?gUR;LH|a6vB!$ne)5)|_7Vj3e zyASL4BPf{!yY*>EDFFX-Z~ zc}?;|sGyd6rO7~Q-)!mEh*q-Wpph~Xb8=*|IFbeP-IWr?*MXr>l!c>YRcGV)QF_m2gQR3a zTzQPR;E6q+lF6}k<0zdowrENx#)Sun3)a{kqEj+4w(b}XOH?k1vPEa_z2E|yOOFm0 zn2Py6*tB1x@CXMa_d(hKo{_ln}2axWjY{|(0=TW3HSz41%g*!X3 zt6(71I6--=5sx0GuPTqqO<<|c5;@t(bG@+ej@&bB=BQ|@oZJaylP(v{0>ZM&?8)H~ ztKB4vA#-KXX^)X>__7cdm^kqbp9k{ny%B{eT^50b#<*o6EI33h3uCeIb6H5)sWa(h zA`4fga9VXJB$q$t9nas8%zI%lb=|bZhHXB%7hao|tv|mPx(ki{%Hp`~@XZT_wg^2m zt^#urWfgcrDw*Pvq!{~sni1-;%8Lxo$|Bj`=~=e|ovJS9{%djzmQAaK68Pc$ z>xO6_Jbv9|Q?z}OIu{M61TOjF$Logv(tLN_U<5~ulcZev>$*XT=58P@ay(TDTqfmi zpmpPy>w;9*zPRPI9k8JcM_U(E7guL?9=t9P=e%9rJJgnhw$LdRC9Bu%;yCM~I3DvY zyE}1H?QXl#Qrcb7-n+g)?=4Hqonj5wROyRpnL`KpVkbwd2c_MfZ)|sA`?#OsxL4+ckMW-rc<3ZlzB7mw<|ZQw)Gy&4Hq2KIXK4^@R&5`Yv=Ol=r373siU`~ zIjL=Fi|o8+aH_<;)?_+Qev(f0S=33=TyB3{B&|3dWWbGsq*5+*L$p%nmlYJoo@Z`+ zBh_?j6Op>cR7yMB)n*ejhix>KeZ_6pHceRton|I&+{(=f?I(p{AQnw&H~VYu;7mCc z<%VsR2=DCM!)-nX+Tam744-6Bw?SPB-=Vw4v}Uy@g6QEYZ{p!jquf}i_TLUrx( zngRC~%+IDoiLw*QQWD)M878M#_kht^REKZ9H z&&{GpT>5Pm#pB9rvnUp)UZbRjU2Mh4wbCxQ80H#_OK;7hyeZ_XSu}Bh)e+YPDe9+L zl!|-|C8{wS_sUXLkqwFxiLhT=E0qp=EG3d+yNFgQCALUPCB%haW>N8Q;gwkwhpiK( zWwpw+#M>gX_ev~ESdj%k*EALLZM65sEJ|K6v}KmM7+MEUOt<7JrYz0Ec=W?8nyUvd zOqaMFw@NFp8J_hhn=ge z6VyfP*p1g^aU>wfrO#z?TrNE>%S2Rer7PZ&WyqY8x?BQE^t3F_9@JS0ewIb?d06Gd z1gz?@D7JTUJFV-yiBkbBI+# z)^3LzOFS4ac8eZz1;Tc9HxGqnu@{Nw;|L&SC6v(7J~^cMT@hu$2mvs+I1N$suWG5XWxuukrgjSCNu_sf0(HOQuO+}m= z$XA7EV_%$ujpKZyiB5e$n--kaJYNgWpF!fogjgOkSjUzR*rwxQ9Cw#WDd!@N8IzMX zhxqym`XDEuh^0fsgzhq8r>;;iTBD72%qBQrZs8{;Pn;;vE)*w>D{C=qKaKW)7HY52 z*auHI))R&8WGJa%+&HYG9GWdXOdw-2ojla8E+jW!ib@Yf+~wf1SSF&s&cfNvTc}|)^%() z-ly@KJb|ri!*17jO+R@r12z2c-E5N1J3}n>k*m3+I6O9*z#K=kGZapDix=#;`H()4 z!a0$;IB*ubQ{!_wOCTLfYYFP=O+>QMWWo}h=#6*aXihWEj${&F30tFv)9LV_C1$st z(9_XKs4E$qvP=q^UNqGoxA_+_oIV5Rh*(q@Fdov0imQD7D)14t4QJd6c zNGO5NjO9js!&dS_0e_OzT~t5bqSYqIFEe6}>C;T;scnS{qFCxyrt= zITMVhvV*Q73j>_>bw!F*i%N2bb72C^;!z7%M13ooLAHdL%%pN53W0{U-W1!Ca0Z>} zihaVBOahHk0u8Yv(ShVSRw*-MSy>zsx6vV}!Yr_l0@8UL&SslPC2Rm|7#TKbq_eK= z5YS>}E9Q9tOx`SYN5mFdz@XxTR`}jycb|}|E8KFyzZ%(yUrruJv`+yP(jbd%_>TBv(8kzl< z>tI>;0&9|uB`Wh?R*ue@=>Zj2u4mvHN_|&<0-2joe(X1=qSQDI)0xSONc_e=R$-N@ z;%jOZRsk@|TYH>M#@r0$Eer@ljjA{&EJy?g^hj@3r*&>tV$BG$M;@qKkRS_ZIyR?` z!5}jd1_F$?*ylUjn*kOz5;uCpD_cq$B^`a5xUdf?6Tq}*UyCOPL&ibjxM7{Td9BQ%eaLEnS=>neJ-m*M9e)XEK!RXsBX^8VAC5q&CcZ>?9n&yxI_X= zq+nI+ClKTV|28_B4>~>f`R*yUCGL$MvbkUuY6!_4=L5f9;=gP6KwiRghUc$JzZ6^aW)jT&s|7`zsPAk+Jt9b@-)!hF5I9R#uQ zqH(YA&x9*b-<+8)&%Yxgn827qoRT&ee0QKTI>3)`w4<`F9gIU>^y8F)Y#H`kYDC}3 znhrWDaqEN#MxG>>%=kbHfp7%VXyMN2fJW1Om}*WYXo^mK5a@F6fLlJ`T~C-$iWxR~SkW8Rv!VIn z`Ro-D2y!tEE<^ZiAbTk$1~D0&VU+2S`uYiU*FlqmyoB*&XKyU2Wx?ExmW?I`6F74r z)S-7JF{iCgBBBm?S6>4&PITvHrZ>c3{Q37Ns-w+;}DlaGN?jU``FTx=!5?OZH=O z#)NTG8nD7mU zDtjh$rZ**^tQHb$m7rX(#ySzc&YBxh2^%zTXkj<9P)%zZSWK^>K{Yw_(wHPiZ2myS z6}EuHCc7(j#L4o4uFK6vYtz#@X7pRI>_kIG=na_M>8V&;!j_TfeiLokbV$Q=JceB% zB{Gb1ref38+N@+VEjnoF0KcuR(bD*<)zWoTnm~g!3uUxv`(BPRZC_FmxH8WbLXH9Q z_+M+sGLu^d8`_aKxlwFcYJ1wJgTLD&dqcyNSM4)u&_8>{5g;5enph_imgtjcgv~xpB?C;!ft734tO*8-8H(O?#1 zjZhSgF^h$u=JrsqjzVZQfZl?v++r6yEI1D@qk{HC#kdOpP56v==q&h>7_~@r#PX3= z&T!9G%#@a3^zdXBXi(a8bd74;OQ9JyccPuiaM{eLDbyRGyro*2 zk@dCOimdPK8qokY^P}9E+~*~*5&MB0nFO?@WWTb9qGSuQw6I7^MFX!Zd-fVs7K+u7pk)?Ko>V{$*Du2eoiKam-kGX+|bG+0g3EGLu)xu}2; zZ?<&KatOA}i7*NAgfNhYa3Kr;gG%NTj?+~!U`~hPdYrtbb19l5b0Tx2A$ZI(x=CED z8QS*Wo->rZF#7#KojJ(Kik=VWKEZ4p!JQ$K2s1*hxD7!OMv|TSf-F{^D4NRr>RdXD z4XwOU*{%fJ^L!v0#atCpAPLCj&-kcfuw^1)U}WW(5Kx{SIe>ZYKD`w~pKt~Pm6HRt z^VJZiWHgdt)1A~y6M>?4;(pe(n4)F+e?Ie2MYHIDE^VEI;T_(HE`YzA%*O!4^1LyC z66iz+TEj@PI^pMkpH#&`$wpnu4MN%mEFJ`hQPNYe1 za#EyXmA`-jEf(ouZq-aAFyG52q1k*CW0b*^>Zw`s#$^-d^WpxLn=5xYmrh(-9PXTp zDnRm@+D^SIOtVXTUEavK8M87p_BS!GuWbhVjK;)cVqu_$`9DCg;fRcmHiU>;j?(SJ zw6T>(@kJ=3G91b>Sxa^-(|Ta-7=mZWG_740UxC0HL^VpOtUN$CAWnT`)s|B2leGl& zVu+l@+0?rp!s-)ygv)D&y34)*rYE|iutw5SwzPRPOAkF`38r;|G!`a8CmYR4#^EUn znw@OfMK(;dJJwd)=%bkVa~8(>f+08$=B!ym0BcCoNXnWaM4>>P=Uf|*E6Wp%t|wa! z%1+H^(n$DwcXWm;!`aHJg_t7ERCSZ$>P>g_M60M1s+twe_VjjCbtlJVR>a2PBo54M zq^ra)45X@luG=$8*f^?;WtnlQWTc7&xQbN{ub2#b7>7f9l8JHb9sZ4rCSv1zCf3*2 zPpoYmHCbcYTWB)ROaSY#bjItL*B@$jE`9ya8W(9*lL%T`9qc9}9`{H{3uIE%AX?Pw z9UO7&>=UbbH@zljrFx(8oUWSp5VcS$$;@QNQ0}}`Z0NMg?AgQ<$>~^z$LxSB=jFuDW2bG=UvV@7EUTVP{F0VY)tyt$V3oc zO;tzB9ib$?*$|Vg^w^ID#!L@%iWbb^;{;mFoz1>UX`@e4uwc)An3S=PSlBlq>Q^gV z?(E;exqp>CTEWAbYP;9rJg-Olc(igop#W(%OW00ys&0|?ndSTnn2gy+YGB3DApz#v z;K4?v*e6EyOPyRSW*`@nl}OKNC41Z^VRne(EZj!d85E63nnpIwDBmsKl(&tS?hG~K z{AOr+tFEo__ROtGWjPJ)B!2}=(qQvO;J0~0jfQ*FsZD|jTz(5sLrCt`B(muS0!nDU zl$&0YZ!Z^aGiJ~vS9&V*NC|~hK{nyD$gk<0o#dG#C;}%7Q^-6}tI3@Qt+WL!Eytuv z|BqV;4HIf6*4Ds8kQ_3xP)Z;-9aKSJ^555m?+W?2LKv5hQ+`5s8vG9^Y1t^!nCT4$ z>t?2tadU@+weQ*x1|G@WY%ZUKWO1zs@~mJsDy7uL$+REiD%9Bxa|;yP7N77UvK^da4bRwt*gvwk?RpT3D}!GrJ%6bI?`fS8wXk*hU%(+02}xtM4Bxy88XS< zbVP@#7l(t6cv6JS@LSf?w&*naSPw2vP}atrFPFmV78-$I+>u}&-bR+WU?Ur6YlnR; zm(2Fi_j|I4R$B^m<$oC^v*VjTaEkI023#hz6eZVV8AO>&kc&Y6Af_+=Y`Q30`V|yG zBNw~Gc4e?nY$qC$P5E*{?bu+sn$+B*n%*!&P>u*n5at=)+rtb?d%$O>{h=79m&r0s zVjP@J!VN8i52_K6GgBq8HSRnkENvT2xrmqNygM&;p=K&_Q?-WPLo7TL5N9sMbskyX! z)R~udyP++cuEJattq7XTA!HqInQ5MwtFunbVNS1w=Jk|WE0zgnADPnxXH2Lop~bOc z74Fte;Tj}EgL%=L?P?0q;tN}fW2)LPKWa_yZ43^`?*3j%~d$_xs2Ci;X36<+My85Mt>oklo{z=J#F09HIOSmfM z=EHqbP{ceBC23^lzmTIGtDn&f>JV1tImsAVI630ToE+ba3?1L|d~LmLP%;O979&@C zcNf|3Ii+TK%9Spoh?X@snTIu4a?rez$oZFB-y)?FP!^vIY-*T9rG^o04wKp2XD*!| zVqj{^&PxMjuRGW*C`=E*BBjqmq}nu8$@cz8z%-;^fUsI(&$b zQ$5C%IZ{hGVEoRl;1FUawf~2wz5@*tCe}_+#MEz{s{>40D+*=eliGSQ>64YAbZ3w_l%(U#)J7)ZH@X4d&Fef*Mzxr zgpEJ3gtVc)VSE-FDCpQP|W_LXI2XR?<*BC;l} zk77@wF2!i0bO^DFmT zrP-Spc9}y2eD=!z1**Fk9bNDs?(c%Y0yF*rPi93r+oiFr@DBk*0{!sULQ z`-3Fw$UWV~{zVuepbxpl1E8TZ8YfD^?B4+Wr>uGgQ%R)9Co|n0pr<<=rx>vqHs?Yx ze(7T)PADfD7)4wWMZ};g0(5D#0a3>wOP+x5NVqEtk`OwO<@*(NVcsJirjI}njN28x zN&K?-0u>f7VjVH!1Kr>^E6BpWEeVv1_z+`kz<+Ro|F4O$s=$AGORS1f*<-9K@IRJJ zrtyQSz<;WWn8vCCKgn+PFHjw0RS~1Ah*2%Df51ak5u>VL{}8~cg3~}xR29e*RY5uP zszC1PF7_|N2myVpDv&#>f+&F>3H}Yxf69tgMT}Pk=wW5XFRKdnOI5)MCEAnSz(`er z|HMA};W1DR*h)-R1Ko;h;J3UQV!3Kyx2OjEGCTr}s0NgtRRfAHNMh9hRzYd7-LKGQ zI-`B~4;=VnPLG4J>^UZW@g+Ppnq-vz5xbJu>x@>gvdK;wme3D>M4i*4_=$w~x z#1A&+3a7Dk+lmaO!bg!A)B^p7W(WLG(djWH~+=1To4jV=L{C#;B)+wBwti#?>I3`z9?ULg!*E7>~dW zSNK;F2k8+%3Gs`K3iu;_DRMl;BJrPud=%Ut=t|REa|1=}N#|IxFg!s|um#0vSMy@_ zDIuI7qj83@ho%!7DCeR{B2kt(Qc(0viu8UXZc`oU_&vKEf*<_Zg?0x zG0@Q=jNR}sY=Xn_u^WV;OCB(Y;dc}hEtlskZg`kTolWx8Fix_ngo|gi9W?HY>5UPD zmo$;4v;<>F}nH>aE$#)|`JD(g7~d~BkCOEptmk(ku2J58$$g4zu%F+F zxJCu^%Nn4#MiuZo5ts3v7~U^yf#Mp~!0$v{qaylcO-w-CTvdo$5t}hBx{Oe>ThdS5 zld%c<$*8IvjR-X=OXNU`j8zOJrV7%sar}j_Z!GEOxNRPVBWo!SHFv&mhz* z{q~FCLGcR##so56bjQ&Jpxcj!PRA$L+RWy;n3NA?_%EidpicU=P**HW-@&vw+xUHxngq+zU#D|&QI4Ba^ zxoV-_4h?!5g_Wc%Mi?mRWtk?}{}|$Q#Fq0cfrykr7q3a=s$*Pe7ea0)pJnsv` z8=TFecl1VM_@W!%&GC>vBN?QC;X!h7BSX5-pP}DjKN%FPmp#!Bp8E0aA9Z+$z+dzx z_!H}nI(e_u#edN8ve20L5x?koSukx?iW}-b@Wc8MdPM)h9{DeI9280&2MgxUvIC)4 zMSFw(eujeeAB{-iq8I3InZpuMR0uq!a?uO$j94##o(gH8xQnQNnGs^Ld|dU2{rz#R zpT}e+qy7fDQP)73@+ay^SR~>YMJ7Jum%fi+H>{6A{H|;i%ZSE}v^ug$W^B+>A&d@M zG@u`9vWSacZi}!0W{j|)43`a9ELxwCEAhjmg@-d$1sM^)sK8_*sm0iK$Jma9KSN$& z@`vde_SkZ@ZOH(lTMZY_^h0|%XxTolN%}$w(kRqwu`4bAPh0x1a);u}*{}Fv_u&ja zhXhaff9MfWcMddawz0mRdD_`slYyl)6ha z;!zUomCQHU8C zg%}9I6fB|lVWVb@moYZ#W!Jyr zJ|WW6eb})?Jo8BOg$Z}b!iQM6wd8?7s6Dn1i`b1@?$6EIGuxh8zdCW6lV`Ral zjE<=u%!OsT5x0xEq<}=4ImNfE+~*WcRFJ}7cPCrKCqc+HMw^9`K4#lKV5T~y&2F1I zyF$~nO@Oty8HQiFD6B%;k==g-|AzwT>6?Jv0DA)V0_+Xg7jPip5Wt~;O2FZOqX0(( z{*7xKeyafiK!XUQ@J4apgx?8(V*rx?#{s4Qf`FNT;{kI3a{&tgEr50a;aH5{C4exX z6VL;Q0_a^5zbgP4@!TtZ>0KZ02LNY?urtN)D*UbnoCR0|SO>TeKxx+F_fm2HUHpCz za2eoAz|{bXa}9of1h^h>qX^r8-=6?(5zn{c_osk60CxiJ0^AFD5b!I&uK|w&9tS)L zcna_|;5onx0LtfO{JswO1K>@-+kkfg?*l#rP@HY}{U5+bfR6!x1^f;0cfdaZUjn`Y zP=$X3Kxu~HcPL;N@l0X6;(i!l55Qi4ZvplO>-49g5$>0Y?Hx0FDA24HyNW z_oMMU1~67UkHc>jAONTlVfFZJ089W(1RMjH4449#2AB>A0%igTCkgQJfVqJAfEK_B zfL6dlz$t)J0ZRcLfKEUUAO?s7l7KXz4{$nQ72qtu*?@BZYXFqbQIGs`#a|yj?br9* z^4hUC-@j_`hhwsTy?D!|t3H2V(Z2oHo>q6LKKi=-kH6?|n_EU+urT$~b6bD^&?^Vt z^qU>8Z=ScyJLkWA;-5d9|Izao^uE8tzmNLEejAo=ySr-Bf-O(Hy?)FUpN!gf?xR(e zQ!ZcGz58!|wrs;ccl&nT;kUo_(8Iq8{BrJnXJ7Js`{w)aJFg{kUf=KbtlaI|A1A6W zI&)31N?<_>k|?52No-mVw4EE+eb`Owy5{+h~ue^k#SukCi(mG6Cj=?i0i@TGQC z&zXnLTJ+57%P(K@QN^K6l^;A4Pn~+yu&ZDBefWm-i=^us`Fq=Ut{Ji5izlxCaMZzf-22i$ z4?6Dj!;ZSV^3k3fPHesWnlJA=p>5rLd)_ern*IN=-*qbwzIOH7x6V5EF9Y|j{%h;| z=YHq9_a6N1l4aMo{C(=zKRR{V=HLEmRqyBjb@*-jJ@C_w!w)}Y|1}q!wQ20~Zw*g8 z_Qxd;J$Lq9S6x`YY151=?!V%ppI>w3z8{ad^Z9q@EZ(DO>fA5S+MJy?A^FJLD?S|f z%c;BH^y^bzdF$4zPWtk?3+jfSz1PEy(Z{MkxoUa;N&YHvQJr{|Z823igqdjARUSFc}r=;m3k&ivCYUq0FYqkYai>Y7b` zH@$Z3lPB-K*Yig`6aVjlmzuNPZ?vpBsP2U+JAOU?slLFeuRS@b`;0YPPF*y#`;o`* zTe3s%m`w{Bk9qs0RipOX`=wcrR(-nL*-P6lyz8pn-#>5H`zDP(=8C1yFTA7nl&xD1 zzJ2bnb&ouG-_}+8MPEIle*U`ar>t6bQuBtpH`Xq0d#n4*5tGgu*RXBV2Q%J(Znv`z z>prRH;qUEn;k<#vPyJr)sLivV`|#VJ?7V98++&|UY0B&aE_tKu)%7`fX8AK$U|51l`|{)kz}?|$gn3&wuuh>J7ZuKD}pcmMwUm+Mk5egEmVH$HXG zO;rc{@|sQIS00-ZyY$sBk}og${m{&YQD?n>LG3qYjJWyGvwQz==u`i7#yvMAe|*M4 zuW!Dg>W`V%ule0GdtY+jAFluH@YqAwZ`$d-z%S~a>)9~u;4f}}?br`5{^8WWeD=rn z=ggQk{?kdzul?RD=l%JOQ&S^4K7DNYZSO3*U{vK^cg`6$yz1ajQXlTQ>cgM!GPmNQ z%g;`{{l?hC-fjIsL-fgmQV%R@d9>z{<=Pi- zJGn+b;2&#O_P!cBuJWbxS8h9e`Ienw-7-oJ&r*X8Hqj)*e3PogZp< zowM@D&3j(+mn$Bdz3_t_PK+$f?pfV*{l(WmK5*r2-7jtnefRQ}#|JiTy6A61cKjr) z|KzaN-@f?fz`h?>KeFbFE6#iH>x<&Y4F7Fk&!@N4emrU8%F}ngy1QY*A5VSn%uAm* z@VGbo&sjNP?M*{g&-?B{zukLy)gk}-?wF1Z!)9N3#~DZbTT33l<+ux0&U3Z9Jw0L5riFoP5A8T^TFtpXy#I%<5mt?zvP}ne|uF$;NY*W`+oTFNA~UM{%7*;N4I@F_sO2& zFMayTacAuGlb6>${M`EAAMo<|zgo}{s=9U7x4Ms7@#d4^r91ra_D4_u^0lWne0}Ja zBM)tD?Yh3T`HJV;-@B)A=q`iD4%_#`L+W4O|JvD)e>iT}^X8At{^{GJzdw8D{YE!b zt*scgdf(xf>^yGRqG00gCBxBw12zM;0JZ_X1Z>Fq&on)&MR8 zYy>wO0CNFL05QO7z>R== z0Z#z70zLx_*$4eKpc*g*&QxEJsa;4{D%`=YxKo8&|z}0}e z0Gk1?06qhx_D9};O93|no&bzE0Oz&gNnfQJFk0=5D^0}MF?=>Q`DO@MYlCm;)01Go%uBj8{dsAB<>04;!} zfHi;{0e1m51GWIR0frq0J^`ixS^!G{mjbQ>+y!_7@Cx8FKxHN30yY932D}6K3^3$y z&;_UlYy`Xm_zW=Q2-E{$B%lc}8?Y3R0*p8kyau!bIssY08o+gcy8xR3F9O~HXd_TZ zfDwQuz+Au*Ko)Q#;4Z*sz$<_c0AB!h{xnx47e9i z2}8abuoRF2tOINXdt10Z0MX0j>kw1=tLD1@IYQ$SCk1FcvTc&;nQrNC8#@ zE(Kf%*a&zS@GM~1Xy6Al0cHc10AhfZfQtZE1AYp47_bGf4WNwyPXLvGNq`nWCtv`u z4sbPK|FNJ0FdMKKkOHg*Xc(yM4HyBa1Iz&Q00sc-09OKT2HXpH2k-@8kMYP0PzRU| zSPZxb@KeBpfTsal0G|PdR3UG`Vn7P88n6-YFyL80OEtm)7XhvYYy@luYz2G*7!m+| zfI7eo0FF)5IssY0I>1)ICx9U}pb0PoummswxD;?5;6=bE0Ie3d03!gC04;z{z(s)T z01pG61#AU;0T@qo&QF! z%_pGsQ`F5Dm(( z4;#RThroyDz=wCihZj)(UH%Pu1rMf!2fOT7p*@K5e~9w`2<5*FWq%jt{te1~FUlQ2 zxsOD-Uqre8gmQm~^6rH}>w_rgRFreIDChV``5er^KAfiAcjNObw}GacK+_$dX&Y#I z6EuAUnsxv^`+=S@?`zsY;6*EF%7UizLDTV|=^F=DXk!imEud)&Xc{xJ0=l(A`x?*> znxdfTK+scDjdxQjw7H;ZCK8p}iVK858_n`^6m3so))5L(%@| z%{@Ew_mc{gVfbRqe<1Fbf1oY}9mBr^z9DQQc$J*WaqNWtlJ1TM59u12;dvasoIj5R z4U}fVvI=c0fUX^O1>m>+Uz&Eq9MGHM;gygx3LlH`L4+?A;eT@>sJAE z?bFX`Y4{e$zdt56=(2tE?sH(=tY`5?3{)ec#I z7qUgyhmf-!@%zxM3hnmU6*vR5LVFs}v$#TAEadBz)jZvEfeLNX0-o+hl%MX--$q!# z@1dNgXF$(MlPk1O0d&<}%G0jhg!}Bz(7vG` zcM|pe570uX4x`B`T))O75z)T`YXLU_=*sNOW%0og(1~bobUg#w=`OJge|~Ny`UpH9jQ0}(N$_tyU{CO_ z3UDC!*94&J2dD7-r;GfLgD#nj@O987q)%2tpO8*jx0UOa-@M6n%e`-L{qp$RT*v(3 z9h4J#=2HOanxW7&q;Ech4kVp33Oa}M&OA^`x+hY>_0MSNAJRcvpchFG?Fv0ay6D%? zMWl~@c{tZeL($GiFTFR4>!w#mbNzGz^b_f*>CjQ6r#?fyk*?aMn(M1wr*NIM0W$jE zfY%_u-+-)+g=~=?+X8tbT^81J`fT|l_Vs)D`J7jwbBJ@$9jm!)d<@w;O~_v6L>}i| z)Hz*8KE~^2@oxNiUmIQWeaINe$$2RMLn!;Q!_a4=oLi@YX3$922?Fox>HPVY(|N!C z8Tx<`=ueJ9UqM&JBA)*O@PV$c*K!(nLD`Q*+3ETUa!Gn}OC$QVP=z)-TA_Ur=kFc{ zA24LnjzZnnqTcJbV*c|@%!8u7GpOrTsORsYjyIr=uSeZ}h`RkV>U9X}^9l6t>rjuk zfS%>3yE~7r(7uOqT!Om#YD|UpPt?=ppzBuD&n=+$jd_R<{_lo7={m57)Bb(*&2&An zf5j@w*YgYc^JKI+x-Q7_=Y4kN&l}I<^s9E!m#cVNy&CO=?8D}%IUDg5 zl$TO2If18dK}St@)SuI}YJk5d8;q_If)_to!k;gL4Ab38A&;ZL_k-}o3zS3 zq5lA#fVF^|0Z#$80e0UDdLMtZXUzK7KpIdA$K=G?&x}d z4Nph5FJ0rnQ|kZ6fuFC;2G7yYoFn*o5|}`?qiTz61}?Hk&I3NxCh0qiZr&|K+Xd|55&LqWt@y{G(9*V^RJSQ2uEs{~0L%e?#A2T6=;KRp$$HnI1{k ze@=w1KBhu@{8;|(l=ZxBXq+g=hjUPm^j6LdEx459zgg7pcp=|kLw4x86Lm@Wmwg+! zAS;t6K=)4P?^dkjX=xl!*E<*S{G!m+e-r)DM&JdB+UdKXZSKb7{VmPo9laC!Jpf(P zJ2+iqMPG0t%D)4`KY&cs&w(L{dh_5zZ5wBYT;p8(Eb2u-x;)jEadq$ z(Ra%^j^UW#Z33R1pbuy~bvSeajj0aX%Ewhp-{fPfQ{Up_t5cvSXpFTKx`M`8S?CKI zYpsLMpz+p)=x1om^)z$`jk}(P{-Ckfd!UxaUpGU~(HJay03U~)e=r}5EjpBs$F4b= zkI7b#;^VS2NAt1SpP^r9eD(o!42{wH#`AI7g;jj4cK&gEy!I68hQ@4t=nHAw_Alrj zId8jAKSkCh~Nwi%lAX$Qc$3DOG|r^!_1~ax!7thCRy&<+ zajP9pHn`RPwzIvHz(>4Z3jSXf?;m?3|@rAdi1Qy9b0(S6z_3d(khopwIg; zfUXON@-iHKIDfvSpV!4wq3_N@xyha=Ru_cp0*5i-2+`iGy5f!XoPHYj(|Dh*_s{3~ zCxxDwfN(0~*(l4;0dx(X&FvqWm$S~ty#;+in53>a2yr1!T6+y_Vc>jg0naC}hQ}ja zMAvb!H7FmlHKc8!CwQFaVN=re{JH#D_M<;t%y}orYF|S(2-`PNr*w@HdP>d>t`&WA z17w=6+l2i5=s+I-5D|Zo7(4%I9mn@%Gk^a$eug2PRoBb;RkC^H94oC0sq?Hae3SR# z)_Lmj7jpjo2x-63#`75?^x!$);?Gw-n%_rU{V*>(jVbB6_C!vroHv_m(H{Y{eTw;4 z^mTOoSB5`RA4AvKi#Z)s@3)D%pMMUo=UW>wrVU|y8^u~noX0<@kEfUO;je;MRDU#% zko@{w(DXa>iFDm2WMePr0J=^Sb~Mei(i|(zuhQHqT|XJk%e=V~Je|kG_J2ai$c~@` zK-b-pPTc}^5K4s~f@MU}pK8>Oe zq5gyV4(d0k&!GN-`U>hNsE?rjf%*pO7pPC5{($-d>IbL~ApK9epY%TIeA4%H-PFO$ zLGz%pKi@3cl--gq;GQG2s({d**Xoubs!ssIK9h z<*@d28`=}4I(i~c`w(yte@38v{A@Z8+y7!7Mz*lDfqx^~Q5WLT^#im)s1r8U-VwTr z#@mAc8gpL=pmF!R02+H=4xp`11jm^77oY2{Hhns}X52q|vV4r9yjd z*9xt7cZ^*@*LuLm(A`Tx+m8URbW~{fgT{XVmVwS&1g-HTm;aTR8+m39^cDIyx;C}& zyzdk`@h>IL54;FnOqiY#?Pus?oF{VaVWVhI|6AkJry<8whe7mHG=`u#t(O6EEU_4M z4c2PIAq$5?4$goKj1l#J*?e9$vd!pfw9%yt|IYQ2swcNjaUQQX3z;}qwAH^tN0L0# zS`n=i(RJ%-Jl~M0`@RFX99q|(<$Tj`zr*8S3_VKMwV+115Z`B^GM4P8NvFk$*Tg`Rb6xc>&AH9rz zmu#e`U?WL8>6RUNJCiy>&Kb1BE+o8b!B=WqwEimF*Q+p6cECI9e8H|4aC+sM^owXe zq(^8j^ee#eXtOkrLv4P{Y>ai#j%aS-`{E*QQWPx}$Z1 zKt1|k$Tr!2H1;Puht|F1yudinPx$1zJf+>R7nj9RC^y*|H1;A}z{+1e^TC0b(k9+BIu-cO6`-bU*L!Cq;8qJmgAD+@JrEN*?XbOt`)jSj-fw4lh?Q1 zoa3ddxL%++E1IvOxhk5cl5jcu^8;IizL)be6Ib&0)GyGryXd>*{Qt|KmGY)JQJN2>YgbF3@oNYDzFF9;4MTXk z^8^q7CGcDY-9fld8-+2Q&>z@%f$>$&v#%B9TsE2Gc;XD+2Gzcv`gygF-vM$=v87$L zL6k}M$M?5$95fDg8tc9s=XFH=HTBihPg5T)`{$c6{-O44oo7Xm7DS;6_1zmqyOwJr ze}nuHy|j)?*B59LbSK9(#6EidikOA#j??(FoXbA~gm~$n2f?bY*8UsNudf2TSlolo=dvhJF}XQ)5zG3Z8G6Cj^FT8E?YgY*fi7voFPp`<@a zchdE;&Dzwa^En^n_@)lBNIWMW5AyFI-wx^5@nD+AmHkQubOK?PYhMq*J|gy!-X#4< z*V~xSqA=1YQio7`r?+wpbPwu;o=IQP^<;#Xk=E8}U7gm{X+53R&}sdgu63vJG_ntU z*3u5zgiS4dmGtMiEK#4Cr&poBDQD8FboD|8=}wM`Plev0GN|LxTcB4-7f}B|{etWZ z#zUrwe|Gl94@5bs?&zZVTEbynv;V?ktAF=&PEVzY+1wWl;-=S-kT0tr~05dKhmFa zO>C*9&l}A0`jG3j^Mw8+o1d=tySeV5b#S^!hDj#KUxxY@@|lr+%;n$Zxa7QKn`mP+ zw@lZCLXOGrjxPEAEXT~}UMQTNsnxLW6U8^SG+ra1`5C%o9J;4?bWs?|HkF(76NRO2 zTes_l1847&ZCkhN`qk&J{PxU!pS}J1__o_u-|=lEBC0iavbLLz*r_zmN?1E2%C0qEYfWq=qU4oCn}fHWWj z=mVS%SOr)OI16wNU@hQ$z=eQ|0L0FV0pA5&2DlP%72sOH^?(h4TLHHLehRo9@H4>A z0e1oJ1>6sK0PqmtVZdX6-vFpgkK^|#z|(+d03<`t0iFlE0Qf!NHNfitsQ>>*+xY<0 zIk*46x;v+{YFnFTZQ6v;wzh>>=q7};MlAGL_p@egYh=sTXp>26gpigA*?#Z$eO;ZiznAI`ux4`b56I{X9&10<<*L? z1K}%#c7$&cnBR9`2f~jCT?pL>xO}tYeg%6Fa?bl;N%18c9|=BZ$YcC1_hHfL_Q?aXa&%?zy%TGQlu z;QOwppNklMT}JQPdqRJ=o*MPt(Nps}-?;T%{=W9n4TX8_ofkZ4wNDQwZg}sb%jOT?w&*y_#cQv7yWIZ$V&~*5en}tvPyPn;u;gnxmba~$ zxn}LX{`_6!B`a3nmoog5=iguJbw*I~b1RR(Dx&hRGhR9O>Z)CN{GIRQ&g_o6$IttH z_6?h_d2&&F&IgY@_0=^2Lpol3IA+vk!Q%!U6?0;7&9Y*Mtk^UUq%ayJs(3 zd~#4rZRz{7?&)eg;;!|d6!3SDo64Hc8oAatF6)YGT+8}>Yh6_zblb5J*WOV-_}5GC z%#3N-c-I&H*26EHeSPq8kMZ}ydE*xJR7bwO{(_~yem88(@t=fEF@GCc`RVAaU!Q+D z^^Ui07 z{n2^m@Hx}Nmgn8xd)0-Dtk%&VY`(m9O!>DHUoHA={@TYjt{nd5&@-d*PK$q|>4v7D z^(8)jAuo)3`<~bhLyu0*^bNlBu8W_m3BUZZ#mj?_TC(EetKK?3^UGsrj;*}A_Tu2z zV@G>mKDEPmZ{cyHw!JVT_uOwjSiU3lgSDTH?(UfUPyRmh!!H&udhw*{r3EJ>-yTpJ z{Pcq8!_S-;Fm7g5$)igbJpRd6{)Y6bqdNvz#bqa6n0Rhn{GSC|?|!BP^SR&G1$YP9u}D{r|Y zD!(Y;^n}c%zpl8n?!HqikKgr0X!?5_cARwo^ealH%r9;^;_df+|Az=&r?j2ih|904~WjEZi^^$u(+cUc0#gQlFRd!mRA9lj@HSPJq{N3=jEB5qndF)iH zW#y0C{9as@H=w?3ZujR4Mo(N@{`=0SoSTz3?fUbSHO@uz$1YoR+%LY12W-lI=EQTB zMwT8HnSb0*XZ6pyd*wgZef&iJj$bl;e0Rq_Isd9zFWvX$u3g>zu&(=K{X+N-;ZKC1 z0Ib&try$HnxCP;UgervB5I#oeK-hyYI1t}?LWn__i11H@YY_?&?n8J2;YEZ-gdGUG z5c**Q2}Kx>a5loF2z3bGBkV>PGyr=A!UTjw1PdV>VF|*$2#+JwA-s$5CBiQVu7UWz zGr~B8vk;~r%t5#rp%mdUgj$5R5n2&W4Z?4w5T+u`Ls*JXhVUf9O9gBNT?h{&Jd3ae;S+=(5xlWs2O}Jha2moSgjooS5bi*zKzIh> zHH425b|N^jQ4d3iL^u=S5`-BDxd^u-tU_3i(17p}!gmONA_N_d@qlm&!UYIv2y+n% z5SAlUBD{d`4#F1*-3Wd|aTY+h7vXUP{tnd-2ZZ4WV-eyICL_#5Scp)J@F2nlgjW%o z5xNi@!*H%Z7=v&I!o>&~2-hS03*iBTbqM^u>J)@I2sa~?B0Ppri|{r=E5c3$=MnG$ zLL|bO2$vwtK*&Y79bpy1dIbK)^&^Du5dK66!lC9Egi{bMKuANFi%@{D9HA271%!7H zzChsbU;Rd)y$E9w;t(by%tXjXxCdbk!bXIx2%jT#Avi{&y$E9v&Oo>r;Z}qd2u~r@ zBfO9BHNtNQhvATQ9KxvxNeELB<{>OaC`0%T;ZKC1Fx0n5&WOWtkiih*>t#$gj6kn= zhy5pG1|cOnZ)}*2Cyuf)AkxOi=i2z?JR8^JK!%jpr`pJyVxuh0M#Bsn18~MdlF?V$ zxF^fT1-UjZyurp*c{W&+TTv6NCtgKZfMCV;0hgR$<7p}TsT5nfSW5dHXF4R=k!jHW5xuJQKmZKAq*y*tZm_3Yoc%-!6XyCqdE`bdYu zO}(Nj_NWTq6xFlK-FcmYZe)qW-f@?hdY?4nbljFvZ$69mFx5Tpx|{m+8>0HrqvH3K zm};z#Txa5K-|fy3o)Y=35~gZ<*jf!T z>;%WkQ2t7W^7adC<%COY6v>D#oN7zMXWMu}Msz<62;_f-XGDK{yxiA2Mn>Te;P;CT))jPs0P z{uv+U72M#?>pe7ps<*4`y5OBx=c}Un>1ns>VjVaAJ>%xf2+3;$)&=dw>($NAdh&|e zE_p?uH#Joj78#aUg6wr7{ehjEs(*#KQ@swEsv{qCr@AIkRQ$UGYB(EhW2zPRx>fu( z8&%dXZq@e#z!GmTGZ}VIZ8$KC+_BHN1d-1|1UumjtuY`is}V`t5H3q>XD&12epJ$FKhUWWLugJ zH$u6=vhj-yzO%2kr3u+KPDX!dSrNU`x=d-`4L#3PPer*6Cx0T@uSTUb`@=N*buiTID|DQcqF$PcU#?+Z56yL}w(A1^4AvQS z%kMgxqA_XJ@I82lhV!3rt4`68*|gYQ;-r3(ihI4*e()QjI^VMjy@!mL*ZQ~I{#uKY zs0zfWIvvF8*ZHElti)a7*Z+{(XMW%|498t*8tz`^UheNhC0OfvR05v(>>PJueqES} zpWNuq^0o6s^&@kR!Ev53Y9SRWL|4xd6;{l=6X$ndP!leJM*6{^&g8 zX2~kEyxd*tqnh7HP&?~poewFV`Eb~W;sM?^(Qa6|QmQ-eR=3X&LyH)DnC7+DGNitF z7E2nskFUNjvE2BQJIe<#MCla%9Sik=$);T!nh6H(%FX=!GlXm53WG?ONg)myz%q>vin;?o>xC5LK>6b)&9KcVX&k?fC;! z8kS+?soQQ>x6Sgn&7p@1U))2|R6oFqhOc|ZUYm7buAVPmedYM!>c<5P-IO!*MQ?Jz-ejP@y zHsVoj>W!YJ?$+!pJ=w2@uW0a-)2_?LvF_$|Xn#HG>8~4f5l(J)r@C2Jo9jG_89)1F zjVHYCPW6NK#HYCZuj6P3QZUtJ2s#}41&QjyFn1%CYmJjVH4fI%_PA%Xo%6dG9{!Bm z@QHz6(4GC;JilNzxyl@%_9Sj@;nRK3iwO>2+?^N4i>E>{*i{ z(LlCw&~kShFMC*=Gj_S#6E|QuFx7611MR!lbPbq?H9%`$u6yd}U2fIO7_l^5yVmXK zQk}yKJY#CEwsE|tjhE{oZbgB6rC&Nr@~XpNhU@rxMZNljXVsa}E2$=Bx~qCqe_Smg z^?g`a(6!s;LgWX`LP*nOF?{%3TY6UZ(cdq!rE{m)NKLbGJ}M4_kB~9&-E14%(0oW+ z=h_&G83buGhB&~NQyuV!=NQAA2>lQ>L001jjp+(i3Yutvbb?fej4~(_{itS9#yKI)M^o>r96WCSV{*LPo3C>x)h~(mZCbe zkExyvbJyiT9hLE(ON%3PZ61rYNV7jqE73F0U1H$-l2?ysVxK)gKBKux_QC=gjs^-t zHvLd7AR3JY65(v%Ey0J0w)9N0jUQx;&XF<7PfC#TCK;UkJOolJW-qWb+s4Z>M&o3R ze!kUK#$!$)314q%?ejb?+^8RAHPyR2{n|&Qquzi=bQ~0^qrXN5s=7s2<0+oi_)E=x znJ4?P{^FcRQ5Wrw_q97#dAehgx^MvYZLR7RqjbnFbNA3}_<^0)f0Vnbfw~i4gBhWQ z59!hJjzw<6b{NqRliXbiJ#AKc`tfW%M}F=(NAA%@^+wO48j7|tucHmOCwz4iden2| zovF_8f^*bgAFFe2^*AS9XX+KWiqljVVNGQAKCie9L)7pGPgP%3)wQ0y{`^GR*a|0U zUeTJ$@T5B7QOQ2tGkJehPrQokwTGHsle}J7>vkc(InH|d-{V&Ci@#JI|GisPeTArA zec7!#98-X)2CsIj9@m+6k!PkojWwL9vclY{hC`-mPN}=oUcyRDRR|VzE*p3~sLg%_ z%~n;ej@3`ld>s?-W0ufx@H_6j-qXA;$HY^A%?Xe^z8GN-rpkEtn0kMZw5t-6P7`0J zhsSp>au>Ww2lhRlf&DxdTo(M>yY7PTQcphQ@#GLy`FZxWlXS7PZg!Vgi;S4pgR9&n zuEaV+)r(kQv|jOpMb-Z8 z6oXETBE;5?b{Fi6RgH^rDtS?>XDWGTv^L+xyFurQ&w+e zS&?50bbbm#Xm&J7dn)q)6;&nuhe*4MC?<3g2s0rW1HK5TpRU+m-c<79V>DX zuy_8sYTu^uA(HF>`(BODg7Mz%D^mN+ZkEK3=XIt|Hvg@#qjLj{nM%T`C}wL3D`S-JWtPlZPoai{o?aAzA#eKWlH=3<#%Yj z_TK^VX=BBH|NP4}|KM>FACAiHUB5<+j~OrVhswWF<2x|E_ileA77D)j#~%6WMc5~P zj;;18IYk&OIADCP*7(3f#IMu%9>njRf0E{3IYA6lkn`T-CrjgdPnGzPL*yTPnndU{ zJ)nM38o&SetJnN<4iVp|@iiK+9d|(fb^j*5UgJAa&At1tRr6nWy41e{Iq&VCUX4#a zL*iEh@XrC`r(5H-e-4OuohkOoz~1HO&lP>D#)pe|fPJ3EC+%lnqV`)fe*gAWXnaka zWE{8O_-)Ymp0gyreZTx&9ME{Ro-JGl`@Q`Wq46d062Ar5yL~AdpL(vuXTZOE$7gGN z-T4w9y?fKd50>$P2&$$evifl^>_^I=&8Qf3e2z-~Kk- zx!|klG9kO^VE${=_|!whM_exU8Hb23*7*I~A2VO+YU%Vv4c@Edfd?n2g z#_l&hvo(HF3{TS|u|0Tu|AD`l>WvpH5WL5Y8;=LEjh~LGIG)esnLmEkw0X1UFPL{_ z=Irs8;~_-j&!3%>x!}t2v*wPSe{I%SJXdMXoEh`RE3;-_IbNQt151x?>>NBg=&Jc+ zv*%79KWAF@Y_IW2v#*>tZQjE1@iVTQk%dP9%^QEt+-t7EbET5-D58|PbF=1;pBz7N z{`g7Lre8EUb=>@ntH&>xKX3f(In%QiWXu>peax8g*PZY;Wix&%9t)L|kuhWD-r>z{#!~|S z#*Umbj|-Szs=NUv!b z8FS~1n?9Yp16Of89X4Y@){Ob%DU7va$6`gdm-VrDKKi&!-l5Y41)CoqvN|;fTI_Ne zcmg}+xicZ-+NW>%I%nGS%)T6FEzBN&;)&xUB~HbYWwEA< zcKY0F@T9@{^YL)K>}j(#DWB&3vbG-IAT5|&P|*Vn1n&BpNGS42j*wS)%&&cL&X zv+y*%Ie3Wp999zk5i?2RUbP?w;D#91Z0=ZiPNDi2yE&fvXFp3BN&1V#N8_r*2CIk$ z%SwT$0r+hJpU#ZO&f*EvISZje$;dt%Gk>Z+XApJ%ulmaFlKr|#Jv0#C?aZ2S4GKeJ z7uYR@%6^hM9-^CNR~P4=tl8Ia>$IJfA#JDNZZ^7-PZ+h6v*m1Ej4h#Y+Ich37GyOY zN0nLAr;nYHn~ev>kIlq0g=fqgn>`PYyPm~!lI?Ru&YL=Y>P-8Y+UNwBdPc#FsdxlD zp2<0%zQkyVh3{w2u`lxIaw!)c=P3fRT~Y9aQ}%Jbim0C?LtcYWb9*btd)(1wW_@Fn z9mq!QEknF!T5ew}?dZK^_sGO8R4z-%6CSgt>s-8tcDlVa;82aJ*+T^+ES;k1&UQlqWmDhhT~XnE+EkE4;UW9Qoi>J3~B( zR#Tt_v*}sp-B%9oY$6*Z7Jc7aSY|Akhvf@vX(n&x%CmC&ydlrQ?aRJTJGJkjw=n4& zU32Y9=re0YkEfktU~oxgMdSgZBJfGP)9~1BWW0|W7002TYR(OPgmvHi@JtMRi0Quc zFe1EteH_95#+zZT9LL~G9RAKk$8m`c{{lyd)3`e$(P6yc7&_6{+cDC3;D$t`^*46+ zOLPo2-aEY3;f2KhNMCT!^s6-epZ`(%ql^b{NOXivM5YD4hGVGHs2`B%=x3BKOmqyG z=x}s90*z1o5*>cV>fA)fP@~mZaHv>cALI683Q*^(jjj||EORq<3~^Ug z2BOws#tdY2Nv-2>rxA&FDemn0Jh@N*{Z($#x3(kR^eTWKFg+gMcY0uMygRFabHjfk z=EB;L#J`*iM;R|;Y#%uhdHES{jjly~FEJ`E?Q$IL>~frB4+f{PaZK$&M+19(^9|^A zrbEFm_+lj6vl4@*&fuVNqQRBNxT?^F=qIPEN;=ZrkLb}cKB;i`9VuNX`$(tpju)o8 zmvL;DG%x>uY+gH>cbqiuVQpUhe$Bi8FPhh}SM!$r&&@l|Y5Xe93)SYe9*HsKS=|1c z-gEo-Kkez;@)8}#iYsomT`}GGR$URVJ>5CF>ySNtN1msre>Tub`}ee~>VUpJSZ`;! zd;3_YQReLviScY4r~Y{MNLSncg+Kh9#k;C7aC3t_Y(@m68)ebMxMQ8xi_WjjDKB*8H}lqBv>xr z+ABje{c@vhA!GU(&$w!_>6BvA@pi-;8|{t6&-fm0yZ~gFwJI2~!iHF)T zxc+!H3S{QxUWu?%a3|Thh-={WPU8`dOsDbbVtY4WiNj!% zaWOmh-|sot(>lC$DZlmqXz=fMWcqIw4y1kBUdUyUdGW8dlm8|ye0-Gg6$a<W3)JpioaNwzT0bEDm5^u_aE=={ zdZ^RQKAwg6cH^L1?i+a+=c~M>S=dt-%Bcz4tOM`Z)SvTQIZmTsu`9>ejdXa2Ruua9 zMC+;hr;$Dp-qOT=#$D6;s>SuknTVPoVPA7Y{__*Ze>wEz3?V*r81=Su{EhEN@~9AM zl-ad9&gg(oZI{~(+hKb;#CRC1h{yjes(l4>0oucPtlfm8fw7bC{fsR*{u(Y5D{eW~ z{J*+-IMyh;2g{e8!fE{GgWX1ZZ>RL$y*?O)0g1+U zH}>_(TdqVWjox=d7Mr13%yOYk!q z0yq(E<*`PcDmQzS;l_)qe8r;-HC|HXCXaHM@ve67jECmopU?Xz;!W5859z2@KU_rl`$POFTlH6T=@B;{H+W00P&aCTRyDc1H%d&1N>c2U*d2qaRgrMa9rRB zyp=Q5ZxU)Xz`4ZXz}^S>~_tQmD*|C(jWIEjD{Q01O6{K zyy{WBQHhlRRV{FgC~)8?+>9>af$8=+Jo@<=y9U9Z_szr>iFE~T>gPJc5pnPdwN=PrkL5{DSnsTkKsVsbiMH_+E#&yYI~ybeC-tpgP6 zZM;7WO-Ef{m~XF7sOO6VYEjI-ZRGLzCAKlZcn-%uALF$FwYJ&s^HB7^bFJ;rZSxEM zQ-`uIkTIIYMNWKqmwlIGsK4>beDr3ZvEE+Wyo`FRP#n77=WxP!8Oz~|P}Cm>a=!w& zdy+jv{hh|^b0y)czL>B^J(2_(&tvd=ZbJAQJA-+o-LS9=ad&VQU@UD2@C=F+`ru|(-}lapZ6mNcV#UO9xhXKw5x2yBndN7^gq9^bPH$e;Vc%g+8B@-Hdk!AuZM~;`&5pnr*lgc-^D-(^Jage|_mtcBzL}q~f%nZg6me1Z=|E4NIEW8%+YC#;pYifd zv_qF-`09lFH-+fUx&OKlZk`x94@TBH9R65{y#qGkF4JVYW1oz~&ao4N#+GJtU9hK> z)A;yG-UdD3mLJxNwlQ3;FSPSufBl;qbC~i^MdH5P`;!y-hE>57^7F@WZRirL_}j3m zp5mTRPNNG$3BLRs8)cO7%qZF5IEGxt2As`!@NsZN1$1KwzjkAnPZVnK!=*eA-^pRx zbt%T9dz#lAxVz9*;UyMmK9!$Z#5@YQsZr)zTAD7zA_BX!Z?Oa(c>_huf z`{t{*@c=#Q`Q5+*^mO4(Tz{~}7+99P9fuifFy9AZb8t8VTnijt-RJ`x>pmI7V|j?N zBOQ~0=UAj2XKbF&r76VNjTKH#x9$_I9bbcMamN4YhohW*`rS8vqsI3h!oF7H|2U}q z5Tg!@{xNXtxI{;PmW0XhSqQ4K(=m*P>%o{iM&UJFX5Z!+#APBaZf8{U7|RL`WvVxD zcbZ4=5a{j3*$3-k#_hNTXQU?@VH}43=$SEeP_R*vLcQ%E<0v^x8|$&r?{iXqju$F= zYChC^`!vm~D<&;a0pFMbt>fnMTYK%9p7R77FU=m;8FuEPbBw;9hfW7Y+<0;f2Fu@Vt zgL#8XE8{jjTf=|Xq58NR#0I^HrqHEJv3ogvq6Qm(*qhl>Y@(>lTFgCfBM1$wOTpA& zGQ9r-{x)jI;GfsHf@7f4^?k|ya>e4{H#)GldKWwqF+tO`A4)l#C>e|k2(O?6~;E4R^JTMEl(IiGA^aqxdWEm|=XG z4IkPEgT8T0LnO!M4NK!TT%AJv(NWN6EjRh>?Pl|l1w1l+g(K4r)H}|-!lT;%{>W5- zl13T#&%_>p4GF$-8V?<2FG<11@?Z=nJwa_4USO=mCDy)857deKpP!%}Szw=_)}|ly z1oivXJVD)#Yrwt}RI`tLg8I$>ASbA8NAd)8l`S7TH^BPxh*r0F++i84(11@LX zwgCnI#a(Ix{aom0A4PEV`LiF|?`5pOZszb`;v0td_he&c`FCT2gE+48mQyzd04C>S zH+4DA#vPf-aDPewkJ3=?iYRbI;qZ3~lzoRk`-;YJ*688y3EV-)xxwGqzyoXF*+0No zg^w*mCt=&<@H*cyXcDi=c$I>)CsNYJIMnr?(|8)|fPE0dW?eL$wFxkG;_TfI%iJ#a z5$zGg^j#wSo9jSh$8^kjd|Zq(l9%z^oG!-@9$HQ`mSZA$PApi_nt0V@+>7aOtP#$G zJFfb0dUD=^6HFIAwCwvV7Bg%4wVYWv>EYM{n>+a-MhIMsd-Z+=#^)IjagMG$0^3b< z2BtX1{SjD%ZW9p$sqc&<$&k149nPj+#v5`ye$W(_dDwLc5*LCn$4LaOhCI>`8$YQJ5MAxVxS5Qh!(BF7*sL_(7IQec8q)x-Z;T;a-80w#KR>6YV_qTXvw{C!Xne zj=KvZ#LK9-3L_A^3fF$C1V^9K{1L8Iv3XE^v%+U1x6_1}=DQ zj~kC&jm`^j8Xw?lyMN!M9u||`i=j7+n{j`d6|KCQ_1n_H-Ub>`bhp;D9{SCdbO!kEO|8!4yUG{{3;qK)DSJn0Qo=}g@smGoG?!PD0vvVZg z?vx+)+7l3mb1XV%7wmZd(4Th=;nQ0kBe)_RhH*JaE;UT|rN-KWUTXZLmm2RKcqxF< zyzj~VX`b9)ys5z0>_u<;L(sGPW}e*b#k0XGv6Z5Vg%e|oo1=5hkZ=^VEg{BREb z(90(chw^<|5q`*4+;z}a+-2V=4lyg(|#p z{^GEe8_x%1;Qsd1t2pKN9Wj{sN4TjU!22FA%ce+8_$Khai2;S8J{WTA92f2gLsPSJN!hV~^ zw;j}ei1FTm6JpCy`?&r$+(CGVAI-hFIMH~{KGI+)ys1OsISz$47t1>IeBV%5x&Kf& z)SZL9_5bNz1baff>wS<3F`N^EtHQ|#pA+{UwC9QzaBU4SHXg$Bf2!we4(j=F#%_&& z{t)(iH2%4R+7B`Ea}HR_R{U)}_bz*`96i_8*K_6Cb8YOoa_zaV`g-mM|NSQM-aT}v z_y1|n`QkX#JlO6yoNmv;_0wm01&#^ET3r0%t2+Tk&m7cg)nfZQGPs<=ZD-@bYj6(V z5X1|r_4>7+CimBVcoo_Y@fEmBFab9L2Yd3tM8`$iAp4TYcx?_&&A1}MM8@pH7I@1| zxNC%ukqlgAALVbn>(zzN;uHA=!-sGp^EXZ}aEvw{OXp4SPoWrKtj2qspx(omS+Ed& z7RF0``yQxKn$C+J;|^Sj*)hC@g&5>C71NLRL2nUlfciw2(St4oi6eg@KwkS z$~utkU#D`V%H=ATs$8UUzREc&XQ`a7a;nNnD#xoFqjHqW;VOr!9Hg>K<=!i$p4}kp z*RFD_%1tV7Rk>c}8kH+S_Fo0a{wo(+W#Ah0U#ZY60oi}~Ap0)|q+J$ByG)^#0n#pA zXr_U*O9E*Z2huJEq+PVoiUMgDDKsNM+J%6$3j$j}7f5?AkoLXPY+5}a?Yo6$CrJBN zkoHX=?Y4rn+ak0YK-$#{%{q{FRUqvuK-!gov?~=_B_QpJg=P^*yIhcVSs?8)K-#4X ztu&B!sX{Xaq+L8nyBLsmQ6TLig;oSeyKtcy2GTAFq@6EFyWVuM>k(SrAniJZW(P>S z7Laz0Anmq*EU!Um)q}LF6Ph(3?J7aqm4mb^1!-3zw2DF66$#BkkajsB?J_~yrGvCf z6I!Vt?NWqhGDy2Pkap1^?IJK;wyz_xyBc2d@dM(_#B~`sqsk~9|xX{_*kJC zrSZXFJId+B@83T~`+9^{HMkl2Vvy@*Ay^3Vclcxu$n`N>nF(_JNmDsRmm9tdNP&ox; z|0jX${{*2G53>K`gk~(r{*MIN|6w5QLO|LD3#}lKc7a0E1=6l(ir964v}*%t*DADH zK-x76%_fj`4Is;_16#mqkoHv|?JI@WYLNC7LbDvCeKAP;e2{jzAnkI5RyIhxETNeR z(k>OGT@pyUc#w8+LMs-eU5wC-25A=#(k=v~T@XmSK%wOVY3D06y+GP^ULkgEAnjT} z+BFNUCXjZGLUSufyE>5Ntpm4%l_2d_3#|%}cI85|45VEVNV`06JD3B~E?a12fwapM zni(MNQb5`zfZM@1kan>`D+Z)pw9t$KX%`04E*RVn27_}g8RR+^4{{xg6PnQ)9}cqI zP>|(@2(4g{tlw- zr-ED`Q-o%M#z$#|2G_R@K*mw69RPSmLwz_g0YJDg?RC<|}i-X2@A8XQ-U2 zaa2ME{BK_S7ay)bh%~sIvZ_w^<(C%-cl@7kh{6Y3tG|2wu-{m30LH1La zG6ZBl1*+_;a?fPl&p^hvsobJ+qsm)Uu2Z>MCbU99+Jy+sV32mcAno|)Gilce-VM7Bq16u3u1#pRg0yP{ zY1aVKt`4MKjnJwFX}3;jR)MrD2WeLV(yj=kU7^s*2WgilG;=}PWrDPe13B+wg;q4U z0{S43>xUP}{iypQ*|$1{W*f-(CXnTB1zGMEq16Dg+fY zrOM?hm#SO@a$e_y^m8sqKj#RoY>RT8l+t~ zNV^b_c0nNR0)>_fq@AzO^a5$unIv{?AnjT}+BFNUCXjZGLUSuvjC6G%%PR%x-x8r! z1g?NS1LQbM0ojiUAp0?1XvTo-=Ma$ngcGBkPwzyVRvq{f^yT1tU@6G{;osLI3qkf% z9(X&L4c3BLs?Sh;s>;bK$EzF*vR|WAj?nlp)d#CSQ1zXO;-7Yq{%I3htswo=A~c)9 zV&uC8q<`u_`n4LQ-8!LF1=6lkXs!lnR|?Xu2&7#;NV`0tl?&1?M`&h)v`YtRmjd1i zCWB*ByGW3B;ULQk1zBE*&Fh=!ZApV}u*p3A0zc!Hl(5!N!$_*gvQwOp>HA1TzWPR2N%_@-fDF@k( z5|#5+jsky!-leQLU&cu_$njGJ-VRo%T&8ld%7rTPNi0mC4YIx&DyM0DvdRf6$AL^2 z0kR!oAlnftv_e3(BUoq#foun#Zp?OcpC@)5Ann?PRvWkmcCA9Q1*F|pkam2Q6U(as zX;&?@)`4qaS0ywnLE4ppv?~TVZi+yTn?j+P4@N@H6Pmdo^UnsEf0oe71lJ&4hR{q0 znSV0K{KG(wlR%K;r1M-ECygM-Nj>-=Sf=`XkmDo;d=>g6kp7HQIY#A3ko5@%S)VYW z6$-9FeL{q0Fv$A&f~-$ZyvXe!!otN#@DF6O7*K%Ukb9m#USfjB(w@a z);C{h=7Fql7RdUhgBdN4}9lGXktYx=@gQ@C8?cULahO)O&_avlDy>`bO|Ga2?nLW`j=nCkbTv z@gUdd7?ACYR(+)E!&DAYIZ$O^koE2{C7(`^`Lu)7x2V2J^)(>dw+>`KR|&03ko~+` zXjXvi=Ms?ZD+Fnm2huKAXyt&k%NCkhAnnpX+9iXuO8{vXFSO!7+QkaZ7?5@mAnigy z_HPKtbvjsR27!@~1BIq9NW1P>vFiX?UK_~rT7^~%$nu(nW)n!e29V{IfM0-lAlL15 zum_9-_kfXLE7)_o=vzUq+f^X@Z#BsATds1EG9P3=(g5>UaQ)5Z?~|3v30M-&T!p(D-VQ^<1s` za+OO|E&`cPzUs5V?T|A;wkJbqrGsown$S!I*`5TD?TG_v7X#8RT4+Uqw2Ks)5g_eC zK-vX@wDSdN=OwgyW5ljUXm*3NYXfQ5tnwC>E5IGlmx7CsPl?bf1{Xpu5?VRncSsiw zehc>E;*M+rpGUezp|u)h|CfW!V2R2_D(8W$cMiyUXA7+?knPPBni(MLodUAn2`a~^ z917+`--Ca>6SVtBXr+U8{|L=g(C#15?jNuPcA?;>sBehS z3IgwkzVl>R-;BR8&s}Sd7a9YDwnHVs&bLa`6_3Fwtqp}zd|b=wEZhI zQ$gFm;0LHrEJ(X(kakf*D-xt#gwPBJX%`IA&IQuW3#45yHa*bl0cqDQG&@1swSu&3 z2HBsDAnmt+v~Lhv^&su*gk}v$`$~}Zq+Je3yG)RF=^*XW zgjOm@yA+|B4AL$Rq+K*fyGW3B5ke~*q+OWM3H7kalGt?Mgt}6$`B*kamSaGasZ~Hb}b+kalSx z?NWtS3P`(Tp_v5IE*7L+6iB-WkapohD-5JvsL%`nY3BlI*L#B4b%V6)6j~i1?b?NA z8%Vn*kaks|J+FmU1-JtGJa8A71@eAJIv9g|(u8KR#>auIZwz=h%8eFUQ6S5W6q*qr z%MAfpZXn2fy+G#M8)eh%25&`tE7%6sfJ|2fVrfjO6q@DWSBTHo_#6;RS5mgn%+UBG zjgJEZ5FaZvqclEP<6Yp%i1!tmJ>w<+7Le<314uvB3#~kG6ZFwwEf}SY1i2oCgG<3s z@FOr-^?|DI9Vhx8a3$iq!4JV!koL_W*V8TFonQlqp`TPQH0wZgeNv6ktOnT+Rp8yI zXQj|u4YD69gl0L&ekcan52+x}&B@?KFb?E-J_uyH0zuZt7i2qna7cR(Yyv4as$37g z3Aq}41S|*Ho>Yxb0t+F>s~oM2REB9hMub;2>fak_(`pB4*9@}UEy{Y;mw`-QDzx%J z);mv`t4s%fV)@EQkoonD!LxP2R`7Y`(;~FCfXt^Jyc4VgQMIHRp;-+gi==fzvkbJ) zl_33<1Ktj1g3KpF^=Yb4RyjfCSe2te_IrfNVHzKz`asqDs=j@+^m{AFes2+4%^>@| zNoY2L#mKiFWWQH~+rcW(9xp;`HE53)p;->nt{9|UK1jPe^h~; zUQ!1GI??*Q%j2(tg0L5}w()fa;tKY8FPFblj7%mh)D zqzs`M2GTwhWcommx5P%Nc$3yb{QbYR~mR5m;$~9CV|W+ z5~QCaz~fMlaG@Cn9s@a4Xa<8!7X%&)eW1{ENqmy8(CkGfOxFX3BVD)9>;#!#htS*t zev5SLz#qVT@My&63C$d^9r_HA>7qckGg4^vpb|er-wLw5TR^sV9mw`of^1)r%Gn_8 zvxHVE$aBbQzC*xnuoIp1D%cLve@!ZH1)Cw)DXYNkkXM78XB9%L99)BP z%7kVq$az)>a(?E4w95f$mo2oiK-y&r%?yxsDIo2l!9PJ?a0}Rt!SV*!3{t-utOYAT z*1rto{L543g4{QAK+e--a4HxHGJQD6_Jx3~Ul7Rp1qv+}$olyTO%7Jpuk$FWUpq*D z)q$UbmEdyNuNGQm;5X3cgZDt6C$zG`Cg|fp)*}XFJt9>OS2;xGAeDVp?#19``cBa9 zHf< zgl0U*^wHoH=%a*Y1jzKE;9<~*2+bgn>A4784t*~sIcRo+Oy3R;hQ3W`wt!5(75oSE zTZCpk$n@3VAn4Z#%}S8z%RmeIQlVK4GJQT61bv>+%mJA`1NDDVpCBZX!-$n+uL0O*5-W+2G)USJyZy(4UzEg;8P6UcG5Mdf;xt3i&VDv;x- zQfRFPIgToXW;w`yF9zA~g&^(nK-%RBtsIbc*+Mf5q+J?FyJ)Z#3Zo$~h`$shqBIs>(?!$EzHpa+J#9Du=2Zq_Rup zUM${hM>oj&w}JFe3rPPo3#}%Q{%I7NTS5A#4y1q9fwZdxX}4NvRe-cB7n)@t?TSF! z<$<)z0cn>lw6Z|jWeUv^eZ&wSu&325HwMv>HL$Z55hZK$cen(yj{J4z31iS0S{@LE4oG%~Ftd zg&^&6!R=r+NV_bdl?l==LujUhv`YqQ7Y}X+V?o-*2(4(4c2Pnz5~N)yNV_0#JLm#w z=PR_hnbWR!m`$?>q+L5myB3gkO(5+Wh1OP(c3XsI14z4Skam?I?J7Xpl?$yhkand) zvjn7FK1jPU^D2ea_`|HcY=&>SGh&yCY2jN)~60+eQJbOHOTs`6Pi^Z>r)Q0KBXY- zib2{H39UkqcKJdx52RfdNV{~ElU0saIa=iikbVpX>9_VF((Y!E`D_81PaVkkbzlRy z8l+tg$bN|d+3qNi=b&(vLqYl}NM)DGz1WPIz8hqGyUML9H>tc;<$9HCRIXBawaR5G zm#AE*a-PcBDrc&krgDnP2`a~_9IbMs%3&b=9|F?xesmev5Jsv=glQ?A*=!5a$3$91~ct`@R-a%eoHzQp) z=#6@I3e9$~3Hm0G`K$*2083O(S2;=LP>|)iRBpy0iE;x-`%;xtK#sR0@I5eE8L14` z_&|{3k%uj&@4+F;9-qpsU?KGNAmeLPU#0SDmHFUu+7+ojU*#N-{gnmY4S!?`tqhR; zl`b^XK=wxx$o_}}X%_?1E?Q_sfwYShnh_xFLO|LDs@#ji9pz4t@vSO1fy{R+$b7d5 ztp?JBo`+aWiB?6*dtwH0K)Z4sIcU@_8FgY;9S%4I4StDL8Dw#w-$r-Cde z8Du$0LMs7eIq^a>4rDn|Aj=6?IapDvdZx)$EqBq za)ipEApH~!(oaD`D-figTtd?qq@TJm*yyKrkaDxiTUD-8xf*1?RUq@N6k4l6=35~& z%R%N-3^Lz*m9tgO0O^-xkbVhQ27~l>x6{k(Ipp6dv^qfgyA7njTZLvbNPjng%%>D& zzG)!+n*!3m2`a~d^l!Avkt&C&9HMfd%DyW1I3&MLkoIjL{m=r^56wcW30#BvH44qG zApKAW(hvA^T((@Ha;eIND(8XB7k|sw&No|VWr55$Q)p&@%r^yOz6mPFs2mB>4I%3M+vP+kp74en&BY*5e(8FE|7M7vKj4qeQa7i zAnm$^W+zCyR*-g0Anmq-wA&)I8bI3B3(Y!^c2ywlDnQ!tIpnk}6UF((x0))NM$EF<#*^?LH1t__%P&3km<8k=5wB_QGSfj;&an)MtlT_|C7Rn zW*A8O9xvfmko{Z(vYZld6_~4XvdS?kw_(3TyKby-3gf{iAah(%&wg2qTR3509vA}N z2nK=aAp2(;$o@eY1K2M&f$Wbf!FF&u*a$Ko_5<^w|Cvt>m;tT>XMmL;^I<G2nbK3}ikbAoB?VnU4$10lmNl zU=RGueAsWyryaZwWdB_cZULE3J;;36pUh_+m7sqg6iWymKy`I+$fOcMu0bfVc^GL2*`4SK$hzQ3qUV$3D}Nt zz@^oG0n5Q65bp=%gP1=9(m}ia;G>Y^ zz$!2Xd>4!Yk=K9-@NF;*d<+Z$p9F(I`oRT01p;=usgd4ng0p&z@I2+p(IRImPgZ_C zO7yFg=P3Vx!O8?xdJWKiYP|@FexG*4Cxb86FRmy?N zHwJ5ZWwP>@L85;}d6)76rJ-!Z1YtcMP@b*q9Vq%YluMKsDf=m(9w6y5l_x8I>M!~i zlna!@l}&*X|B!Nu@_6MJ0TO?UGEUiF`MSTv-=mzQ?CK}_2tVPM_)w4SD_5SS{MlFZ zGkt`+y@ih`E#**UDRN;x)0E?sf9$dMCFd69a^-2t?%fi9zjCrNOu79}iC?2kS2~n~ zdL{lXT(q^tHbVrz#_rzwHwJGs6y=5`VXHqO!A7^iL?S zSDv8!^CyXaUYVv`)*<>NrBnIj_oAQjov`s6;R5A&Wz*N9zf(CyIYjxzR}#Nc8K+EY z6TMSezeD61%J;t%dEFPnOO*qaZ?ua3X65P1Up^Q8Q_2+Orq4uwgEB$sqkQ*MiO*4v zQ?|E={$b_$N^j*0pGbU>@>1nDI81V!1uM^J7Wu1>gtsftRqpvv^jnqpD@Q3eejxE* zHwi10S11Q7x4tj&wL++z9R9DC=-=GZxa2Edf|NKSmie_i+-W`F)whmnajJLzUa^llTXemn(bk75#I{B}!A-Pq}%yq{~zut^BD} z^p7hSD90!6Q|8?&@kc5;n?!$}k{7YwoR5ozQBF|7R%My92GE({5 z)uMk*d5>zg&5xa=fy4w!}ZAoTB_8Q}m_E9KzAr3wF~j8}d;Mf8s-rznRg-@QWOZ&O~T3{t-N4~ggB3u8H> zlpm*xe2;RHvg>luS1B)6j#M^ZCh<2aCn$fqRP@=((aN?I(XUdTqx^HS=$}=dqU^jx z^iL==l>L++UM%tVCks!xP}n(1xLkRW(of01zg+;+C;uTw@T+s_jHWy&Dsn{lEqRE|>aI8*d1mHm{P&k+5M$_dIAQ}p*LFI0XR zEBbQfWy&Dsv!_dZ?rFj!m9L#D@-q{J`N~Pk;mU7Lk@$y{@ygvNi@ruVRXI%geze5j zp*&ydt=xE$#LribRep1#=pR)6L&@J$u^*pPW-CW4--?p>JmoRU=f{h_P! z893$~pDnpeYjuw51^7~ODFH@eX+!-PIdzHyb zr}Eb0CH^esAIFLOtTI)}@7=R~e}oGkRt`T#} zKT`CIl>EN0H_H8Sr0^c)B&9=n{|Jentn9CRJyi7k-Y4^U=m;Ud_elAt;X;1Tj`A(a zG0Lw(ME@^kyz={@qF<&=Qu6y{%%|*d;U&sIf`c**ZY1A-8KC@st=)fMTXntg@tm@;@H=uRM1Dr$Vz|Oc+pP<~1EZr1 z*mBu`fMC;g*;47c&~_z59*8ixQ3^L)3I?1Kpgd+!E`b%u)dB&EM(y=RncR4p8ntM| zd8tq(>byRmPrmPVZ93HF@yQ?Obw1zU=bMvrk~Z!4$^A@z2kP(Zw7+lG8Dn^pBx-sS zPS{K=!>y(_cblL0o{hzbi3_+9LwE^ZfG6XJanB}Ge-dBEZ{w5rWxNY-$5nVC?(Q<} zjpOV1ZCs5P<0*I|&c{D)H0`{G-@=FS0qn(2eB?S)?+bV(uELMu33xEh!(V;U)PEDd ziaRidQM?NO5l_P7@R1J2gEwI>UXGXI33xQV6E^kV!ciQ-ch{TzU*ebXLA(oZ$6oBj zV{jpsLZ-bUeg&V#0qn;vT#qYpIWEGJFul&SpTc!`4W5aOcsL%2zi2o0e~jP2mvB2i zgl%{gdeMXP@sDdwyBFbk_{TPr{u}%begmJz$M7D!1KaQ_JPD7(KLt(u@8KAZ;zf8K zegu!gKeU?q@8UP`B}`%hKZ$Gc{%cMByYW(N#t-9%unvEJjj8ujd;_1t?bwH1xC$@C zV{jn`KW^F$;6gkY%U7HH5`F_;!pHDojA8`O#wBYn${0uI|)9?Va@Qo`>{ns#netd3?$$t_*kN=EcU2XDr;Ky+_o`xUA!*BtPU1sW! z;t&pEJ)Vr2e>COO*o_O?x+E2(QKS@eKSR z9)fSLF!g_qdCcLL@j?77ej3-|HRwbKRxUE_PvAXx2PRugegdNy!6Wf7v|nh-+pul9 ziLXL0dhjq@fIn|G<$r`P;&b>A-j8vNVF$M13OpZA#AEP(E-?N57K>QG9r!rjfw$pC z4B;BQ1ef5ccmy7be_Uqz{|%1dFn$hi#ii$)@~7c^{Ns5heFz6}HC~MG_)NLC@L_xa zZ^k|hpdY>HK_@!!y>m_bZ{zFuZG0C074O5la5HYiKb>RRdk^2lAK(~{;?A>8`7!)B zuEwr2P5ye^eTIq0@m{;eRxk@?Xc6dK3HbZjXsS zi(w4nxwsUMK>fm_{Pzu{nzj@d>B{b#kl<_Q~n|RIIhMecq$%- z3-A{oGWCCq-@un}J3fRy^x~6FQ~%5Oha*k=E`Aa3#T#%FUWu!4DV~N$;Gy`NBTW0h z!tdd~<1_dK{tJE%yYZ8FF)qUs@MyH~cOPV)@cVcx-iWU+H08dH|9~ICJO9q)e+HM~ znYib0lRt@{#I<-1HsMblru-Y&go`kLn90xK?RYbueTd0lg2&)OJm6rHZ{ZIQGV$y9 zJU)ZlZ~%|TBk|+|P5lq!ngdLH2`JTi7Z>9x_^WxQ{F`_# zF2$c%CjY;11c&iHybB{3MnATo2i^DqJOJOdnf`u>-^Q5yT3B=FY)X6BF@7-yG^;N?@@n_cc55G#c$#cd>rq^J28S`T!H7~iFgeD&zq*d-{KGPb$kJz z#Ru{8_-WjN*Wem#!bRvnJH9n;`u_=j6JN&1@L{|IZ^Mlk!WQ)5NAM{8!%t0r@8V7z z!yWiIK7jv%F^pmugXlvq9*KwHfB(ev|1*3QpT|e>i`a~3V_T`0F2-et&@l%wr6r7{macferXUJOtm~W!nEaZp08? zip}^@JRa-t_ivbXN?61kX7LMn58i;A@CZBw5 zhEL;Tcn{uzowyD!!3*#>JOZD3+4Q#^*W)K})k`M-djsffi%~v~S7Uiw zSye9YRrB~5_G1^Gjq!`j@x@TrF_NbCk6-}(*n&RPb&j;W2i@pGJKC_)V#-gTu7jlY z3z)|orZI&{Okflv7{(yBpbx$1K_@!Ujy5b`XvSBSZQXwSVUbHNza2k>iS3; zr!j>|Okflv7{(yBpbx$1K_@!UjyBZwl5`v;EMft(n87rrFpe?Qb(OTe2nNuPE$Blx zy3mOZtSmF_>H109ZW&9M#~fxcgGo$a9Ag;9AO_HnUi6?FU1&!eR?cU#lA6w9eZq#+3w7e4? zSdkmKrcYoQOIXALW-)_lOkole7{v&NF^B>5qZd8sMi<)AhLy7zKbEnCdCXxJGnhnO zw@K$Ajxh{l5CiB(FM808E_9*;b={}xd}A3)Si}NmF@tGLVGT{f={WM3!!)KaiMk$^mXG7q-*<$GgBU!~puyiym~N3+-sb3V*Mn>uc$J z>H1n~0rQwcU2jYCQ<%gAMlph63}OrV(2E{)q66({!}4O&e+hMct?GC&iy2H~3gZ~V zC`M4%&C>S#*n&Rvq6eMmKs(y7+{k!Q*Tt%i7xS3IG^Q|#y8e~ci(?GK7(`v?sycpb zK_9x&g-&!}rNPvnz%rJwhy~1I2Gf|rIL0uF5e%RoThNDYbfFU+Xh$3Bx>9=lB`jhA z^O(alrZ9;KjAIPL7{mbj(Tg5*qYLe5!-|Lb#v&Flk2y?Z3X_D7WAPPJ?KUk+R=tne+M_Q z$Q(xz3#jW|>GA10SE{aKrRw@sY7!F|#R!HmhynDY7d_}k7dp{_cC=ynR5Oke7E#y1 z((z?6gK11*9Ag;82y3vJBbYSIVGoA@7V+r$^!z^Yn zi3yBj48s`20Q#{7edtCPI?;i4v|-uJ{GzVARh?hVV-C}p!Xzdzjxmg41OqtrcdsqP zKJ=moo#;S2+OYCb<{x!kuj=?QkGjs6re`sON!0beG(V0pjA8`C7{mbj(Tg5*qYLe5 zLtW=f`_=Wm)FKv8*ZI=)9HudaNlaiABN)aYwxAEa=s_ns(2h1N|GgQHt{YYzFBUM1 z8BAje;~2vzMlgVWY(XEo(S=TQVC6(Jt_dt-35!_3EM_o`DNJGlqZmP5FHGklhynDY z7d_}k7dp{_l@l00ma&9IEMOKhm_}VsOvjbP1V&NU4b%KE2C)Tw=tU1Y(SdffVfiDb z-4g2hV%kpuvzWm&>bhgq@nQmX-7!s%U>JiKKtFoXgKl)86CGIjuxWn+%UHrZ<}iyH zOk)b;7{e$=Fo1q+K_9x&g-&#!9c@^4nemsfhy~1J4%3*zBqlJ9F$`l61L#LDdeDt7 zw4)6x$1~qp!~*7V>i-U;iBp)w1V%A}VGLpb{pdvxy3vJBbYSH;#*1YvVIFgsMO~N7 z($^m*Fpe<{V-N%AM=yHNjV`pK4J*eoUMyk(b-ghim##Oa>iS};t}9j@FD5XKF$`l6 z1L(&V^r0JF=tKurjxqgCU>Qr8#~fxcgK11*9Ag;82!=6;E$BmCXH4h8gHCjy9c@@S zn(?EqE2i}en8zGuF@s4=U>su@#Rvw_k5m6Q!$<5!7dp{_m7^Fhma&Ao&X5 zqZd8sMi<)Ah7~8{#Ud6kk2%zJx^!GAOroyaRUI!zFpNQLK_7b2gHCjy9c@@X()3fp zA{H=<8BAjelbFCLMo`xS)8hzY0R8Ai54zEXcC=yT2-BXf6Q=DJv4DBZVH#67^?zUz z#8Hf37=ze?KJ=moo#;S2+ECX6({Ywi*9FtKfLYXa!8ARMDU4$bqZq+32C)Tw=tU1Y z(Sdffp{^rV9WNHKfVzH|=4UXCDU4$bqp0hLX}vH8u?2nTMGrdBfp)ZE`R^Dn7E#v; z)BduU!8E2&*9p^dF^pma1L#LxFHFn((2Xv1q62kZFfBiUx;~i3CCp%jr63 zY7D~|!~puS1%2p64?59-cC=yn5Yt}?i&#KiS53#G>#3<}Oko^j7)4!AP0NQdhynDY z7d_}k7dp{_cC=ynV8)L{EMOjUn8gexF@bT6VHkrLz^VT?<|X!^8(nBe8&(c7`p}CWbfXLHXv4~Zj2EZ=Us{1Uk2y?Z3X_HK{vY4jy9~= z87~&GfO*Ve8dI3W1V%A}VGLpmPW_)cFR=%m=s-K#u(E*hqOLoq^H;z;=1|w0tIjVb zF@bT6VHkrLKwWoE+wr0Y-RMF)+OV=e<3(M6t~y@KV-C}(>tt!UBqlJ9F$`l61L#LD zdeDt7bfN<*^BFIev4nZdVHS0ry6Si_fpLss7=sufeo2&u7eI4)yOyG(Uw&Okf;i7{(w5(2p(XLpQq6i4L@*4a+hZ z9Zw01Sin5yFpC*XVglnB!ze~Dj6rNcA9~S)Zgim?ZCJ6H@lRkGOPI$TW-)_lOko^j z7{v&NF^DbbLoa&Ji4L@*pog%(-cRMJ*kA9bZ^$}pF7BIpU)6NIuWI_#{j|h=Du*f5 z`=plF`=pkSksd@Jy3i?B+ZU_tlU|Ym>bP>4LcOn5+ZU_tlO9ALx=`<1)%L||`=pn+ z59Ba~dLOE`FIL+pJ%~PZp;N53FIL+py&~6bO`i}oy~K6ANP2 zJw|$z^a$xe(gURXN%xWNCEY{1i*zUH4$^I;m$;4>MLmv!sK=2bJ%urhidrrrYPlfk z0n+`X`$%`84J&dTuFjWOoiDD-MbZnT=SWXs45MPTf3ey>=>gL9zM$zo(p_l7id;vl z{fpK9xvmyT*ZY8`=SWXsl6<}HYkrLMDCrT>gQWY=g-%iX)$6*}w~=0v#OiotQyq_} zuZJS(1=4e*r!YyrUdOBBAw5cZg!CZk0n+`X`$+ea?jhYpx(zEb7}?!_LadHY)bZso zD{6j5)ch3bNzxOf$4C!ifP6psKGMCUdq{VY?j+qox{dUTT-U1O6RYDBC2Rj8=>^hr zq-RObke(tvNqU0x80k^cBcumO50LIB-AB5YbPwq+(w(F`NEfQ(tnhoQkMa3%LET_o zy3Ssgts9Z;!2IO=1$F)N6Z7qL`T1kApPN4_`+Mfc_FqspIlm(Nnf-@lKfV8uZVwnb zK%Q3Lo70!3A~s501%p#F=wS-J=JO zw$}|Got16=*s)_}gvX8^D=Eiik6TbTbX?{*dtLds-LhXgZd|q#CrqATuZx|y^+bE! z$Vs`A7Ss)&ls!p~)SYz8k-8IZdtLn0{!6 zuiJWB{ImsidltoHJ6xZwpSNGWVXUFhV6WTOm}*>5H_(`Dl(9DMl>L0;nCx#|9A7Lo z8e@y4#l<7CpIJOC`@0uU$o}}^vh1gp3@%wvmt3-KiM?*;lA`R7Eh)%;ys5uQM$@#l zNk-h1ll|eQtn5!TP0D_`X}9bTE=@08P`7PqYN^ci(p|D&Sh`d8D`)IELyq~3$unfG z&m1~a=IhKs*$$kQJWIxNW=yvEv&LjQbXG=F&WfEaGj-Ou>}Sp%mi>XVld>H@yDZ!M z*<-Rzp0n*7DS38GwqxfMWSco>Shlfqx1K8{&ncfHvw2?fJeke&66eXea(--?jBr_6 zw*40*E?7{v^@8{XGXCY0%Vqq_cQ2P?zi{wEY5Br!vMsfYw=AeDw(OGa?v@GJ4y;J7 zkk(ctWSd?wB-_-ALD`P1$jNqiMOLk|R;E_U+^)*4lJWb?emNJ{46KoJaZSH$N7v+KJF+IX z#$GqMrXu^h*G$NM`tqU6Wh9pmUT&}3b$LnlcV1qUZT8BMD`ifu9KKT0uPn)S;Hu4YkQ} zw8hrSS-m#9R-UW18QJbyTUtABzjXUhd!}7xvwgB%X0v^_><_L>ual!%ms%%h!@6Cv zUs$(O_WMJLkn|9WhwOE^(5UQZLnE?38LG(s?$Ctnr`Hdym+`G1TrZx;6V z*f6j`W@JPE27BG;hP>>LY{<#}o(-|E%}SHmvY!qQh3$3Y;j--S3YWq%#_NWz z%Um~azhvjO&Qz!5b(T9Nud^ik6J3*CGVZS3UGj?Av~!d6bp62fa@JqpFWXr6*6sy$ zmFxG&{&06z_J_JN-O@sLS@w5zmt?=(x4Tcyn!fQqdtGVE_!c>Lw(OGaz>Ucp<=MV5 zaifg*#=Pv0+?bR7%8h$uf8xeT*&q5;=2LPOd@3#5J^w3qv-EOv_Ganj=8Wu*-&~gc z;ajq|NXjjlTVw`fRw8D}?A>aO-fGGG-D-`f#apdiYT;IE=dF?-zs>5uP2$*X*4Eo3 zPJhN4`i#V>&sc-%$n93{c5(7{t8%;M$E~5b=EtqUxWuW?S%aUGIQcni+vg)5>Z*bf=ZkxO}IzTjSE5*0{#o?y^#MNjz|umAp&h z?A_ML-4bW+wubMPI5}W#8<03LU=65a16DyD9kB8PlD}ubirp*mo{tQo4A*wd;P#D%@}F z)VTivEAfEDTOY9E4@jJQz#7#!`+zl~@#F(mMdRHMSQ8IOQ#-d=#ckHEZIYDyqP6Xd zV&RL{PIc>-toWD2kuO;}HSwS|@Srr2f6y9xP~zN!)~Gu1pf&lRG&Pd4aw%&xB}KMA zWW^tntUW0!_K?KchpZ8eGY?tA8t;C{n$URsA*-x$>S1f}VTqFuTiYI%c;~}bQRA_P zt%An!N38xwB#u2|ZGA-Ikw>hY#>0)EanH;`pOh|DzI*K5FGP9(mNtX633sg`kxR>PgvtmXm3wi=_jqBC#6XFNo%*7%2n*&st*|=d#vlRt~N5Rcp^zt=Nbpjf_}1b#lb2sOjgeq36ZY^VYaJ z{DPHzL7Le8f;I7i#N#hmWp&_1EBT@{ReI4Hf6*$xC`HmaYbYmKshl;KlXzFoDrvkk zXB9P0ykrf$Bys#DtN$g5M_;n?8jrkWLKjRWu$RwXzxyjar#e ziOZwbZjDQ$*0{#oUbRxMN<8qYm3&p=!kD#lOyc~QH8v)1ruDJuXnAwbzQ*Ut_dO1k z&oI~Appnh?HTk~Eq4GvNzTU)}wfv0u=j1y#nEW@jzT}6A*AZul-?i$Cub_;%($_BmYq1_$N)iexFFo-$Qx* zK99yE{BOiB=y;_3H;Dbj-ytq*f0F+?@jb*P;_K!65<31t#`AmT&wia5 zUpw=64Dr7)UoFH1tuO7DX|Ip*pVVjS>v}?(-$Fdh__h!qBH!oI{CBCpocTDI{EMmI zM*I--AEo~Z$`{FBPWyKd|B&NN5`UKXapJEXVfufW_*)UM~Tm( z|NU<;$NK~3ZzuUzF&~GL|0KtA2Jv#{cY^ZUnBPdJX>Sp6jQC#}&o<(-INs}N?P~7yG(pEk=w2l*zl z*_w#;=dAjuBM!>X1@&={e7{87FUj{*_0b^5a+sB~m991Mbuw2PCy2i*!`ApF;!n#s zG>#IFQNRC6Q-2|`oA_GkSIZZ!F!=}5UYuChxzhaci%tF{{ileRQNN$~9r}+G-%b7W zX{P>b)Yrc!)QA3FPTSvoii!V|`df*+rpCX<YugJ)W4nj zl}k=+4h`n;%$P)3(ufE`qTfrppRRt<>mQm zGVw2~&u`8)u*AgY5)YE!L43`rCjV!09%}#Tr6#`Y5EEx8zu6rByb=04(HzgbEb)Af zXY6C9emlo|)43)t9%|aVBxK^{@>oeEnXEwwJiT)DKnri`mw! zGjWXe`iW1d&S%Va6Y;O4nAX4G!>0Tq+M9Hnc;OKyKXayuk7E22Ehhetg(g4HY~ru- zd}n4nU*_Xew(8>vVjJ;+POGqIDnjW~UyslSZaPkf|azoq@i)bZ;1De(m3 zdCM~Moj=#qzyBZ^pUm&LoADf_`8J#WJ&-;=ORRqvq>r!4@ksXc;{o}--^}U-`1ylp$IEK^|DwE}X4ZGr z)W1V|nwfvQ%TPiBs9xTgGlHS@W#roUt5e4JVTmYV(#sj2_nn)(OS#8=gfZ%s}8e9ipc zQ`6t?YR;!yYU+>4`8{*Izme*e4}tj_=W${xxrAeqYUezFgDZ_L}kW_a)Qg`H^#Wd*82_AGuu4>aV$`zhBnG zU#W@zt7iNkt!b~jCJxrrAFFx3ZLM8xk&f04q2AU=_ohgwyLSso;kKUIq#h~N)wVIT zt~Nuf?=z#lJJi-2YF)c|{rXUMYx^d-%$g2+!`+*1u(h_fwny7qr-G|j_nzJx>fYGV zC6)Rl_v)34SIY3}>(A@i($#+Drta%P-Swxh>Y5IhZQ2;=4E2VZ{q>&efrPsHT3hSu ztNT5@ZM~a&{MClmbs9~B-sPLS+Iu@Tbv3RG-EfhA`O4L;ORi|^+#G7Y>|)ukZ&=pW z*}1l@{kn^~)^BQ-$7)aOtRB|1`Y&#$<+hnE&mO9G#!#E1q4v$SBYoehOD_oZ^mcFB z(rl*T;_5ssY3}ac)V=tIa9i&_(i@uA=%k+4v!bo9ZFPHhN2Iqo+8&DNahl@$oX*9o zx^!ZvXHt&8vAL_SdDbL0ue|v3&c5c>_Rd)yH?8jN?&#WZ`sKary=MOA4ws2F8TFo( zp=hspB9~6hh{KasvzhuO)n?v5 zzmd`HyY`I3kojA6F|+c1$1tnRz7Jq#k-4Lvm0LUXS(&rPJu_?WOX<(&UeLf%$*VFn zbs|kCn%0)ATKh?PvMvkB%RAK79-7Wx-CN(#8S2{58*UBhNqa#(jm1*%9iob+#^&qak~JTW?#Zd2wiOYp$q$$y8HU?=$tHxvAAV z9*0wX#mzp#-Yt>PjLx*#`p!)oWPT|uBhXf7CsrG6Teq%Nj-;)#*+NITAS0pwl+mx zy>goi$$4gKOq1mZduaSA)d+n@_UnY5Gih0_k&DQn2C7J!a z?MVDs$7(TYcNs+Agm!Ib?ZzCTBvky!)wk zAaDBq=6;rThk8QYeW7M)YVTc}!_yn|j3=^dbEkx@a-{O+thGISUF-U`j%td&kBn^Y z4z>1mboXv8PBYeO44x?1Hr(;n9T zwYQL-C?=u$EOzwlJtbNrk}H=jy3;dr(|TL$#?Z!%oBBdC4yb$T&e__h?>}v=yzQuV z(%IIvLAsEWWBOgOt@Sb)dRxy_8*-EBY7JNKIITT;%c1RdeUr4WjB16@)V*q7B}~=# zE7E#-*9{$VM$(bh?wdRfO)uyVqB;L~M2ZPxkD&&-}mNIX}>uYb=jTeS`^<}ZQ zrCA>ZmNl4<7So?Rrpx{qQ`YO>6 zY}KoIYwO-F_jaY9<#ZZmep2-RrRwI5)tqYe4b_)?^))-Yw>5ebI!|vxtJYr>ZvLxl z?wuMv&gsveatZg$_&oYoPFLgq<#aVyKitX5GyAw!pWnJ>##BxXv7u33fNh&Qdt1#r zwCOho7yZ8uR?geL+0RSg>SdJVxnS@!BuvA8%AJELv&uo!SW|cO5U9qxW-e$K)qit(D`l?rw zo(_4>)Yj8eeGgWB4eqmKeQRsq#=oj){Zi>*A1&6`SAT$DE(P+#8uKw?_Rni{KIF5C z-U0Q!JlBmsQ@EkA_RZB_QKzBW!QQuDf4NHi(!FnQ{)*D(2&zA!_{)d8cl z)=QzjjC<>w^xbHO`5e;P+0oN`QO)(L+B^;H<0JF`_oiyPf1g3>&1>dM^z`Y^@N&JJ zeqA@unwvjYX6CDU?#)(zfcZY3pBwk}0lKmF6ZBs-iF1yePMiAVr$O>jT#k9ATs&ud zIM-Q_hwZ{;%XpjIT0I9(pOdn9Zc^jve0E;cFgLS)I&<&d=`-FhnwzxwF+%HR`AOyM zcbzjcY6s_?Gq|R?NsH$uHO@_H@J=7X+|2sv%)NVaOD&xrqZ*VB9T(|fYhyHWmkeeHzqBV}$<*NEu{4Q$argfV; zL)BkNY1kL)?vdYMwD#50dAEEN@9C9aCs9x`^f0Hg`3TR;x>IghUG;NjU~Y>1!}&QU z>)fP9>8tufyhVHW8m80g_wLCBzjZ@2DnAG4?%AY2JL}!j+UKbb)HA1}xheAR<7-FL eG&gC<+@wb7g8|OXY?#iJz1sHcr!!^G_J08B=f?y9 diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/spanner_napi.node b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/Release/spanner_napi.node deleted file mode 100755 index 0cafbc86a0ff037aa34b864d516c035a48814698..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103584 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 z z-6*Or&bCwReWabPw{mQ1nB9NZk8fDNlM?A9;xee@<1yHB5sxh@Guig*y3qsDm^k!E zR$|lbIf>1sXC!;9x}F@J0XtqLY{T0Uv{9oH8g1UGwxyyYBS~mTyMB$NEB}vr!yF&( z>6Zk}UzPB&N5?gKOiu8VG3>U?<)}3W>)Hn5RcX!}`MWkV&>8>tepKdb{mxCE*~ei3 zh@PL#o8rsY$H=Hl@7-E;oS)F?8bS5hOQd0RA3e=!-sMxL${!r?1^MeAqlF!l-3>FQ z8)j@b%(!ltoNk!$-7pinVJ3FNOzMWoj*;o^dCcyf$?WcV%I=8k<-1{Io*q$(><%>yJrF`YkQ*@-@QN+y60;`cl8sytDl(7 zu{3|4zD6{MSB2^}C61y_icF;O!&s4@7Oan7i;EdhLxi) zOhEF)$>NM|$xD81DTD1yvu}z*bzdl%Ig+eV3lPf~NGV1EVwUyVZZi-|cf28AQezLp z7ST3jN~AW<0b}lCR8*F%z;8^6QP<$tuBt{Y@mDUXT3)%RxMURPF{3Uo2^KG3G-^rt zh^l3!BdRL=_=&N~Q8FwoSu|>;^`mN48g2x)_HV2jQBhtviu)X+7A-F+EgCg)5HDG2vOFDS)h@$ zzR3Nk_xoqNM)vs5?MSw)Yq1nNKX4Q}FU{p6*w=Y{S6so>5eA%{}cq@2!4tcF#wS zjcoqx>|d7^_v*9gt}SbSbEE4g6N0~5mv{AJsmo`NNon%m^wW}a+Pxn(2Y$S2_N3AO z_WEz$yz8FMpN+l#t$r;xHNIE1{KijTD17F(BX^Ct?z#Ee+Y8dxam{zH;cGQClv!^}Pp1Kl0}d1AhA9H4o(dI@`Evm+zsS zFP2<(-b+^>zhn5PYwvj?<5hq8qqpsNe17?F|F*cv_2#Ru-sG4)KdE!=&b2px=dEYH zJN?e#Kl@MVr_#%B?mH;0ZORqDdG?a=zkG6R|CG5?dc8hu??0A4e9=FixavRE|7G%3 zSH3vy$~UL{dP?B3-Fd5T4No8Re&>8 zhIXTI;&>yOa1<|I(YGfHxIwP-<`GU=~Y*JuWp<8;SI0$9RAJQe(}wxKh6E= z>9h7dJbT9zZ#;POvcbn{T8~`x%G2LFyKZyYuKWLM<%_q3ub=(-MaM&@xBa%)(pPTE z?LBeb@Jkn@toy~RpD%6m?wz+FX?5y*c|S>>_|o)6rE6N&-reij>m0*6?tP-{s>wwu JoBt)m{{t}@_8R~I diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/binding.Makefile b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/binding.Makefile deleted file mode 100644 index 156660be..00000000 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/binding.Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# This file is generated by gyp; do not edit. - -export builddir_name ?= ./build/. -.PHONY: all -all: - $(MAKE) spanner_napi diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi deleted file mode 100644 index cf1a772d..00000000 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/config.gypi +++ /dev/null @@ -1,506 +0,0 @@ -# Do not edit. File was generated by node-gyp's "configure" step -{ - "target_defaults": { - "cflags": [], - "configurations": { - "Debug": { - "v8_enable_v8_checks": 0, - "variables": {} - }, - "Release": { - "v8_enable_v8_checks": 1, - "variables": {} - } - }, - "default_configuration": "Release", - "defines": [], - "include_dirs": [], - "libraries": [], - "msvs_configuration_platform": "ARM64", - "xcode_configuration_platform": "arm64" - }, - "variables": { - "arm_fpu": "neon", - "asan": 0, - "clang": 1, - "control_flow_guard": "false", - "coverage": "false", - "dcheck_always_on": 0, - "debug_nghttp2": "false", - "debug_node": "false", - "enable_lto": "false", - "enable_pgo_generate": "false", - "enable_pgo_use": "false", - "error_on_warn": "false", - "force_dynamic_crt": 0, - "host_arch": "arm64", - "icu_data_in": "../../deps/icu-tmp/icudt77l.dat", - "icu_endianness": "l", - "icu_gyp_path": "tools/icu/icu-generic.gyp", - "icu_path": "deps/icu-small", - "icu_small": "false", - "icu_ver_major": "77", - "libdir": "lib", - "llvm_version": "16.0", - "napi_build_version": "10", - "node_builtin_shareable_builtins": [ - "deps/cjs-module-lexer/lexer.js", - "deps/cjs-module-lexer/dist/lexer.js", - "deps/undici/undici.js", - "deps/amaro/dist/index.js" - ], - "node_byteorder": "little", - "node_cctest_sources": [ - "src/node_snapshot_stub.cc", - "test/cctest/inspector/test_node_protocol.cc", - "test/cctest/node_test_fixture.cc", - "test/cctest/test_aliased_buffer.cc", - "test/cctest/test_base64.cc", - "test/cctest/test_base_object_ptr.cc", - "test/cctest/test_cppgc.cc", - "test/cctest/test_crypto_clienthello.cc", - "test/cctest/test_dataqueue.cc", - "test/cctest/test_environment.cc", - "test/cctest/test_inspector_socket.cc", - "test/cctest/test_inspector_socket_server.cc", - "test/cctest/test_json_utils.cc", - "test/cctest/test_linked_binding.cc", - "test/cctest/test_node_api.cc", - "test/cctest/test_node_crypto.cc", - "test/cctest/test_node_crypto_env.cc", - "test/cctest/test_node_postmortem_metadata.cc", - "test/cctest/test_node_task_runner.cc", - "test/cctest/test_path.cc", - "test/cctest/test_per_process.cc", - "test/cctest/test_platform.cc", - "test/cctest/test_quic_cid.cc", - "test/cctest/test_quic_error.cc", - "test/cctest/test_quic_tokens.cc", - "test/cctest/test_report.cc", - "test/cctest/test_sockaddr.cc", - "test/cctest/test_traced_value.cc", - "test/cctest/test_util.cc", - "test/cctest/node_test_fixture.h" - ], - "node_debug_lib": "false", - "node_enable_d8": "false", - "node_enable_v8_vtunejit": "false", - "node_fipsinstall": "false", - "node_install_corepack": "true", - "node_install_npm": "true", - "node_library_files": [ - "lib/_http_agent.js", - "lib/_http_client.js", - "lib/_http_common.js", - "lib/_http_incoming.js", - "lib/_http_outgoing.js", - "lib/_http_server.js", - "lib/_stream_duplex.js", - "lib/_stream_passthrough.js", - "lib/_stream_readable.js", - "lib/_stream_transform.js", - "lib/_stream_wrap.js", - "lib/_stream_writable.js", - "lib/_tls_common.js", - "lib/_tls_wrap.js", - "lib/assert.js", - "lib/assert/strict.js", - "lib/async_hooks.js", - "lib/buffer.js", - "lib/child_process.js", - "lib/cluster.js", - "lib/console.js", - "lib/constants.js", - "lib/crypto.js", - "lib/dgram.js", - "lib/diagnostics_channel.js", - "lib/dns.js", - "lib/dns/promises.js", - "lib/domain.js", - "lib/events.js", - "lib/fs.js", - "lib/fs/promises.js", - "lib/http.js", - "lib/http2.js", - "lib/https.js", - "lib/inspector.js", - "lib/inspector/promises.js", - "lib/internal/abort_controller.js", - "lib/internal/assert.js", - "lib/internal/assert/assertion_error.js", - "lib/internal/assert/calltracker.js", - "lib/internal/assert/myers_diff.js", - "lib/internal/assert/utils.js", - "lib/internal/async_context_frame.js", - "lib/internal/async_hooks.js", - "lib/internal/async_local_storage/async_context_frame.js", - "lib/internal/async_local_storage/async_hooks.js", - "lib/internal/blob.js", - "lib/internal/blocklist.js", - "lib/internal/bootstrap/node.js", - "lib/internal/bootstrap/realm.js", - "lib/internal/bootstrap/shadow_realm.js", - "lib/internal/bootstrap/switches/does_not_own_process_state.js", - "lib/internal/bootstrap/switches/does_own_process_state.js", - "lib/internal/bootstrap/switches/is_main_thread.js", - "lib/internal/bootstrap/switches/is_not_main_thread.js", - "lib/internal/bootstrap/web/exposed-wildcard.js", - "lib/internal/bootstrap/web/exposed-window-or-worker.js", - "lib/internal/buffer.js", - "lib/internal/child_process.js", - "lib/internal/child_process/serialization.js", - "lib/internal/cli_table.js", - "lib/internal/cluster/child.js", - "lib/internal/cluster/primary.js", - "lib/internal/cluster/round_robin_handle.js", - "lib/internal/cluster/shared_handle.js", - "lib/internal/cluster/utils.js", - "lib/internal/cluster/worker.js", - "lib/internal/console/constructor.js", - "lib/internal/console/global.js", - "lib/internal/constants.js", - "lib/internal/crypto/aes.js", - "lib/internal/crypto/certificate.js", - "lib/internal/crypto/cfrg.js", - "lib/internal/crypto/cipher.js", - "lib/internal/crypto/diffiehellman.js", - "lib/internal/crypto/ec.js", - "lib/internal/crypto/hash.js", - "lib/internal/crypto/hashnames.js", - "lib/internal/crypto/hkdf.js", - "lib/internal/crypto/keygen.js", - "lib/internal/crypto/keys.js", - "lib/internal/crypto/mac.js", - "lib/internal/crypto/pbkdf2.js", - "lib/internal/crypto/random.js", - "lib/internal/crypto/rsa.js", - "lib/internal/crypto/scrypt.js", - "lib/internal/crypto/sig.js", - "lib/internal/crypto/util.js", - "lib/internal/crypto/webcrypto.js", - "lib/internal/crypto/webidl.js", - "lib/internal/crypto/x509.js", - "lib/internal/data_url.js", - "lib/internal/debugger/inspect.js", - "lib/internal/debugger/inspect_client.js", - "lib/internal/debugger/inspect_repl.js", - "lib/internal/dgram.js", - "lib/internal/dns/callback_resolver.js", - "lib/internal/dns/promises.js", - "lib/internal/dns/utils.js", - "lib/internal/encoding.js", - "lib/internal/error_serdes.js", - "lib/internal/errors.js", - "lib/internal/event_target.js", - "lib/internal/events/abort_listener.js", - "lib/internal/events/symbols.js", - "lib/internal/file.js", - "lib/internal/fixed_queue.js", - "lib/internal/freelist.js", - "lib/internal/freeze_intrinsics.js", - "lib/internal/fs/cp/cp-sync.js", - "lib/internal/fs/cp/cp.js", - "lib/internal/fs/dir.js", - "lib/internal/fs/glob.js", - "lib/internal/fs/promises.js", - "lib/internal/fs/read/context.js", - "lib/internal/fs/recursive_watch.js", - "lib/internal/fs/rimraf.js", - "lib/internal/fs/streams.js", - "lib/internal/fs/sync_write_stream.js", - "lib/internal/fs/utils.js", - "lib/internal/fs/watchers.js", - "lib/internal/heap_utils.js", - "lib/internal/histogram.js", - "lib/internal/http.js", - "lib/internal/http2/compat.js", - "lib/internal/http2/core.js", - "lib/internal/http2/util.js", - "lib/internal/inspector/network.js", - "lib/internal/inspector/network_http.js", - "lib/internal/inspector/network_undici.js", - "lib/internal/inspector_async_hook.js", - "lib/internal/inspector_network_tracking.js", - "lib/internal/js_stream_socket.js", - "lib/internal/legacy/processbinding.js", - "lib/internal/linkedlist.js", - "lib/internal/main/check_syntax.js", - "lib/internal/main/embedding.js", - "lib/internal/main/eval_stdin.js", - "lib/internal/main/eval_string.js", - "lib/internal/main/inspect.js", - "lib/internal/main/mksnapshot.js", - "lib/internal/main/print_help.js", - "lib/internal/main/prof_process.js", - "lib/internal/main/repl.js", - "lib/internal/main/run_main_module.js", - "lib/internal/main/test_runner.js", - "lib/internal/main/watch_mode.js", - "lib/internal/main/worker_thread.js", - "lib/internal/mime.js", - "lib/internal/modules/cjs/loader.js", - "lib/internal/modules/customization_hooks.js", - "lib/internal/modules/esm/assert.js", - "lib/internal/modules/esm/create_dynamic_module.js", - "lib/internal/modules/esm/formats.js", - "lib/internal/modules/esm/get_format.js", - "lib/internal/modules/esm/hooks.js", - "lib/internal/modules/esm/initialize_import_meta.js", - "lib/internal/modules/esm/load.js", - "lib/internal/modules/esm/loader.js", - "lib/internal/modules/esm/module_job.js", - "lib/internal/modules/esm/module_map.js", - "lib/internal/modules/esm/resolve.js", - "lib/internal/modules/esm/shared_constants.js", - "lib/internal/modules/esm/translators.js", - "lib/internal/modules/esm/utils.js", - "lib/internal/modules/esm/worker.js", - "lib/internal/modules/helpers.js", - "lib/internal/modules/package_json_reader.js", - "lib/internal/modules/run_main.js", - "lib/internal/modules/typescript.js", - "lib/internal/navigator.js", - "lib/internal/net.js", - "lib/internal/options.js", - "lib/internal/per_context/domexception.js", - "lib/internal/per_context/messageport.js", - "lib/internal/per_context/primordials.js", - "lib/internal/perf/event_loop_delay.js", - "lib/internal/perf/event_loop_utilization.js", - "lib/internal/perf/nodetiming.js", - "lib/internal/perf/observe.js", - "lib/internal/perf/performance.js", - "lib/internal/perf/performance_entry.js", - "lib/internal/perf/resource_timing.js", - "lib/internal/perf/timerify.js", - "lib/internal/perf/usertiming.js", - "lib/internal/perf/utils.js", - "lib/internal/priority_queue.js", - "lib/internal/process/execution.js", - "lib/internal/process/finalization.js", - "lib/internal/process/per_thread.js", - "lib/internal/process/permission.js", - "lib/internal/process/pre_execution.js", - "lib/internal/process/promises.js", - "lib/internal/process/report.js", - "lib/internal/process/signal.js", - "lib/internal/process/task_queues.js", - "lib/internal/process/warning.js", - "lib/internal/process/worker_thread_only.js", - "lib/internal/promise_hooks.js", - "lib/internal/querystring.js", - "lib/internal/quic/quic.js", - "lib/internal/quic/state.js", - "lib/internal/quic/stats.js", - "lib/internal/quic/symbols.js", - "lib/internal/readline/callbacks.js", - "lib/internal/readline/emitKeypressEvents.js", - "lib/internal/readline/interface.js", - "lib/internal/readline/promises.js", - "lib/internal/readline/utils.js", - "lib/internal/repl.js", - "lib/internal/repl/await.js", - "lib/internal/repl/history.js", - "lib/internal/repl/utils.js", - "lib/internal/socket_list.js", - "lib/internal/socketaddress.js", - "lib/internal/source_map/prepare_stack_trace.js", - "lib/internal/source_map/source_map.js", - "lib/internal/source_map/source_map_cache.js", - "lib/internal/source_map/source_map_cache_map.js", - "lib/internal/stream_base_commons.js", - "lib/internal/streams/add-abort-signal.js", - "lib/internal/streams/compose.js", - "lib/internal/streams/destroy.js", - "lib/internal/streams/duplex.js", - "lib/internal/streams/duplexify.js", - "lib/internal/streams/duplexpair.js", - "lib/internal/streams/end-of-stream.js", - "lib/internal/streams/from.js", - "lib/internal/streams/lazy_transform.js", - "lib/internal/streams/legacy.js", - "lib/internal/streams/operators.js", - "lib/internal/streams/passthrough.js", - "lib/internal/streams/pipeline.js", - "lib/internal/streams/readable.js", - "lib/internal/streams/state.js", - "lib/internal/streams/transform.js", - "lib/internal/streams/utils.js", - "lib/internal/streams/writable.js", - "lib/internal/test/binding.js", - "lib/internal/test/transfer.js", - "lib/internal/test_runner/assert.js", - "lib/internal/test_runner/coverage.js", - "lib/internal/test_runner/harness.js", - "lib/internal/test_runner/mock/loader.js", - "lib/internal/test_runner/mock/mock.js", - "lib/internal/test_runner/mock/mock_timers.js", - "lib/internal/test_runner/reporter/dot.js", - "lib/internal/test_runner/reporter/junit.js", - "lib/internal/test_runner/reporter/lcov.js", - "lib/internal/test_runner/reporter/spec.js", - "lib/internal/test_runner/reporter/tap.js", - "lib/internal/test_runner/reporter/utils.js", - "lib/internal/test_runner/reporter/v8-serializer.js", - "lib/internal/test_runner/runner.js", - "lib/internal/test_runner/snapshot.js", - "lib/internal/test_runner/test.js", - "lib/internal/test_runner/tests_stream.js", - "lib/internal/test_runner/utils.js", - "lib/internal/timers.js", - "lib/internal/tls/secure-context.js", - "lib/internal/tls/secure-pair.js", - "lib/internal/trace_events_async_hooks.js", - "lib/internal/tty.js", - "lib/internal/url.js", - "lib/internal/util.js", - "lib/internal/util/colors.js", - "lib/internal/util/comparisons.js", - "lib/internal/util/debuglog.js", - "lib/internal/util/diff.js", - "lib/internal/util/inspect.js", - "lib/internal/util/inspector.js", - "lib/internal/util/parse_args/parse_args.js", - "lib/internal/util/parse_args/utils.js", - "lib/internal/util/types.js", - "lib/internal/v8/startup_snapshot.js", - "lib/internal/v8_prof_polyfill.js", - "lib/internal/v8_prof_processor.js", - "lib/internal/validators.js", - "lib/internal/vm.js", - "lib/internal/vm/module.js", - "lib/internal/wasm_web_api.js", - "lib/internal/watch_mode/files_watcher.js", - "lib/internal/watchdog.js", - "lib/internal/webidl.js", - "lib/internal/webstorage.js", - "lib/internal/webstreams/adapters.js", - "lib/internal/webstreams/compression.js", - "lib/internal/webstreams/encoding.js", - "lib/internal/webstreams/queuingstrategies.js", - "lib/internal/webstreams/readablestream.js", - "lib/internal/webstreams/transfer.js", - "lib/internal/webstreams/transformstream.js", - "lib/internal/webstreams/util.js", - "lib/internal/webstreams/writablestream.js", - "lib/internal/worker.js", - "lib/internal/worker/io.js", - "lib/internal/worker/js_transferable.js", - "lib/internal/worker/messaging.js", - "lib/module.js", - "lib/net.js", - "lib/os.js", - "lib/path.js", - "lib/path/posix.js", - "lib/path/win32.js", - "lib/perf_hooks.js", - "lib/process.js", - "lib/punycode.js", - "lib/querystring.js", - "lib/readline.js", - "lib/readline/promises.js", - "lib/repl.js", - "lib/sea.js", - "lib/sqlite.js", - "lib/stream.js", - "lib/stream/consumers.js", - "lib/stream/promises.js", - "lib/stream/web.js", - "lib/string_decoder.js", - "lib/sys.js", - "lib/test.js", - "lib/test/reporters.js", - "lib/timers.js", - "lib/timers/promises.js", - "lib/tls.js", - "lib/trace_events.js", - "lib/tty.js", - "lib/url.js", - "lib/util.js", - "lib/util/types.js", - "lib/v8.js", - "lib/vm.js", - "lib/wasi.js", - "lib/worker_threads.js", - "lib/zlib.js" - ], - "node_module_version": 127, - "node_no_browser_globals": "false", - "node_prefix": "/", - "node_release_urlbase": "https://nodejs.org/download/release/", - "node_shared": "false", - "node_shared_ada": "false", - "node_shared_brotli": "false", - "node_shared_cares": "false", - "node_shared_http_parser": "false", - "node_shared_libuv": "false", - "node_shared_nghttp2": "false", - "node_shared_nghttp3": "false", - "node_shared_ngtcp2": "false", - "node_shared_openssl": "false", - "node_shared_simdjson": "false", - "node_shared_simdutf": "false", - "node_shared_sqlite": "false", - "node_shared_uvwasi": "false", - "node_shared_zlib": "false", - "node_shared_zstd": "false", - "node_tag": "", - "node_target_type": "executable", - "node_use_amaro": "true", - "node_use_bundled_v8": "true", - "node_use_node_code_cache": "true", - "node_use_node_snapshot": "true", - "node_use_openssl": "true", - "node_use_sqlite": "true", - "node_use_v8_platform": "true", - "node_with_ltcg": "false", - "node_without_node_options": "false", - "node_write_snapshot_as_array_literals": "false", - "openssl_is_fips": "false", - "openssl_quic": "false", - "ossfuzz": "false", - "shlib_suffix": "127.dylib", - "single_executable_application": "true", - "suppress_all_error_on_warn": "false", - "target_arch": "arm64", - "ubsan": 0, - "use_ccache_win": 0, - "use_prefix_to_find_headers": "false", - "v8_enable_31bit_smis_on_64bit_arch": 0, - "v8_enable_extensible_ro_snapshot": 0, - "v8_enable_external_code_space": 0, - "v8_enable_gdbjit": 0, - "v8_enable_hugepage": 0, - "v8_enable_i18n_support": 1, - "v8_enable_inspector": 1, - "v8_enable_javascript_promise_hooks": 1, - "v8_enable_lite_mode": 0, - "v8_enable_maglev": 0, - "v8_enable_object_print": 1, - "v8_enable_pointer_compression": 0, - "v8_enable_pointer_compression_shared_cage": 0, - "v8_enable_sandbox": 0, - "v8_enable_shared_ro_heap": 1, - "v8_enable_webassembly": 1, - "v8_optimized_debug": 1, - "v8_promise_internal_field_count": 1, - "v8_random_seed": 0, - "v8_trace_maps": 0, - "v8_use_siphash": 1, - "want_separate_host_toolset": 0, - "xcode_version": "16.0", - "nodedir": "/Users/gargsurbhi/Library/Caches/node-gyp/22.17.1", - "python": "/Users/gargsurbhi/.asdf/installs/python/3.9.23/bin/python3", - "standalone_static_library": 1, - "prefix": "/Users/gargsurbhi/.asdf/installs/nodejs/22.17.1", - "user_agent": "npm/10.9.2 node/v22.17.1 darwin arm64 workspaces/false", - "cache": "/Users/gargsurbhi/.npm", - "node_gyp": "/Users/gargsurbhi/.asdf/installs/nodejs/22.17.1/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", - "npm_version": "10.9.2", - "init_module": "/Users/gargsurbhi/.npm-init.js", - "userconfig": "/Users/gargsurbhi/.npmrc", - "globalconfig": "/Users/gargsurbhi/.asdf/installs/nodejs/22.17.1/etc/npmrc", - "local_prefix": "/Users/gargsurbhi/Work/Github/go-sql-spanner/spannerlib/wrappers/spannerlib-nodejs-poc/napi", - "global_prefix": "/Users/gargsurbhi/.asdf/installs/nodejs/22.17.1" - } -} diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/gyp-mac-tool b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/gyp-mac-tool deleted file mode 100755 index ab21cf16..00000000 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/build/gyp-mac-tool +++ /dev/null @@ -1,766 +0,0 @@ -#!/usr/bin/env python3 -# Generated by gyp. Do not edit. -# Copyright (c) 2012 Google Inc. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Utility functions to perform Xcode-style build steps. - -These functions are executed via gyp-mac-tool when using the Makefile generator. -""" - -import fcntl -import fnmatch -import glob -import json -import os -import plistlib -import re -import shutil -import struct -import subprocess -import sys -import tempfile - - -def main(args): - executor = MacTool() - if (exit_code := executor.Dispatch(args)) is not None: - sys.exit(exit_code) - - -class MacTool: - """This class performs all the Mac tooling steps. The methods can either be - executed directly, or dispatched from an argument list.""" - - def Dispatch(self, args): - """Dispatches a string command to a method.""" - if len(args) < 1: - raise Exception("Not enough arguments") - - method = "Exec%s" % self._CommandifyName(args[0]) - return getattr(self, method)(*args[1:]) - - def _CommandifyName(self, name_string): - """Transforms a tool name like copy-info-plist to CopyInfoPlist""" - return name_string.title().replace("-", "") - - def ExecCopyBundleResource(self, source, dest, convert_to_binary): - """Copies a resource file to the bundle/Resources directory, performing any - necessary compilation on each resource.""" - convert_to_binary = convert_to_binary == "True" - extension = os.path.splitext(source)[1].lower() - if os.path.isdir(source): - # Copy tree. - # TODO(thakis): This copies file attributes like mtime, while the - # single-file branch below doesn't. This should probably be changed to - # be consistent with the single-file branch. - if os.path.exists(dest): - shutil.rmtree(dest) - shutil.copytree(source, dest) - elif extension in {".xib", ".storyboard"}: - return self._CopyXIBFile(source, dest) - elif extension == ".strings" and not convert_to_binary: - self._CopyStringsFile(source, dest) - else: - if os.path.exists(dest): - os.unlink(dest) - shutil.copy(source, dest) - - if convert_to_binary and extension in {".plist", ".strings"}: - self._ConvertToBinary(dest) - - def _CopyXIBFile(self, source, dest): - """Compiles a XIB file with ibtool into a binary plist in the bundle.""" - - # ibtool sometimes crashes with relative paths. See crbug.com/314728. - base = os.path.dirname(os.path.realpath(__file__)) - if os.path.relpath(source): - source = os.path.join(base, source) - if os.path.relpath(dest): - dest = os.path.join(base, dest) - - args = ["xcrun", "ibtool", "--errors", "--warnings", "--notices"] - - if os.environ["XCODE_VERSION_ACTUAL"] > "0700": - args.extend(["--auto-activate-custom-fonts"]) - if "IPHONEOS_DEPLOYMENT_TARGET" in os.environ: - args.extend( - [ - "--target-device", - "iphone", - "--target-device", - "ipad", - "--minimum-deployment-target", - os.environ["IPHONEOS_DEPLOYMENT_TARGET"], - ] - ) - else: - args.extend( - [ - "--target-device", - "mac", - "--minimum-deployment-target", - os.environ["MACOSX_DEPLOYMENT_TARGET"], - ] - ) - - args.extend( - ["--output-format", "human-readable-text", "--compile", dest, source] - ) - - ibtool_section_re = re.compile(r"/\*.*\*/") - ibtool_re = re.compile(r".*note:.*is clipping its content") - try: - stdout = subprocess.check_output(args) - except subprocess.CalledProcessError as e: - print(e.output) - raise - current_section_header = None - for line in stdout.splitlines(): - if ibtool_section_re.match(line): - current_section_header = line - elif not ibtool_re.match(line): - if current_section_header: - print(current_section_header) - current_section_header = None - print(line) - return 0 - - def _ConvertToBinary(self, dest): - subprocess.check_call( - ["xcrun", "plutil", "-convert", "binary1", "-o", dest, dest] - ) - - def _CopyStringsFile(self, source, dest): - """Copies a .strings file using iconv to reconvert the input into UTF-16.""" - input_code = self._DetectInputEncoding(source) or "UTF-8" - - # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call - # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints - # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing - # semicolon in dictionary. - # on invalid files. Do the same kind of validation. - import CoreFoundation # noqa: PLC0415 - - with open(source, "rb") as in_file: - s = in_file.read() - d = CoreFoundation.CFDataCreate(None, s, len(s)) - _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None) - if error: - return - - with open(dest, "wb") as fp: - fp.write(s.decode(input_code).encode("UTF-16")) - - def _DetectInputEncoding(self, file_name): - """Reads the first few bytes from file_name and tries to guess the text - encoding. Returns None as a guess if it can't detect it.""" - with open(file_name, "rb") as fp: - try: - header = fp.read(3) - except Exception: - return None - if header.startswith((b"\xfe\xff", b"\xff\xfe")): - return "UTF-16" - elif header.startswith(b"\xef\xbb\xbf"): - return "UTF-8" - else: - return None - - def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys): - """Copies the |source| Info.plist to the destination directory |dest|.""" - # Read the source Info.plist into memory. - with open(source) as fd: - lines = fd.read() - - # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild). - plist = plistlib.readPlistFromString(lines) - if keys: - plist.update(json.loads(keys[0])) - lines = plistlib.writePlistToString(plist) - - # Go through all the environment variables and replace them as variables in - # the file. - IDENT_RE = re.compile(r"[_/\s]") - for key in os.environ: - if key.startswith("_"): - continue - evar = "${%s}" % key - evalue = os.environ[key] - lines = lines.replace(lines, evar, evalue) - - # Xcode supports various suffices on environment variables, which are - # all undocumented. :rfc1034identifier is used in the standard project - # template these days, and :identifier was used earlier. They are used to - # convert non-url characters into things that look like valid urls -- - # except that the replacement character for :identifier, '_' isn't valid - # in a URL either -- oops, hence :rfc1034identifier was born. - evar = "${%s:identifier}" % key - evalue = IDENT_RE.sub("_", os.environ[key]) - lines = lines.replace(lines, evar, evalue) - - evar = "${%s:rfc1034identifier}" % key - evalue = IDENT_RE.sub("-", os.environ[key]) - lines = lines.replace(lines, evar, evalue) - - # Remove any keys with values that haven't been replaced. - lines = lines.splitlines() - for i in range(len(lines)): - if lines[i].strip().startswith("${"): - lines[i] = None - lines[i - 1] = None - lines = "\n".join(line for line in lines if line is not None) - - # Write out the file with variables replaced. - with open(dest, "w") as fd: - fd.write(lines) - - # Now write out PkgInfo file now that the Info.plist file has been - # "compiled". - self._WritePkgInfo(dest) - - if convert_to_binary == "True": - self._ConvertToBinary(dest) - - def _WritePkgInfo(self, info_plist): - """This writes the PkgInfo file from the data stored in Info.plist.""" - plist = plistlib.readPlist(info_plist) - if not plist: - return - - # Only create PkgInfo for executable types. - package_type = plist["CFBundlePackageType"] - if package_type != "APPL": - return - - # The format of PkgInfo is eight characters, representing the bundle type - # and bundle signature, each four characters. If that is missing, four - # '?' characters are used instead. - signature_code = plist.get("CFBundleSignature", "????") - if len(signature_code) != 4: # Wrong length resets everything, too. - signature_code = "?" * 4 - - dest = os.path.join(os.path.dirname(info_plist), "PkgInfo") - with open(dest, "w") as fp: - fp.write(f"{package_type}{signature_code}") - - def ExecFlock(self, lockfile, *cmd_list): - """Emulates the most basic behavior of Linux's flock(1).""" - # Rely on exception handling to report errors. - fd = os.open(lockfile, os.O_RDONLY | os.O_NOCTTY | os.O_CREAT, 0o666) - fcntl.flock(fd, fcntl.LOCK_EX) - return subprocess.call(cmd_list) - - def ExecFilterLibtool(self, *cmd_list): - """Calls libtool and filters out '/path/to/libtool: file: foo.o has no - symbols'.""" - libtool_re = re.compile( - r"^.*libtool: (?:for architecture: \S* )?file: .* has no symbols$" - ) - libtool_re5 = re.compile( - r"^.*libtool: warning for library: " - + r".* the table of contents is empty " - + r"\(no object file members in the library define global symbols\)$" - ) - env = os.environ.copy() - # Ref: - # http://www.opensource.apple.com/source/cctools/cctools-809/misc/libtool.c - # The problem with this flag is that it resets the file mtime on the file to - # epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone. - env["ZERO_AR_DATE"] = "1" - libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env) - err = libtoolout.communicate()[1].decode("utf-8") - for line in err.splitlines(): - if not libtool_re.match(line) and not libtool_re5.match(line): - print(line, file=sys.stderr) - # Unconditionally touch the output .a file on the command line if present - # and the command succeeded. A bit hacky. - if not libtoolout.returncode: - for i in range(len(cmd_list) - 1): - if cmd_list[i] == "-o" and cmd_list[i + 1].endswith(".a"): - os.utime(cmd_list[i + 1], None) - break - return libtoolout.returncode - - def ExecPackageIosFramework(self, framework): - # Find the name of the binary based on the part before the ".framework". - binary = os.path.basename(framework).split(".")[0] - module_path = os.path.join(framework, "Modules") - if not os.path.exists(module_path): - os.mkdir(module_path) - module_template = ( - "framework module %s {\n" - ' umbrella header "%s.h"\n' - "\n" - " export *\n" - " module * { export * }\n" - "}\n" % (binary, binary) - ) - - with open(os.path.join(module_path, "module.modulemap"), "w") as module_file: - module_file.write(module_template) - - def ExecPackageFramework(self, framework, version): - """Takes a path to Something.framework and the Current version of that and - sets up all the symlinks.""" - # Find the name of the binary based on the part before the ".framework". - binary = os.path.basename(framework).split(".")[0] - - CURRENT = "Current" - RESOURCES = "Resources" - VERSIONS = "Versions" - - if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)): - # Binary-less frameworks don't seem to contain symlinks (see e.g. - # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle). - return - - # Move into the framework directory to set the symlinks correctly. - pwd = os.getcwd() - os.chdir(framework) - - # Set up the Current version. - self._Relink(version, os.path.join(VERSIONS, CURRENT)) - - # Set up the root symlinks. - self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary) - self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES) - - # Back to where we were before! - os.chdir(pwd) - - def _Relink(self, dest, link): - """Creates a symlink to |dest| named |link|. If |link| already exists, - it is overwritten.""" - if os.path.lexists(link): - os.remove(link) - os.symlink(dest, link) - - def ExecCompileIosFrameworkHeaderMap(self, out, framework, *all_headers): - framework_name = os.path.basename(framework).split(".")[0] - all_headers = [os.path.abspath(header) for header in all_headers] - filelist = {} - for header in all_headers: - filename = os.path.basename(header) - filelist[filename] = header - filelist[os.path.join(framework_name, filename)] = header - WriteHmap(out, filelist) - - def ExecCopyIosFrameworkHeaders(self, framework, *copy_headers): - header_path = os.path.join(framework, "Headers") - if not os.path.exists(header_path): - os.makedirs(header_path) - for header in copy_headers: - shutil.copy(header, os.path.join(header_path, os.path.basename(header))) - - def ExecCompileXcassets(self, keys, *inputs): - """Compiles multiple .xcassets files into a single .car file. - - This invokes 'actool' to compile all the inputs .xcassets files. The - |keys| arguments is a json-encoded dictionary of extra arguments to - pass to 'actool' when the asset catalogs contains an application icon - or a launch image. - - Note that 'actool' does not create the Assets.car file if the asset - catalogs does not contains imageset. - """ - command_line = [ - "xcrun", - "actool", - "--output-format", - "human-readable-text", - "--compress-pngs", - "--notices", - "--warnings", - "--errors", - ] - is_iphone_target = "IPHONEOS_DEPLOYMENT_TARGET" in os.environ - if is_iphone_target: - platform = os.environ["CONFIGURATION"].split("-")[-1] - if platform not in ("iphoneos", "iphonesimulator"): - platform = "iphonesimulator" - command_line.extend( - [ - "--platform", - platform, - "--target-device", - "iphone", - "--target-device", - "ipad", - "--minimum-deployment-target", - os.environ["IPHONEOS_DEPLOYMENT_TARGET"], - "--compile", - os.path.abspath(os.environ["CONTENTS_FOLDER_PATH"]), - ] - ) - else: - command_line.extend( - [ - "--platform", - "macosx", - "--target-device", - "mac", - "--minimum-deployment-target", - os.environ["MACOSX_DEPLOYMENT_TARGET"], - "--compile", - os.path.abspath(os.environ["UNLOCALIZED_RESOURCES_FOLDER_PATH"]), - ] - ) - if keys: - keys = json.loads(keys) - for key, value in keys.items(): - arg_name = "--" + key - if isinstance(value, bool): - if value: - command_line.append(arg_name) - elif isinstance(value, list): - for v in value: - command_line.append(arg_name) - command_line.append(str(v)) - else: - command_line.append(arg_name) - command_line.append(str(value)) - # Note: actool crashes if inputs path are relative, so use os.path.abspath - # to get absolute path name for inputs. - command_line.extend(map(os.path.abspath, inputs)) - subprocess.check_call(command_line) - - def ExecMergeInfoPlist(self, output, *inputs): - """Merge multiple .plist files into a single .plist file.""" - merged_plist = {} - for path in inputs: - plist = self._LoadPlistMaybeBinary(path) - self._MergePlist(merged_plist, plist) - plistlib.writePlist(merged_plist, output) - - def ExecCodeSignBundle(self, key, entitlements, provisioning, path, preserve): - """Code sign a bundle. - - This function tries to code sign an iOS bundle, following the same - algorithm as Xcode: - 1. pick the provisioning profile that best match the bundle identifier, - and copy it into the bundle as embedded.mobileprovision, - 2. copy Entitlements.plist from user or SDK next to the bundle, - 3. code sign the bundle. - """ - substitutions, overrides = self._InstallProvisioningProfile( - provisioning, self._GetCFBundleIdentifier() - ) - entitlements_path = self._InstallEntitlements( - entitlements, substitutions, overrides - ) - - args = ["codesign", "--force", "--sign", key] - if preserve == "True": - args.extend(["--deep", "--preserve-metadata=identifier,entitlements"]) - else: - args.extend(["--entitlements", entitlements_path]) - args.extend(["--timestamp=none", path]) - subprocess.check_call(args) - - def _InstallProvisioningProfile(self, profile, bundle_identifier): - """Installs embedded.mobileprovision into the bundle. - - Args: - profile: string, optional, short name of the .mobileprovision file - to use, if empty or the file is missing, the best file installed - will be used - bundle_identifier: string, value of CFBundleIdentifier from Info.plist - - Returns: - A tuple containing two dictionary: variables substitutions and values - to overrides when generating the entitlements file. - """ - source_path, provisioning_data, team_id = self._FindProvisioningProfile( - profile, bundle_identifier - ) - target_path = os.path.join( - os.environ["BUILT_PRODUCTS_DIR"], - os.environ["CONTENTS_FOLDER_PATH"], - "embedded.mobileprovision", - ) - shutil.copy2(source_path, target_path) - substitutions = self._GetSubstitutions(bundle_identifier, team_id + ".") - return substitutions, provisioning_data["Entitlements"] - - def _FindProvisioningProfile(self, profile, bundle_identifier): - """Finds the .mobileprovision file to use for signing the bundle. - - Checks all the installed provisioning profiles (or if the user specified - the PROVISIONING_PROFILE variable, only consult it) and select the most - specific that correspond to the bundle identifier. - - Args: - profile: string, optional, short name of the .mobileprovision file - to use, if empty or the file is missing, the best file installed - will be used - bundle_identifier: string, value of CFBundleIdentifier from Info.plist - - Returns: - A tuple of the path to the selected provisioning profile, the data of - the embedded plist in the provisioning profile and the team identifier - to use for code signing. - - Raises: - SystemExit: if no .mobileprovision can be used to sign the bundle. - """ - profiles_dir = os.path.join( - os.environ["HOME"], "Library", "MobileDevice", "Provisioning Profiles" - ) - if not os.path.isdir(profiles_dir): - print( - "cannot find mobile provisioning for %s" % (bundle_identifier), - file=sys.stderr, - ) - sys.exit(1) - provisioning_profiles = None - if profile: - profile_path = os.path.join(profiles_dir, profile + ".mobileprovision") - if os.path.exists(profile_path): - provisioning_profiles = [profile_path] - if not provisioning_profiles: - provisioning_profiles = glob.glob( - os.path.join(profiles_dir, "*.mobileprovision") - ) - valid_provisioning_profiles = {} - for profile_path in provisioning_profiles: - profile_data = self._LoadProvisioningProfile(profile_path) - app_id_pattern = profile_data.get("Entitlements", {}).get( - "application-identifier", "" - ) - for team_identifier in profile_data.get("TeamIdentifier", []): - app_id = f"{team_identifier}.{bundle_identifier}" - if fnmatch.fnmatch(app_id, app_id_pattern): - valid_provisioning_profiles[app_id_pattern] = ( - profile_path, - profile_data, - team_identifier, - ) - if not valid_provisioning_profiles: - print( - "cannot find mobile provisioning for %s" % (bundle_identifier), - file=sys.stderr, - ) - sys.exit(1) - # If the user has multiple provisioning profiles installed that can be - # used for ${bundle_identifier}, pick the most specific one (ie. the - # provisioning profile whose pattern is the longest). - selected_key = max(valid_provisioning_profiles, key=lambda v: len(v)) - return valid_provisioning_profiles[selected_key] - - def _LoadProvisioningProfile(self, profile_path): - """Extracts the plist embedded in a provisioning profile. - - Args: - profile_path: string, path to the .mobileprovision file - - Returns: - Content of the plist embedded in the provisioning profile as a dictionary. - """ - with tempfile.NamedTemporaryFile() as temp: - subprocess.check_call( - ["security", "cms", "-D", "-i", profile_path, "-o", temp.name] - ) - return self._LoadPlistMaybeBinary(temp.name) - - def _MergePlist(self, merged_plist, plist): - """Merge |plist| into |merged_plist|.""" - for key, value in plist.items(): - if isinstance(value, dict): - merged_value = merged_plist.get(key, {}) - if isinstance(merged_value, dict): - self._MergePlist(merged_value, value) - merged_plist[key] = merged_value - else: - merged_plist[key] = value - else: - merged_plist[key] = value - - def _LoadPlistMaybeBinary(self, plist_path): - """Loads into a memory a plist possibly encoded in binary format. - - This is a wrapper around plistlib.readPlist that tries to convert the - plist to the XML format if it can't be parsed (assuming that it is in - the binary format). - - Args: - plist_path: string, path to a plist file, in XML or binary format - - Returns: - Content of the plist as a dictionary. - """ - try: - # First, try to read the file using plistlib that only supports XML, - # and if an exception is raised, convert a temporary copy to XML and - # load that copy. - return plistlib.readPlist(plist_path) - except Exception: - pass - with tempfile.NamedTemporaryFile() as temp: - shutil.copy2(plist_path, temp.name) - subprocess.check_call(["plutil", "-convert", "xml1", temp.name]) - return plistlib.readPlist(temp.name) - - def _GetSubstitutions(self, bundle_identifier, app_identifier_prefix): - """Constructs a dictionary of variable substitutions for Entitlements.plist. - - Args: - bundle_identifier: string, value of CFBundleIdentifier from Info.plist - app_identifier_prefix: string, value for AppIdentifierPrefix - - Returns: - Dictionary of substitutions to apply when generating Entitlements.plist. - """ - return { - "CFBundleIdentifier": bundle_identifier, - "AppIdentifierPrefix": app_identifier_prefix, - } - - def _GetCFBundleIdentifier(self): - """Extracts CFBundleIdentifier value from Info.plist in the bundle. - - Returns: - Value of CFBundleIdentifier in the Info.plist located in the bundle. - """ - info_plist_path = os.path.join( - os.environ["TARGET_BUILD_DIR"], os.environ["INFOPLIST_PATH"] - ) - info_plist_data = self._LoadPlistMaybeBinary(info_plist_path) - return info_plist_data["CFBundleIdentifier"] - - def _InstallEntitlements(self, entitlements, substitutions, overrides): - """Generates and install the ${BundleName}.xcent entitlements file. - - Expands variables "$(variable)" pattern in the source entitlements file, - add extra entitlements defined in the .mobileprovision file and the copy - the generated plist to "${BundlePath}.xcent". - - Args: - entitlements: string, optional, path to the Entitlements.plist template - to use, defaults to "${SDKROOT}/Entitlements.plist" - substitutions: dictionary, variable substitutions - overrides: dictionary, values to add to the entitlements - - Returns: - Path to the generated entitlements file. - """ - source_path = entitlements - target_path = os.path.join( - os.environ["BUILT_PRODUCTS_DIR"], os.environ["PRODUCT_NAME"] + ".xcent" - ) - if not source_path: - source_path = os.path.join(os.environ["SDKROOT"], "Entitlements.plist") - shutil.copy2(source_path, target_path) - data = self._LoadPlistMaybeBinary(target_path) - data = self._ExpandVariables(data, substitutions) - if overrides: - for key in overrides: - if key not in data: - data[key] = overrides[key] - plistlib.writePlist(data, target_path) - return target_path - - def _ExpandVariables(self, data, substitutions): - """Expands variables "$(variable)" in data. - - Args: - data: object, can be either string, list or dictionary - substitutions: dictionary, variable substitutions to perform - - Returns: - Copy of data where each references to "$(variable)" has been replaced - by the corresponding value found in substitutions, or left intact if - the key was not found. - """ - if isinstance(data, str): - for key, value in substitutions.items(): - data = data.replace("$(%s)" % key, value) - return data - if isinstance(data, list): - return [self._ExpandVariables(v, substitutions) for v in data] - if isinstance(data, dict): - return {k: self._ExpandVariables(data[k], substitutions) for k in data} - return data - - -def NextGreaterPowerOf2(x): - return 2 ** (x).bit_length() - - -def WriteHmap(output_name, filelist): - """Generates a header map based on |filelist|. - - Per Mark Mentovai: - A header map is structured essentially as a hash table, keyed by names used - in #includes, and providing pathnames to the actual files. - - The implementation below and the comment above comes from inspecting: - http://www.opensource.apple.com/source/distcc/distcc-2503/distcc_dist/include_server/headermap.py?txt - while also looking at the implementation in clang in: - https://llvm.org/svn/llvm-project/cfe/trunk/lib/Lex/HeaderMap.cpp - """ - magic = 1751998832 - version = 1 - _reserved = 0 - count = len(filelist) - capacity = NextGreaterPowerOf2(count) - strings_offset = 24 + (12 * capacity) - max_value_length = max(len(value) for value in filelist.values()) - - out = open(output_name, "wb") - out.write( - struct.pack( - "=20.0.0" }, "scripts": { - "build": "node-gyp rebuild", + "build": "node-gyp rebuild && install_name_tool -change libspanner.so @loader_path/libspanner.so ./build/Release/spanner_napi.node", "test": "node test.js", "setup": "node setup_db.js" }, From 8c83c0b7804221108febf8a05c6a5f2c37247b7e Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Fri, 10 Apr 2026 16:48:27 +0530 Subject: [PATCH 6/9] napi metadata changes --- .../spannerlib-nodejs-poc/napi/binding.gyp | 8 +- .../spannerlib-nodejs-poc/napi/package.json | 3 +- .../napi/src/cpp/addon.cc | 44 +++++++ .../napi/src/ffi/utils.js | 5 + .../napi/src/lib/connection.js | 30 ++++- .../napi/src/lib/rows.js | 122 +++++++++++------- .../spannerlib-nodejs-poc/napi/test.js | 19 ++- 7 files changed, 170 insertions(+), 61 deletions(-) diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp index 1847c6c2..54392a3e 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/binding.gyp @@ -39,10 +39,16 @@ }], ['OS=="linux"', { 'ldflags': [ - '-Wl,-rpath,\'$$ORIGIN/../../../shared\'' + '-Wl,-rpath,$$ORIGIN' ], 'libraries': [ '<(module_root_dir)/../../../shared/libspanner.so' + ], + 'copies': [ + { + 'destination': '<(PRODUCT_DIR)', + 'files': [ '<(module_root_dir)/../../../shared/libspanner.so' ] + } ] }] ] diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json index 3d528857..09d870ff 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/package.json @@ -6,7 +6,8 @@ "node": ">=20.0.0" }, "scripts": { - "build": "node-gyp rebuild && install_name_tool -change libspanner.so @loader_path/libspanner.so ./build/Release/spanner_napi.node", + "build": "node-gyp rebuild", + "postbuild": "node -e \"if (process.platform === 'darwin') require('child_process').execSync('install_name_tool -change libspanner.so @loader_path/libspanner.so ./build/Release/spanner_napi.node')\"", "test": "node test.js", "setup": "node setup_db.js" }, diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/cpp/addon.cc b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/cpp/addon.cc index 481d72e1..028acf73 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/cpp/addon.cc +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/cpp/addon.cc @@ -247,6 +247,49 @@ Napi::Value NextWrapper(const Napi::CallbackInfo& info) { return env.Undefined(); } +// +// Worker 7: Metadata asynchronously +// +class MetadataWorker : public Napi::AsyncWorker { +public: + MetadataWorker(Napi::Function& callback, int64_t poolId, int64_t connId, int64_t rowsId) + : AsyncWorker(callback), poolId_(poolId), connId_(connId), rowsId_(rowsId), result_({0, 0, 0, 0, nullptr}) {} + + void Execute() override { + result_ = ::Metadata(poolId_, connId_, rowsId_); + } + + void OnOK() override { + Napi::Env env = Env(); + Napi::Object obj = Napi::Object::New(env); + obj.Set("r0", Napi::Number::New(env, result_.r0)); + obj.Set("r1", Napi::Number::New(env, result_.r1)); + obj.Set("r2", Napi::Number::New(env, result_.r2)); + obj.Set("r3", Napi::Number::New(env, result_.r3)); + if (result_.r4 != nullptr && result_.r3 > 0) { + obj.Set("r4", Napi::Buffer::Copy(env, (uint8_t*)result_.r4, result_.r3)); + } else { + obj.Set("r4", env.Null()); + } + Callback().Call({env.Null(), obj}); + } +private: + int64_t poolId_, connId_, rowsId_; + Metadata_return result_; +}; + +Napi::Value MetadataWrapper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + int64_t pid = info[0].As().Int64Value(); + int64_t cid = info[1].As().Int64Value(); + int64_t rid = info[2].As().Int64Value(); + Napi::Function cb = info[3].As(); + + MetadataWorker* worker = new MetadataWorker(cb, pid, cid, rid); + worker->Queue(); + return env.Undefined(); +} + // Memory Release (Synchronous as it is just freeing RAM via GC) Napi::Value NativeRelease(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); @@ -288,6 +331,7 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) { exports.Set("CloseRows", Napi::Function::New(env, CloseRowsWrapper)); exports.Set("Release", Napi::Function::New(env, NativeRelease)); + exports.Set("Metadata", Napi::Function::New(env, MetadataWrapper)); return exports; } diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/utils.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/utils.js index ad1f471f..2b389bbf 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/utils.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/ffi/utils.js @@ -1,5 +1,8 @@ const addon = require('../../build/Release/spanner_napi.node'); +const ENCODING_JSON = 0; +const ENCODING_PROTOBUF = 1; + /** * Normalizes C++ responses to look structurally identical to what Koffi did. * Koffi returned: { r0: int, r1: int, r2: int, r3: int, r4: pointer/buffer } @@ -43,6 +46,8 @@ function invokeAsync(funcName, constructor1, constructor2, ...args) { const Release = addon.Release; module.exports = { + ENCODING_JSON, + ENCODING_PROTOBUF, invokeAsync, Release }; diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/connection.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/connection.js index 83908ae6..8be9ec7b 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/connection.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/connection.js @@ -56,17 +56,37 @@ class Connection { const ExecuteSqlRequestProto = google.spanner.v1.ExecuteSqlRequest; const serializedPb = ExecuteSqlRequestProto.encode(requestObj).finish(); - // 2. Transmit the standard protobuf binary buffer over CGO FFI seamlessly - const handled = await invokeAsync( - Execute, - null, // Rows gets constructed afterward + // 1. Execute the SQL to get a Rows identifier + const rowsResult = await invokeAsync( + "Execute", + null, null, this.pool.oid, this.oid, serializedPb ); + const rowsId = rowsResult.objectId; - return new Rows(this, handled.objectId); + // 2. Fetch the metadata to get column names + const metadataResult = await invokeAsync( + "Metadata", + null, + null, + this.pool.oid, + this.oid, + rowsId + ); + + // 3. Decode the metadata protobuf + const ResultSetMetadataProto = google.spanner.v1.ResultSetMetadata; + const metadata = ResultSetMetadataProto.decode(metadataResult.protobufBytes); + const columnInfo = metadata.rowType.fields.map(field => ({ + name: field.name, + typeCode: field.type.code + })); + + // 4. Return a new Rows object, now equipped with the column info + return new Rows(this, rowsId, columnInfo); } /** diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/rows.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/rows.js index 9d0f089d..cffbd435 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/rows.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/src/lib/rows.js @@ -1,70 +1,96 @@ -const { CloseRows, Next } = require('../ffi/bindings.js'); -const { invokeAsync } = require('../ffi/utils.js'); +const { invokeAsync, ENCODING_PROTOBUF } = require('../ffi/utils.js'); const { spannerLib } = require('./spannerlib.js'); const { google } = require('@google-cloud/spanner/build/protos/protos.js'); +const ListValue = google.protobuf.ListValue; + +/** + * Parses a binary `ListValue` protobuf message into a key-value row object. + * @param {Buffer} buffer The binary buffer from the Go library. + * @param {Array<{name: string, typeCode: number}>} columnInfo An array of objects with column names and types. + * @returns {object|null} + */ +function parseRowToObject(buffer, columnInfo) { + if (!buffer || buffer.length === 0) { + return null; // End of result set + } + + const listValue = ListValue.decode(buffer); + const rowObject = {}; + const values = listValue.values; + + columnInfo.forEach((column, index) => { + const value = values[index]; + const columnName = column.name; + let parsedValue; + + // The decoded `value` object has a 'kind' oneof field. + // We check which property is set to get the primitive value. + switch (value.kind) { + case 'nullValue': + parsedValue = null; + break; + case 'numberValue': + parsedValue = value.numberValue; + break; + case 'stringValue': + parsedValue = value.stringValue; + break; + case 'boolValue': + parsedValue = value.boolValue; + break; + default: + parsedValue = undefined; + } + rowObject[columnName] = parsedValue; + }); + + return rowObject; +} class Rows { /** - * @param {import('./connection.js').Connection} conn - * @param {Number} objectId - The OID identifying these rows inside the Go Driver + * @param {import('./connection.js').Connection} connection + * @param {Number} oid + * @param {Array<{name: string, typeCode: number}>} columnInfo */ - constructor(conn, objectId) { - this.conn = conn; - - /** - * The Object ID (OID). - * Used to execute operations like `.next()` against THIS specific ResultSet inside Go. - * @type {Number|null} - */ - this.oid = objectId; - + constructor(connection, oid, columnInfo) { + this.connection = connection; + this.oid = oid; + this.pinnerId = null; this.closed = false; - - // FinalizationRegistry could optionally be mapped to this via - // spannerLib.register(this, pinnerId_from_execute) - // For the POC, we won't fully map the Rows Pinner unless needed - // by the Next() function iterator. + this.columnInfo = columnInfo; // Store column names and types } /** - * Iterates to the next result chunk. - * In a full implementation, it would call `Next(poolId, connId, rowsId, ...)` natively. + * Fetches the next row from the result set. + * @returns {Promise} A promise that resolves to a row object, or null if there are no more rows. */ async next() { - if (this.closed) throw new Error("Rows object is already closed"); - - // Go Signature: Next(poolId, connId, rowsId, numRows, encodeRowOption) - // We pass 1 for numRows, and 0 for encodeRowOption as per POC defaults - const handled = await invokeAsync(Next, null, null, this.conn.pool.oid, this.conn.oid, this.oid, 1, 0); - - // Handle EOF case (The chunk buffer is perfectly empty or contains no message) - if (!handled.protobufBytes || handled.protobufBytes.length === 0) { - return null; // Signals end of rows to the caller - } - - // The returned message contains a google.protobuf.ListValue according to the spec! - // We natively unpack those bytes matching standard Protobuf conventions. - const listValueProto = google.protobuf.ListValue; - const decodedList = listValueProto.decode(handled.protobufBytes); + if (this.closed) throw new Error("Rows are already closed"); - // This converts the complex generic Protobuf ListValue deeply into native Javascript! - const jsonRecord = listValueProto.toObject(decodedList, { - longs: String, // Ensure Int64 types from Spanner decode as Strings instead of mangled JS doubles - enums: String, - bytes: String, - }); + const handled = await invokeAsync( + "Next", + null, + null, + this.connection.pool.oid, + this.connection.oid, + this.oid, + 1, // Fetch one row at a time + ENCODING_PROTOBUF + ); - return jsonRecord.values || []; + // The result for `Next` is a binary `ListValue` protobuf message. + return parseRowToObject(handled.protobufBytes, this.columnInfo); } - /** - * Closes the rows object safely, waiting on the network. - */ async close() { if (!this.closed) { this.closed = true; - // Native FFI execution in the background - await invokeAsync(CloseRows, null, spannerLib, this.conn.pool.oid, this.conn.oid, this.oid); + try { + await invokeAsync("CloseRows", this, spannerLib, this.connection.pool.oid, this.connection.oid, this.oid); + } finally { + spannerLib.unregister(this, this.pinnerId); + } } } } diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test.js b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test.js index 62de5264..ee70ea67 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/napi/test.js @@ -34,12 +34,19 @@ async function runTest() { rows = await connection.executeSql(sqlQuery); console.log(`Executed SQL successfully in ${(performance.now() - startTime).toFixed(3)}ms (Rows OID: ${rows.oid})`); - console.log("\n[JS-App] 4. Fetching ResultSet Native Types (Int, String, Float, Bool)..."); - let nextRow; - while ((nextRow = await rows.next()) !== null) { - // nextRow is an array of Value protobuf objects (Google Protobuf Structs) - console.log(" - Fetched native row chunk ->"); - console.log(" " + JSON.stringify(nextRow)); + console.log("\n[JS-App] 4. Fetching ResultSet as Objects..."); + let row; + const results = []; + while ((row = await rows.next()) !== null) { + results.push(row); + } + + console.log(" - Fetched rows ->"); + console.log(JSON.stringify(results, null, 2)); + + // Example of accessing a property on the first row + if (results.length > 0) { + console.log(`\nExample access: results[0].FirstName is "${results[0].FirstName}"`); } } catch (err) { From 10f14a9334048787b0fb0d430318d93071b29bcf Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Mon, 13 Apr 2026 12:13:52 +0530 Subject: [PATCH 7/9] benchmark --- .gitignore | 3 +- .../benchmark/RESULTS.md | 61 ++++ .../benchmark/benchmark.js | 332 ++++++++++++++++++ .../benchmark/package.json | 12 + 4 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/benchmark.js create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/package.json diff --git a/.gitignore b/.gitignore index 8769a30e..2931fbaf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ gorm/ .idea .DS_Store node_modules -build/ \ No newline at end of file +build/ +package-lock.json \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md new file mode 100644 index 00000000..e79622e9 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md @@ -0,0 +1,61 @@ +# Benchmark Results + +## Environment +- **Database**: `projects/span-cloud-testing/instances/gargsurbhi-testing/databases/test-db-koffi-136` + +## Mitata Latency Benchmark + +``` +cpu: Apple M4 Pro +runtime: node v22.17.1 (arm64-darwin) + +benchmark time (avg) (min … max) p75 p99 p999 +--------------------------------------------------------------- ----------------------------- +Koffi Single Point Read 66'049 µs/iter (62'838 µs … 69'484 µs) 68'705 µs 69'484 µs 69'484 µs +N-API Single Point Read 71'349 µs/iter (66'112 µs … 83'420 µs) 76'782 µs 83'420 µs 83'420 µs +IPC Single Point Read 75'546 µs/iter (66'407 µs … 97'423 µs) 91'583 µs 97'423 µs 97'423 µs +``` + +## Summary of Manual Benchmark (Average of 5 Runs) + +| Wrapper | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff (Avg) | +| :--- | :--- | :--- | :--- | :--- | :--- | +| **Koffi** | 13.83 ops/sec | 72.48 ms | 60.38 ms | 159.86 ms | 0.73 MB | +| **N-API** | 13.97 ops/sec | 71.81 ms | 59.34 ms | 267.20 ms | 0.55 MB | +| **IPC** | 13.24 ops/sec | 75.80 ms | 63.78 ms | 215.10 ms | 13.28 MB | + +## Detailed Runs + +### Koffi + +| Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| Run 1 | 2026-04-13T06:26:00.195Z | 2026-04-13T06:26:35.666Z | 14.10 ops/sec | 70.94 ms | 60.02 ms | 369.14 ms | 0.68 MB | +| Run 2 | 2026-04-13T06:26:37.677Z | 2026-04-13T06:27:11.543Z | 14.76 ops/sec | 67.73 ms | 59.99 ms | 95.69 ms | 0.76 MB | +| Run 3 | 2026-04-13T06:27:13.556Z | 2026-04-13T06:27:51.062Z | 13.33 ops/sec | 75.01 ms | 61.05 ms | 108.63 ms | 0.72 MB | +| Run 4 | 2026-04-13T06:27:53.073Z | 2026-04-13T06:28:31.692Z | 12.95 ops/sec | 77.24 ms | 61.14 ms | 106.80 ms | 0.71 MB | +| Run 5 | 2026-04-13T06:28:33.703Z | 2026-04-13T06:29:09.433Z | 13.99 ops/sec | 71.46 ms | 59.70 ms | 119.04 ms | 0.78 MB | +| **Average** | - | - | 13.83 ops/sec | 72.48 ms | 60.38 ms | 159.86 ms | 0.73 MB | + +### N-API + +| Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| Run 1 | 2026-04-13T06:30:09.445Z | 2026-04-13T06:30:45.556Z | 13.85 ops/sec | 72.22 ms | 59.20 ms | 633.28 ms | 0.56 MB | +| Run 2 | 2026-04-13T06:30:47.561Z | 2026-04-13T06:31:20.317Z | 15.26 ops/sec | 65.51 ms | 59.25 ms | 131.44 ms | 0.53 MB | +| Run 3 | 2026-04-13T06:31:22.329Z | 2026-04-13T06:31:57.787Z | 14.10 ops/sec | 70.92 ms | 58.95 ms | 129.25 ms | 0.56 MB | +| Run 4 | 2026-04-13T06:31:59.797Z | 2026-04-13T06:32:36.084Z | 13.78 ops/sec | 72.57 ms | 59.58 ms | 192.24 ms | 0.55 MB | +| Run 5 | 2026-04-13T06:32:38.096Z | 2026-04-13T06:33:17.018Z | 12.85 ops/sec | 77.84 ms | 59.74 ms | 249.79 ms | 0.55 MB | +| **Average** | - | - | 13.97 ops/sec | 71.81 ms | 59.34 ms | 267.20 ms | 0.55 MB | + +### IPC + +| Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| Run 1 | 2026-04-13T06:34:17.030Z | 2026-04-13T06:34:58.429Z | 12.08 ops/sec | 82.80 ms | 63.94 ms | 608.08 ms | 8.40 MB | +| Run 2 | 2026-04-13T06:35:00.440Z | 2026-04-13T06:35:39.422Z | 12.83 ops/sec | 77.96 ms | 64.92 ms | 134.13 ms | 15.16 MB | +| Run 3 | 2026-04-13T06:35:41.437Z | 2026-04-13T06:36:17.121Z | 14.01 ops/sec | 71.37 ms | 62.60 ms | 112.61 ms | 15.49 MB | +| Run 4 | 2026-04-13T06:36:19.130Z | 2026-04-13T06:36:54.629Z | 14.09 ops/sec | 71.00 ms | 62.87 ms | 118.40 ms | 13.68 MB | +| Run 5 | 2026-04-13T06:36:56.642Z | 2026-04-13T06:37:34.589Z | 13.18 ops/sec | 75.89 ms | 64.54 ms | 102.27 ms | 13.66 MB | +| **Average** | - | - | 13.24 ops/sec | 75.80 ms | 63.78 ms | 215.10 ms | 13.28 MB | + diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/benchmark.js b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/benchmark.js new file mode 100644 index 00000000..05fd4cfe --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/benchmark.js @@ -0,0 +1,332 @@ +const { bench, run } = require('mitata'); +const fs = require('fs'); +const path = require('path'); + +// Helper to read DB name from any of the POC directories +function getDbName() { + const paths = [ + path.resolve(__dirname, '../koffi/test-db.txt'), + path.resolve(__dirname, '../napi/test-db.txt'), + path.resolve(__dirname, '../ipc/test-db.txt') + ]; + for (const p of paths) { + try { + if (fs.existsSync(p)) { + return fs.readFileSync(p, 'utf8').trim(); + } + } catch (e) { + // Ignore + } + } + return "dummy-testing-db"; +} + +const dbName = getDbName(); +const dbPath = `projects/span-cloud-testing/instances/gargsurbhi-testing/databases/${dbName}`; +const sqlQuery = "SELECT SingerId, FirstName, LastName, IsActive, Balance FROM Singers WHERE SingerId = 1"; + +console.log(`Using database: ${dbPath}`); + +// Import wrappers +let KoffiPool, KoffiCleanup; +try { + const koffi = require('../koffi'); + KoffiPool = koffi.Pool; + KoffiCleanup = koffi.cleanup; +} catch (e) { + console.warn("Could not load Koffi wrapper:", e.message); +} + +let NapiPool, NapiCleanup; +try { + const napi = require('../napi'); + NapiPool = napi.Pool; + NapiCleanup = napi.cleanup; +} catch (e) { + console.warn("Could not load N-API wrapper:", e.message); +} + +let IpcPool; +try { + const ipc = require('../ipc'); + IpcPool = ipc.Pool; +} catch (e) { + console.warn("Could not load IPC wrapper:", e.message); +} + +/** + * Helper for manual measurement + */ +async function measure(name, conn, executeMethod, iterations = 500, runs = 5, sleepMs = 2000) { + console.log(`\nRunning benchmark for ${name} (${runs} runs of ${iterations} iterations)...`); + + const runResults = []; + + for (let r = 0; r < runs; r++) { + if (r > 0) { + console.log(` Sleeping for ${sleepMs}ms to let DB cool down...`); + await new Promise(resolve => setTimeout(resolve, sleepMs)); + } + + console.log(` Run ${r + 1}/${runs}...`); + if (global.gc) global.gc(); + + const startTimeStr = new Date().toISOString(); + const startMemory = process.memoryUsage().heapUsed; + const startTime = performance.now(); + + let min = Infinity; + let max = 0; + let total = 0; + + for (let i = 0; i < iterations; i++) { + const opStart = performance.now(); + const rows = await conn[executeMethod](sqlQuery); + await rows.next(); + await rows.close(); + const opEnd = performance.now(); + + const opDiff = opEnd - opStart; + if (opDiff < min) min = opDiff; + if (opDiff > max) max = opDiff; + total += opDiff; + } + + const endTime = performance.now(); + const endTimeStr = new Date().toISOString(); + const endMemory = process.memoryUsage().heapUsed; + + const timeTaken = endTime - startTime; + const opsPerSec = (iterations / timeTaken) * 1000; + const memoryUsed = (endMemory - startMemory) / 1024 / 1024; + const avgLatency = total / iterations; + + console.log(` Throughput: ${opsPerSec.toFixed(2)} ops/sec`); + console.log(` Latency: Avg ${avgLatency.toFixed(2)} ms, Min ${min.toFixed(2)} ms, Max ${max.toFixed(2)} ms`); + console.log(` Heap Diff: ${memoryUsed.toFixed(2)} MB`); + + runResults.push({ + opsPerSec, + avgLatency, + min, + max, + memoryUsed, + startTime: startTimeStr, + endTime: endTimeStr + }); + } + + const avg = { + opsPerSec: runResults.reduce((acc, r) => acc + r.opsPerSec, 0) / runs, + avgLatency: runResults.reduce((acc, r) => acc + r.avgLatency, 0) / runs, + min: runResults.reduce((acc, r) => acc + r.min, 0) / runs, + max: runResults.reduce((acc, r) => acc + r.max, 0) / runs, + memoryUsed: runResults.reduce((acc, r) => acc + r.memoryUsed, 0) / runs + }; + + console.log(`\n Average for ${name}:`); + console.log(` Throughput: ${avg.opsPerSec.toFixed(2)} ops/sec`); + console.log(` Latency: Avg ${avg.avgLatency.toFixed(2)} ms, Min ${avg.min.toFixed(2)} ms, Max ${avg.max.toFixed(2)} ms`); + console.log(` Heap Diff: ${avg.memoryUsed.toFixed(2)} MB`); + + return { runResults, avg }; +} + +/** + * Initialize all available wrappers + */ +async function initialize() { + const connections = {}; + + if (KoffiPool) { + try { + console.log("Initializing Koffi..."); + const pool = await KoffiPool.create("nodejs-koffi-poc", dbPath); + const conn = await pool.createConnection(); + const rows = await conn.executeSql(sqlQuery); + await rows.next(); + await rows.close(); + connections.koffi = { pool, conn, cleanup: KoffiCleanup }; + } catch (e) { + console.error("Failed to initialize Koffi:", e.message); + } + } + + if (NapiPool) { + try { + console.log("Initializing N-API..."); + const pool = await NapiPool.create("nodejs-napi-poc", dbPath); + const conn = await pool.createConnection(); + const rows = await conn.executeSql(sqlQuery); + await rows.next(); + await rows.close(); + connections.napi = { pool, conn, cleanup: NapiCleanup }; + } catch (e) { + console.error("Failed to initialize N-API:", e.message); + } + } + + if (IpcPool) { + try { + console.log("Initializing IPC (Requires gRPC server running)..."); + const pool = await IpcPool.create(dbPath, "nodejs-ipc-poc"); + const conn = await pool.createConnection(); + const rows = await conn.execute(sqlQuery); + await rows.next(); + await rows.close(); + connections.ipc = { pool, conn }; + } catch (e) { + console.error("Failed to initialize IPC. Is the gRPC server running on localhost:50051?", e.message); + } + } + + return connections; +} + +/** + * Run Mitata Latency Benchmark + */ +async function runMitataBenchmark(connections) { + console.log("\nStarting Mitata Latency Benchmark..."); + + if (connections.koffi) { + bench('Koffi Single Point Read', async () => { + const rows = await connections.koffi.conn.executeSql(sqlQuery); + await rows.next(); + await rows.close(); + }); + } + + if (connections.napi) { + bench('N-API Single Point Read', async () => { + const rows = await connections.napi.conn.executeSql(sqlQuery); + await rows.next(); + await rows.close(); + }); + } + + if (connections.ipc) { + bench('IPC Single Point Read', async () => { + const rows = await connections.ipc.conn.execute(sqlQuery); + await rows.next(); + await rows.close(); + }); + } + + const originalLog = console.log; + let mitataOutput = ''; + console.log = (...args) => { + mitataOutput += args.join(' ') + '\n'; + originalLog.apply(console, args); + }; + + await run(); + + console.log = originalLog; + return mitataOutput; +} + +/** + * Run Manual Throughput & Memory Benchmark + */ +async function runManualBenchmark(connections, iterations = 500) { + console.log("\nStarting Manual Throughput & Memory Benchmark..."); + const results = {}; + + const wrappers = []; + if (connections.koffi) wrappers.push({ key: 'Koffi', name: 'Koffi', conn: connections.koffi.conn, method: 'executeSql' }); + if (connections.napi) wrappers.push({ key: 'Napi', name: 'N-API', conn: connections.napi.conn, method: 'executeSql' }); + if (connections.ipc) wrappers.push({ key: 'Ipc', name: 'IPC', conn: connections.ipc.conn, method: 'execute' }); + + for (let i = 0; i < wrappers.length; i++) { + if (i > 0) { + console.log(`\nSleeping for 1 minute before ${wrappers[i].name} to let DB cool down...`); + await new Promise(resolve => setTimeout(resolve, 60000)); + } + const w = wrappers[i]; + results[w.key] = await measure(w.name, w.conn, w.method, iterations); + } + + return results; +} + +/** + * Save results to RESULTS.md + */ +function saveResults(mitataOutput, results, iterations) { + console.log("\nSaving results to RESULTS.md..."); + let report = `# Benchmark Results\n\n`; + report += `## Environment\n`; + report += `- **Database**: \`${dbPath}\`\n\n`; + + report += `## Mitata Latency Benchmark\n\n`; + report += `\`\`\`\n${mitataOutput}\`\`\`\n\n`; + + report += `## Summary of Manual Benchmark (Average of 5 Runs)\n\n`; + report += `| Wrapper | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff (Avg) |\n`; + report += `| :--- | :--- | :--- | :--- | :--- | :--- |\n`; + + if (results.Koffi) { + const avg = results.Koffi.avg; + report += `| **Koffi** | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.min.toFixed(2)} ms | ${avg.max.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n`; + } + if (results.Napi) { + const avg = results.Napi.avg; + report += `| **N-API** | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.min.toFixed(2)} ms | ${avg.max.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n`; + } + if (results.Ipc) { + const avg = results.Ipc.avg; + report += `| **IPC** | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.min.toFixed(2)} ms | ${avg.max.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n`; + } + + report += `\n## Detailed Runs\n\n`; + + function appendDetails(name, data) { + if (!data) return; + report += `### ${name}\n\n`; + report += `| Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff |\n`; + report += `| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |\n`; + data.runResults.forEach((r, i) => { + report += `| Run ${i + 1} | ${r.startTime} | ${r.endTime} | ${r.opsPerSec.toFixed(2)} ops/sec | ${r.avgLatency.toFixed(2)} ms | ${r.min.toFixed(2)} ms | ${r.max.toFixed(2)} ms | ${r.memoryUsed.toFixed(2)} MB |\n`; + }); + const avg = data.avg; + report += `| **Average** | - | - | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.min.toFixed(2)} ms | ${avg.max.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n\n`; + } + + appendDetails('Koffi', results.Koffi); + appendDetails('N-API', results.Napi); + appendDetails('IPC', results.Ipc); + + fs.writeFileSync(path.resolve(__dirname, 'RESULTS.md'), report); + console.log("Results saved to RESULTS.md"); +} + +async function main() { + const connections = await initialize(); + + const mitataOutput = await runMitataBenchmark(connections); + + const iterations = 500; + const results = await runManualBenchmark(connections, iterations); + + saveResults(mitataOutput, results, iterations); + + // Cleanup + console.log("\nCleaning up..."); + if (connections.koffi) { + await connections.koffi.conn.close(); + await connections.koffi.pool.close(); + if (connections.koffi.cleanup) connections.koffi.cleanup(); + } + if (connections.napi) { + await connections.napi.conn.close(); + await connections.napi.pool.close(); + if (connections.napi.cleanup) connections.napi.cleanup(); + } + if (connections.ipc) { + await connections.ipc.conn.close(); + await connections.ipc.pool.close(); + } +} + +main().catch(console.error); diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/package.json b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/package.json new file mode 100644 index 00000000..53e21387 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/package.json @@ -0,0 +1,12 @@ +{ + "name": "spannerlib-nodejs-poc-benchmark", + "version": "1.0.0", + "description": "Benchmark for Spanner Node Wrappers POC", + "main": "benchmark.js", + "scripts": { + "test": "node benchmark.js" + }, + "dependencies": { + "mitata": "^0.1.11" + } +} From e41d93a4a36077e74851fda7b9329c3c05bf2d07 Mon Sep 17 00:00:00 2001 From: surbhigarg92 Date: Mon, 13 Apr 2026 17:11:56 +0000 Subject: [PATCH 8/9] benchmarking results --- .gitignore | 3 +- spannerlib/.gitignore | 2 + .../spannerlib-nodejs-poc/benchmark/README.md | 79 +++++++++++++ .../benchmark/RESULTS.md | 54 ++++----- .../benchmark/benchmark.js | 111 ++++++++++++------ 5 files changed, 183 insertions(+), 66 deletions(-) create mode 100644 spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/README.md diff --git a/.gitignore b/.gitignore index 2931fbaf..e8178a80 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ gorm/ .DS_Store node_modules build/ -package-lock.json \ No newline at end of file +package-lock.json +googleapis/ \ No newline at end of file diff --git a/spannerlib/.gitignore b/spannerlib/.gitignore index 02b98474..ddc2028a 100644 --- a/spannerlib/.gitignore +++ b/spannerlib/.gitignore @@ -10,3 +10,5 @@ vendor/bundle *.swp ext/ Gemfile.lock +/googleapis/ +package-lock.json \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/README.md b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/README.md new file mode 100644 index 00000000..08034ca0 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/README.md @@ -0,0 +1,79 @@ +# Spanner Node.js Wrappers Benchmark + +This directory contains a benchmark suite to compare the performance, throughput, and memory usage of three different Node.js wrappers for the Spanner Shared C-Library: +1. **Koffi** (Fast FFI) +2. **N-API** (Native C++ Addon) +3. **IPC** (gRPC Server/Client) + +## Prerequisites +Ensure you have the following installed on the machine: +* **Node.js** (v22 recommended) +* **Go** (v1.22 recommended) +* **Build Tools** (`gcc`, `g++`, `make`) + +--- + +## Setup Instructions + +### 1. Fetch Google API Protos (For IPC) +The IPC wrapper depends on standard Google API protos. You can fetch them by running the build script in the `grpc-server` directory: + +```bash +cd spannerlib/grpc-server +./build-protos.sh +``` +*(Note: This script also attempts to generate Go code using `protoc`. If you do not have `protoc` installed, it may show an error on the generation step, but it will still have successfully cloned the `googleapis` folder that Node.js needs).* + +### 2. Build the Go Shared Library +Navigate to the shared library directory and build the `.so` file: +```bash +cd spannerlib/shared +go build -o libspanner.so -buildmode=c-shared shared_lib.go +``` + +### 3. Install Dependencies for Wrappers +Navigate to each wrapper directory and install its specific dependencies: + +**Koffi:** +```bash +cd spannerlib/wrappers/spannerlib-nodejs-poc/koffi +npm install +``` + +**N-API:** +```bash +cd spannerlib/wrappers/spannerlib-nodejs-poc/napi +npm install # This will also automatically build the C++ addon +``` + +**IPC:** +```bash +cd spannerlib/wrappers/spannerlib-nodejs-poc/ipc +npm install +``` + +### 4. Start the gRPC Server (Required for IPC) +The IPC wrapper requires the Go gRPC server to be running. +Navigate to `spannerlib/grpc-server` and run it in the background (or in a `tmux` session): +```bash +cd spannerlib/grpc-server +nohup go run server.go localhost:50051 tcp > server.log 2>&1 & +``` + +--- + +## Running the Benchmark + +Once all setups are complete, navigate to this directory: + +```bash +cd spannerlib/wrappers/spannerlib-nodejs-poc/benchmark +npm install +node --expose-gc benchmark.js +``` + +## Results +The script will generate a `RESULTS.md` file in this directory containing: +* Latency statistics from `mitata`. +* Throughput (ops/sec) and Heap memory delta for 5 runs of each wrapper. +* A 1-minute cooldown sleep is automatically applied between wrappers to ensure DB cooling and isolation. diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md index e79622e9..9bbd4cd9 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md @@ -4,25 +4,19 @@ - **Database**: `projects/span-cloud-testing/instances/gargsurbhi-testing/databases/test-db-koffi-136` ## Mitata Latency Benchmark - -``` -cpu: Apple M4 Pro -runtime: node v22.17.1 (arm64-darwin) - benchmark time (avg) (min … max) p75 p99 p999 --------------------------------------------------------------- ----------------------------- -Koffi Single Point Read 66'049 µs/iter (62'838 µs … 69'484 µs) 68'705 µs 69'484 µs 69'484 µs -N-API Single Point Read 71'349 µs/iter (66'112 µs … 83'420 µs) 76'782 µs 83'420 µs 83'420 µs -IPC Single Point Read 75'546 µs/iter (66'407 µs … 97'423 µs) 91'583 µs 97'423 µs 97'423 µs -``` +Koffi Single Point Read 4'228 µs/iter (2'763 µs … 7'062 µs) 4'795 µs 6'234 µs 7'062 µs +N-API Single Point Read 4'223 µs/iter (2'745 µs … 6'530 µs) 4'777 µs 5'694 µs 6'530 µs +IPC Single Point Read 6'744 µs/iter (5'166 µs … 11'075 µs) 7'296 µs 11'075 µs 11'075 µs ## Summary of Manual Benchmark (Average of 5 Runs) | Wrapper | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff (Avg) | | :--- | :--- | :--- | :--- | :--- | :--- | -| **Koffi** | 13.83 ops/sec | 72.48 ms | 60.38 ms | 159.86 ms | 0.73 MB | -| **N-API** | 13.97 ops/sec | 71.81 ms | 59.34 ms | 267.20 ms | 0.55 MB | -| **IPC** | 13.24 ops/sec | 75.80 ms | 63.78 ms | 215.10 ms | 13.28 MB | +| **Koffi** | 247.50 ops/sec | 4.04 ms | 2.19 ms | 120.20 ms | 0.48 MB | +| **N-API** | 251.79 ops/sec | 3.97 ms | 2.08 ms | 114.84 ms | 0.29 MB | +| **IPC** | 178.48 ops/sec | 5.60 ms | 3.55 ms | 62.48 ms | 1.11 MB | ## Detailed Runs @@ -30,32 +24,32 @@ IPC Single Point Read 75'546 µs/iter (66'407 µs … 97'423 µs) 91'583 µs | Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -| Run 1 | 2026-04-13T06:26:00.195Z | 2026-04-13T06:26:35.666Z | 14.10 ops/sec | 70.94 ms | 60.02 ms | 369.14 ms | 0.68 MB | -| Run 2 | 2026-04-13T06:26:37.677Z | 2026-04-13T06:27:11.543Z | 14.76 ops/sec | 67.73 ms | 59.99 ms | 95.69 ms | 0.76 MB | -| Run 3 | 2026-04-13T06:27:13.556Z | 2026-04-13T06:27:51.062Z | 13.33 ops/sec | 75.01 ms | 61.05 ms | 108.63 ms | 0.72 MB | -| Run 4 | 2026-04-13T06:27:53.073Z | 2026-04-13T06:28:31.692Z | 12.95 ops/sec | 77.24 ms | 61.14 ms | 106.80 ms | 0.71 MB | -| Run 5 | 2026-04-13T06:28:33.703Z | 2026-04-13T06:29:09.433Z | 13.99 ops/sec | 71.46 ms | 59.70 ms | 119.04 ms | 0.78 MB | -| **Average** | - | - | 13.83 ops/sec | 72.48 ms | 60.38 ms | 159.86 ms | 0.73 MB | +| Run 1 | 2026-04-13T16:09:56.696Z | 2026-04-13T16:13:17.847Z | 248.57 ops/sec | 4.02 ms | 2.10 ms | 211.72 ms | 0.63 MB | +| Run 2 | 2026-04-13T16:13:19.850Z | 2026-04-13T16:16:39.698Z | 250.19 ops/sec | 4.00 ms | 2.21 ms | 50.32 ms | 0.60 MB | +| Run 3 | 2026-04-13T16:16:41.700Z | 2026-04-13T16:20:04.955Z | 246.00 ops/sec | 4.06 ms | 2.22 ms | 46.13 ms | 0.50 MB | +| Run 4 | 2026-04-13T16:20:06.957Z | 2026-04-13T16:23:30.452Z | 245.71 ops/sec | 4.07 ms | 2.23 ms | 83.57 ms | 0.59 MB | +| Run 5 | 2026-04-13T16:23:32.455Z | 2026-04-13T16:26:54.852Z | 247.04 ops/sec | 4.05 ms | 2.18 ms | 209.29 ms | 0.05 MB | +| **Average** | - | - | 247.50 ops/sec | 4.04 ms | 2.19 ms | 120.20 ms | 0.48 MB | ### N-API | Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -| Run 1 | 2026-04-13T06:30:09.445Z | 2026-04-13T06:30:45.556Z | 13.85 ops/sec | 72.22 ms | 59.20 ms | 633.28 ms | 0.56 MB | -| Run 2 | 2026-04-13T06:30:47.561Z | 2026-04-13T06:31:20.317Z | 15.26 ops/sec | 65.51 ms | 59.25 ms | 131.44 ms | 0.53 MB | -| Run 3 | 2026-04-13T06:31:22.329Z | 2026-04-13T06:31:57.787Z | 14.10 ops/sec | 70.92 ms | 58.95 ms | 129.25 ms | 0.56 MB | -| Run 4 | 2026-04-13T06:31:59.797Z | 2026-04-13T06:32:36.084Z | 13.78 ops/sec | 72.57 ms | 59.58 ms | 192.24 ms | 0.55 MB | -| Run 5 | 2026-04-13T06:32:38.096Z | 2026-04-13T06:33:17.018Z | 12.85 ops/sec | 77.84 ms | 59.74 ms | 249.79 ms | 0.55 MB | -| **Average** | - | - | 13.97 ops/sec | 71.81 ms | 59.34 ms | 267.20 ms | 0.55 MB | +| Run 1 | 2026-04-13T16:27:56.860Z | 2026-04-13T16:31:15.625Z | 251.55 ops/sec | 3.97 ms | 2.07 ms | 212.07 ms | -1.32 MB | +| Run 2 | 2026-04-13T16:31:17.628Z | 2026-04-13T16:34:37.128Z | 250.63 ops/sec | 3.99 ms | 2.07 ms | 211.28 ms | 0.60 MB | +| Run 3 | 2026-04-13T16:34:39.131Z | 2026-04-13T16:37:58.728Z | 250.50 ops/sec | 3.99 ms | 2.10 ms | 49.52 ms | -0.15 MB | +| Run 4 | 2026-04-13T16:38:00.729Z | 2026-04-13T16:41:19.177Z | 251.96 ops/sec | 3.97 ms | 2.10 ms | 48.44 ms | -0.19 MB | +| Run 5 | 2026-04-13T16:41:21.180Z | 2026-04-13T16:44:37.807Z | 254.29 ops/sec | 3.93 ms | 2.07 ms | 52.89 ms | 2.50 MB | +| **Average** | - | - | 251.79 ops/sec | 3.97 ms | 2.08 ms | 114.84 ms | 0.29 MB | ### IPC | Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -| Run 1 | 2026-04-13T06:34:17.030Z | 2026-04-13T06:34:58.429Z | 12.08 ops/sec | 82.80 ms | 63.94 ms | 608.08 ms | 8.40 MB | -| Run 2 | 2026-04-13T06:35:00.440Z | 2026-04-13T06:35:39.422Z | 12.83 ops/sec | 77.96 ms | 64.92 ms | 134.13 ms | 15.16 MB | -| Run 3 | 2026-04-13T06:35:41.437Z | 2026-04-13T06:36:17.121Z | 14.01 ops/sec | 71.37 ms | 62.60 ms | 112.61 ms | 15.49 MB | -| Run 4 | 2026-04-13T06:36:19.130Z | 2026-04-13T06:36:54.629Z | 14.09 ops/sec | 71.00 ms | 62.87 ms | 118.40 ms | 13.68 MB | -| Run 5 | 2026-04-13T06:36:56.642Z | 2026-04-13T06:37:34.589Z | 13.18 ops/sec | 75.89 ms | 64.54 ms | 102.27 ms | 13.66 MB | -| **Average** | - | - | 13.24 ops/sec | 75.80 ms | 63.78 ms | 215.10 ms | 13.28 MB | +| Run 1 | 2026-04-13T16:45:39.821Z | 2026-04-13T16:50:15.184Z | 181.58 ops/sec | 5.51 ms | 3.54 ms | 100.94 ms | 7.74 MB | +| Run 2 | 2026-04-13T16:50:17.187Z | 2026-04-13T16:54:54.569Z | 180.26 ops/sec | 5.55 ms | 3.56 ms | 53.70 ms | -0.07 MB | +| Run 3 | 2026-04-13T16:54:56.572Z | 2026-04-13T16:59:37.603Z | 177.92 ops/sec | 5.62 ms | 3.57 ms | 52.15 ms | -0.16 MB | +| Run 4 | 2026-04-13T16:59:39.606Z | 2026-04-13T17:04:22.795Z | 176.56 ops/sec | 5.66 ms | 3.57 ms | 55.32 ms | -5.46 MB | +| Run 5 | 2026-04-13T17:04:24.798Z | 2026-04-13T17:09:08.731Z | 176.10 ops/sec | 5.68 ms | 3.50 ms | 50.27 ms | 3.48 MB | +| **Average** | - | - | 178.48 ops/sec | 5.60 ms | 3.55 ms | 62.48 ms | 1.11 MB | diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/benchmark.js b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/benchmark.js index 05fd4cfe..de8b9add 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/benchmark.js +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/benchmark.js @@ -2,6 +2,12 @@ const { bench, run } = require('mitata'); const fs = require('fs'); const path = require('path'); +// Handle Ctrl+C to ensure the script stops immediately +process.on('SIGINT', () => { + console.log('\n[Benchmark] Interrupted by user. Exiting...'); + process.exit(1); +}); + // Helper to read DB name from any of the POC directories function getDbName() { const paths = [ @@ -63,10 +69,8 @@ async function measure(name, conn, executeMethod, iterations = 500, runs = 5, sl const runResults = []; for (let r = 0; r < runs; r++) { - if (r > 0) { - console.log(` Sleeping for ${sleepMs}ms to let DB cool down...`); - await new Promise(resolve => setTimeout(resolve, sleepMs)); - } + console.log(` Sleeping for ${sleepMs}ms to let DB cool down...`); + await new Promise(resolve => setTimeout(resolve, sleepMs)); console.log(` Run ${r + 1}/${runs}...`); if (global.gc) global.gc(); @@ -75,9 +79,8 @@ async function measure(name, conn, executeMethod, iterations = 500, runs = 5, sl const startMemory = process.memoryUsage().heapUsed; const startTime = performance.now(); - let min = Infinity; - let max = 0; let total = 0; + const samples = []; for (let i = 0; i < iterations; i++) { const opStart = performance.now(); @@ -87,8 +90,7 @@ async function measure(name, conn, executeMethod, iterations = 500, runs = 5, sl const opEnd = performance.now(); const opDiff = opEnd - opStart; - if (opDiff < min) min = opDiff; - if (opDiff > max) max = opDiff; + samples.push(opDiff); total += opDiff; } @@ -101,15 +103,21 @@ async function measure(name, conn, executeMethod, iterations = 500, runs = 5, sl const memoryUsed = (endMemory - startMemory) / 1024 / 1024; const avgLatency = total / iterations; + samples.sort((a, b) => a - b); + const p50 = samples[Math.floor(samples.length * 0.50)]; + const p90 = samples[Math.floor(samples.length * 0.90)]; + const p99 = samples[Math.floor(samples.length * 0.99)]; + console.log(` Throughput: ${opsPerSec.toFixed(2)} ops/sec`); - console.log(` Latency: Avg ${avgLatency.toFixed(2)} ms, Min ${min.toFixed(2)} ms, Max ${max.toFixed(2)} ms`); + console.log(` Latency: Avg ${avgLatency.toFixed(2)} ms, p50 ${p50.toFixed(2)} ms, p90 ${p90.toFixed(2)} ms, p99 ${p99.toFixed(2)} ms`); console.log(` Heap Diff: ${memoryUsed.toFixed(2)} MB`); runResults.push({ opsPerSec, avgLatency, - min, - max, + p50, + p90, + p99, memoryUsed, startTime: startTimeStr, endTime: endTimeStr @@ -119,14 +127,15 @@ async function measure(name, conn, executeMethod, iterations = 500, runs = 5, sl const avg = { opsPerSec: runResults.reduce((acc, r) => acc + r.opsPerSec, 0) / runs, avgLatency: runResults.reduce((acc, r) => acc + r.avgLatency, 0) / runs, - min: runResults.reduce((acc, r) => acc + r.min, 0) / runs, - max: runResults.reduce((acc, r) => acc + r.max, 0) / runs, + p50: runResults.reduce((acc, r) => acc + r.p50, 0) / runs, + p90: runResults.reduce((acc, r) => acc + r.p90, 0) / runs, + p99: runResults.reduce((acc, r) => acc + r.p99, 0) / runs, memoryUsed: runResults.reduce((acc, r) => acc + r.memoryUsed, 0) / runs }; console.log(`\n Average for ${name}:`); console.log(` Throughput: ${avg.opsPerSec.toFixed(2)} ops/sec`); - console.log(` Latency: Avg ${avg.avgLatency.toFixed(2)} ms, Min ${avg.min.toFixed(2)} ms, Max ${avg.max.toFixed(2)} ms`); + console.log(` Latency: Avg ${avg.avgLatency.toFixed(2)} ms, p50 ${avg.p50.toFixed(2)} ms, p90 ${avg.p90.toFixed(2)} ms, p99 ${avg.p99.toFixed(2)} ms`); console.log(` Heap Diff: ${avg.memoryUsed.toFixed(2)} MB`); return { runResults, avg }; @@ -213,17 +222,20 @@ async function runMitataBenchmark(connections) { }); } - const originalLog = console.log; + const originalWrite = process.stdout.write; let mitataOutput = ''; - console.log = (...args) => { - mitataOutput += args.join(' ') + '\n'; - originalLog.apply(console, args); + process.stdout.write = function(chunk, encoding, callback) { + mitataOutput += chunk.toString(); + return originalWrite.call(process.stdout, chunk, encoding, callback); }; await run(); - console.log = originalLog; - return mitataOutput; + process.stdout.write = originalWrite; + + // Strip ANSI escape codes (colors) from Mitata output + const stripAnsi = (str) => str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqrtvx-z]/g, ''); + return stripAnsi(mitataOutput); } /** @@ -239,10 +251,8 @@ async function runManualBenchmark(connections, iterations = 500) { if (connections.ipc) wrappers.push({ key: 'Ipc', name: 'IPC', conn: connections.ipc.conn, method: 'execute' }); for (let i = 0; i < wrappers.length; i++) { - if (i > 0) { - console.log(`\nSleeping for 1 minute before ${wrappers[i].name} to let DB cool down...`); - await new Promise(resolve => setTimeout(resolve, 60000)); - } + console.log(`\nSleeping for 1 minute before ${wrappers[i].name} to let DB cool down...`); + await new Promise(resolve => setTimeout(resolve, 60000)); const w = wrappers[i]; results[w.key] = await measure(w.name, w.conn, w.method, iterations); } @@ -258,25 +268,56 @@ function saveResults(mitataOutput, results, iterations) { let report = `# Benchmark Results\n\n`; report += `## Environment\n`; report += `- **Database**: \`${dbPath}\`\n\n`; + report += `**Action Benchmarked**: A Single Point Read operation involving executing a SQL query (\`SELECT ... WHERE SingerId = 1\`), reading the first result row, and closing the result stream.\n\n`; report += `## Mitata Latency Benchmark\n\n`; - report += `\`\`\`\n${mitataOutput}\`\`\`\n\n`; - report += `## Summary of Manual Benchmark (Average of 5 Runs)\n\n`; - report += `| Wrapper | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff (Avg) |\n`; + const lines = mitataOutput.split('\n'); + let cpuInfo = ''; + let runtimeInfo = ''; + const tableRows = []; + + for (const line of lines) { + if (line.startsWith('cpu:')) cpuInfo = line; + if (line.startsWith('runtime:')) runtimeInfo = line; + + if (line.includes('Single Point Read')) { + const match = line.match(/^(.+?)\s+([\d',]+ µs\/iter)\s+\(([\d',]+ µs … [\d',]+ µs)\)\s+([\d',]+ µs)\s+([\d',]+ µs)\s+([\d',]+ µs)$/); + if (match) { + const [, name, avg, minMax, p75, p99, p999] = match; + tableRows.push({ name: name.trim(), avg, minMax, p75, p99, p999 }); + } + } + } + + if (cpuInfo) report += `**${cpuInfo}**\n`; + if (runtimeInfo) report += `**${runtimeInfo}**\n\n`; + + report += `| Wrapper | Time (Avg) | Min … Max | p75 | p99 | p999 |\n`; report += `| :--- | :--- | :--- | :--- | :--- | :--- |\n`; + tableRows.forEach(row => { + const simpleName = row.name.replace(' Single Point Read', ''); + report += `| **${simpleName}** | ${row.avg} | ${row.minMax} | ${row.p75} | ${row.p99} | ${row.p999} |\n`; + }); + report += `\n`; + + report += `## Summary of Manual Benchmark (Average of 5 Runs)\n\n`; + report += `This table summarizes a manual benchmark designed to measure throughput and memory efficiency under sustained load.\n\n`; + report += `Each run consists of 50,000 iterations of this action. The table displays the average results across 5 independent runs for each wrapper.\n\n`; + report += `| Wrapper | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff (Avg) |\n`; + report += `| :--- | :--- | :--- | :--- | :--- | :--- | :--- |\n`; if (results.Koffi) { const avg = results.Koffi.avg; - report += `| **Koffi** | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.min.toFixed(2)} ms | ${avg.max.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n`; + report += `| **Koffi** | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.p50.toFixed(2)} ms | ${avg.p90.toFixed(2)} ms | ${avg.p99.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n`; } if (results.Napi) { const avg = results.Napi.avg; - report += `| **N-API** | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.min.toFixed(2)} ms | ${avg.max.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n`; + report += `| **N-API** | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.p50.toFixed(2)} ms | ${avg.p90.toFixed(2)} ms | ${avg.p99.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n`; } if (results.Ipc) { const avg = results.Ipc.avg; - report += `| **IPC** | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.min.toFixed(2)} ms | ${avg.max.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n`; + report += `| **IPC** | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.p50.toFixed(2)} ms | ${avg.p90.toFixed(2)} ms | ${avg.p99.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n`; } report += `\n## Detailed Runs\n\n`; @@ -284,13 +325,13 @@ function saveResults(mitataOutput, results, iterations) { function appendDetails(name, data) { if (!data) return; report += `### ${name}\n\n`; - report += `| Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff |\n`; - report += `| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |\n`; + report += `| Run | Start Time | End Time | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff |\n`; + report += `| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |\n`; data.runResults.forEach((r, i) => { - report += `| Run ${i + 1} | ${r.startTime} | ${r.endTime} | ${r.opsPerSec.toFixed(2)} ops/sec | ${r.avgLatency.toFixed(2)} ms | ${r.min.toFixed(2)} ms | ${r.max.toFixed(2)} ms | ${r.memoryUsed.toFixed(2)} MB |\n`; + report += `| Run ${i + 1} | ${r.startTime} | ${r.endTime} | ${r.opsPerSec.toFixed(2)} ops/sec | ${r.avgLatency.toFixed(2)} ms | ${r.p50.toFixed(2)} ms | ${r.p90.toFixed(2)} ms | ${r.p99.toFixed(2)} ms | ${r.memoryUsed.toFixed(2)} MB |\n`; }); const avg = data.avg; - report += `| **Average** | - | - | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.min.toFixed(2)} ms | ${avg.max.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n\n`; + report += `| **Average** | - | - | ${avg.opsPerSec.toFixed(2)} ops/sec | ${avg.avgLatency.toFixed(2)} ms | ${avg.p50.toFixed(2)} ms | ${avg.p90.toFixed(2)} ms | ${avg.p99.toFixed(2)} ms | ${avg.memoryUsed.toFixed(2)} MB |\n\n`; } appendDetails('Koffi', results.Koffi); @@ -306,7 +347,7 @@ async function main() { const mitataOutput = await runMitataBenchmark(connections); - const iterations = 500; + const iterations = 50000; const results = await runManualBenchmark(connections, iterations); saveResults(mitataOutput, results, iterations); From 213703cfe2b2564b2dccd65d88621458890b1ac2 Mon Sep 17 00:00:00 2001 From: surbhigarg92 Date: Fri, 17 Apr 2026 10:38:07 +0000 Subject: [PATCH 9/9] Benchmark run 2 --- .../benchmark/RESULTS.md | 78 +++++++++++-------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md index 9bbd4cd9..7ae68e49 100644 --- a/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md +++ b/spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md @@ -3,53 +3,63 @@ ## Environment - **Database**: `projects/span-cloud-testing/instances/gargsurbhi-testing/databases/test-db-koffi-136` +**Action Benchmarked**: A Single Point Read operation involving executing a SQL query (`SELECT ... WHERE SingerId = 1`), reading the first result row, and closing the result stream. + ## Mitata Latency Benchmark -benchmark time (avg) (min … max) p75 p99 p999 ---------------------------------------------------------------- ----------------------------- -Koffi Single Point Read 4'228 µs/iter (2'763 µs … 7'062 µs) 4'795 µs 6'234 µs 7'062 µs -N-API Single Point Read 4'223 µs/iter (2'745 µs … 6'530 µs) 4'777 µs 5'694 µs 6'530 µs -IPC Single Point Read 6'744 µs/iter (5'166 µs … 11'075 µs) 7'296 µs 11'075 µs 11'075 µs -## Summary of Manual Benchmark (Average of 5 Runs) +**cpu: Intel(R) Xeon(R) CPU @ 2.80GHz** +**runtime: node v22.22.2 (x64-linux)** -| Wrapper | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff (Avg) | +| Wrapper | Time (Avg) | Min … Max | p75 | p99 | p999 | | :--- | :--- | :--- | :--- | :--- | :--- | -| **Koffi** | 247.50 ops/sec | 4.04 ms | 2.19 ms | 120.20 ms | 0.48 MB | -| **N-API** | 251.79 ops/sec | 3.97 ms | 2.08 ms | 114.84 ms | 0.29 MB | -| **IPC** | 178.48 ops/sec | 5.60 ms | 3.55 ms | 62.48 ms | 1.11 MB | +| **Koffi** | 4'554 µs/iter | 2'985 µs … 6'313 µs | 5'295 µs | 6'288 µs | 6'313 µs | +| **N-API** | 4'608 µs/iter | 2'689 µs … 6'519 µs | 5'122 µs | 6'132 µs | 6'519 µs | +| **IPC** | 7'090 µs/iter | 4'831 µs … 11'449 µs | 8'010 µs | 11'449 µs | 11'449 µs | + +## Summary of Manual Benchmark (Average of 5 Runs) + +This table summarizes a manual benchmark designed to measure throughput and memory efficiency under sustained load. + +Each run consists of 50,000 iterations of this action. The table displays the average results across 5 independent runs for each wrapper. + +| Wrapper | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff (Avg) | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| **Koffi** | 230.82 ops/sec | 4.33 ms | 4.46 ms | 5.35 ms | 7.04 ms | 4.72 MB | +| **N-API** | 239.63 ops/sec | 4.17 ms | 4.30 ms | 5.23 ms | 6.62 ms | 4.06 MB | +| **IPC** | 171.31 ops/sec | 5.84 ms | 5.85 ms | 6.93 ms | 10.28 ms | 10.21 MB | ## Detailed Runs ### Koffi -| Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff | -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -| Run 1 | 2026-04-13T16:09:56.696Z | 2026-04-13T16:13:17.847Z | 248.57 ops/sec | 4.02 ms | 2.10 ms | 211.72 ms | 0.63 MB | -| Run 2 | 2026-04-13T16:13:19.850Z | 2026-04-13T16:16:39.698Z | 250.19 ops/sec | 4.00 ms | 2.21 ms | 50.32 ms | 0.60 MB | -| Run 3 | 2026-04-13T16:16:41.700Z | 2026-04-13T16:20:04.955Z | 246.00 ops/sec | 4.06 ms | 2.22 ms | 46.13 ms | 0.50 MB | -| Run 4 | 2026-04-13T16:20:06.957Z | 2026-04-13T16:23:30.452Z | 245.71 ops/sec | 4.07 ms | 2.23 ms | 83.57 ms | 0.59 MB | -| Run 5 | 2026-04-13T16:23:32.455Z | 2026-04-13T16:26:54.852Z | 247.04 ops/sec | 4.05 ms | 2.18 ms | 209.29 ms | 0.05 MB | -| **Average** | - | - | 247.50 ops/sec | 4.04 ms | 2.19 ms | 120.20 ms | 0.48 MB | +| Run | Start Time | End Time | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| Run 1 | 2026-04-17T09:05:36.744Z | 2026-04-17T09:09:15.783Z | 228.27 ops/sec | 4.38 ms | 4.50 ms | 5.39 ms | 7.35 ms | 2.63 MB | +| Run 2 | 2026-04-17T09:09:17.828Z | 2026-04-17T09:12:54.407Z | 230.86 ops/sec | 4.33 ms | 4.47 ms | 5.35 ms | 6.81 ms | 3.09 MB | +| Run 3 | 2026-04-17T09:12:56.451Z | 2026-04-17T09:16:31.826Z | 232.15 ops/sec | 4.31 ms | 4.44 ms | 5.31 ms | 6.82 ms | 6.09 MB | +| Run 4 | 2026-04-17T09:16:33.872Z | 2026-04-17T09:20:08.088Z | 233.41 ops/sec | 4.28 ms | 4.42 ms | 5.29 ms | 6.73 ms | 6.08 MB | +| Run 5 | 2026-04-17T09:20:10.133Z | 2026-04-17T09:23:48.067Z | 229.43 ops/sec | 4.36 ms | 4.47 ms | 5.38 ms | 7.47 ms | 5.71 MB | +| **Average** | - | - | 230.82 ops/sec | 4.33 ms | 4.46 ms | 5.35 ms | 7.04 ms | 4.72 MB | ### N-API -| Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff | -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -| Run 1 | 2026-04-13T16:27:56.860Z | 2026-04-13T16:31:15.625Z | 251.55 ops/sec | 3.97 ms | 2.07 ms | 212.07 ms | -1.32 MB | -| Run 2 | 2026-04-13T16:31:17.628Z | 2026-04-13T16:34:37.128Z | 250.63 ops/sec | 3.99 ms | 2.07 ms | 211.28 ms | 0.60 MB | -| Run 3 | 2026-04-13T16:34:39.131Z | 2026-04-13T16:37:58.728Z | 250.50 ops/sec | 3.99 ms | 2.10 ms | 49.52 ms | -0.15 MB | -| Run 4 | 2026-04-13T16:38:00.729Z | 2026-04-13T16:41:19.177Z | 251.96 ops/sec | 3.97 ms | 2.10 ms | 48.44 ms | -0.19 MB | -| Run 5 | 2026-04-13T16:41:21.180Z | 2026-04-13T16:44:37.807Z | 254.29 ops/sec | 3.93 ms | 2.07 ms | 52.89 ms | 2.50 MB | -| **Average** | - | - | 251.79 ops/sec | 3.97 ms | 2.08 ms | 114.84 ms | 0.29 MB | +| Run | Start Time | End Time | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| Run 1 | 2026-04-17T09:24:50.107Z | 2026-04-17T09:28:24.288Z | 233.45 ops/sec | 4.28 ms | 4.41 ms | 5.34 ms | 6.81 ms | 1.66 MB | +| Run 2 | 2026-04-17T09:28:26.330Z | 2026-04-17T09:31:56.971Z | 237.37 ops/sec | 4.21 ms | 4.35 ms | 5.24 ms | 6.47 ms | 2.83 MB | +| Run 3 | 2026-04-17T09:31:59.016Z | 2026-04-17T09:35:23.629Z | 244.36 ops/sec | 4.09 ms | 4.23 ms | 5.14 ms | 6.40 ms | 5.80 MB | +| Run 4 | 2026-04-17T09:35:25.673Z | 2026-04-17T09:38:53.506Z | 240.58 ops/sec | 4.16 ms | 4.26 ms | 5.22 ms | 6.84 ms | 5.21 MB | +| Run 5 | 2026-04-17T09:38:55.551Z | 2026-04-17T09:42:21.827Z | 242.39 ops/sec | 4.12 ms | 4.24 ms | 5.20 ms | 6.58 ms | 4.82 MB | +| **Average** | - | - | 239.63 ops/sec | 4.17 ms | 4.30 ms | 5.23 ms | 6.62 ms | 4.06 MB | ### IPC -| Run | Start Time | End Time | Throughput | Avg Latency | Min Latency | Max Latency | Heap Diff | -| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -| Run 1 | 2026-04-13T16:45:39.821Z | 2026-04-13T16:50:15.184Z | 181.58 ops/sec | 5.51 ms | 3.54 ms | 100.94 ms | 7.74 MB | -| Run 2 | 2026-04-13T16:50:17.187Z | 2026-04-13T16:54:54.569Z | 180.26 ops/sec | 5.55 ms | 3.56 ms | 53.70 ms | -0.07 MB | -| Run 3 | 2026-04-13T16:54:56.572Z | 2026-04-13T16:59:37.603Z | 177.92 ops/sec | 5.62 ms | 3.57 ms | 52.15 ms | -0.16 MB | -| Run 4 | 2026-04-13T16:59:39.606Z | 2026-04-13T17:04:22.795Z | 176.56 ops/sec | 5.66 ms | 3.57 ms | 55.32 ms | -5.46 MB | -| Run 5 | 2026-04-13T17:04:24.798Z | 2026-04-13T17:09:08.731Z | 176.10 ops/sec | 5.68 ms | 3.50 ms | 50.27 ms | 3.48 MB | -| **Average** | - | - | 178.48 ops/sec | 5.60 ms | 3.55 ms | 62.48 ms | 1.11 MB | +| Run | Start Time | End Time | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| Run 1 | 2026-04-17T09:43:23.923Z | 2026-04-17T09:48:16.443Z | 170.93 ops/sec | 5.85 ms | 5.85 ms | 6.94 ms | 10.36 ms | 13.09 MB | +| Run 2 | 2026-04-17T09:48:18.488Z | 2026-04-17T09:53:11.760Z | 170.49 ops/sec | 5.86 ms | 5.87 ms | 6.97 ms | 10.68 ms | 8.24 MB | +| Run 3 | 2026-04-17T09:53:13.800Z | 2026-04-17T09:58:03.738Z | 172.45 ops/sec | 5.80 ms | 5.82 ms | 6.89 ms | 10.28 ms | 6.35 MB | +| Run 4 | 2026-04-17T09:58:05.778Z | 2026-04-17T10:02:58.023Z | 171.09 ops/sec | 5.84 ms | 5.87 ms | 6.94 ms | 10.09 ms | 14.67 MB | +| Run 5 | 2026-04-17T10:03:00.069Z | 2026-04-17T10:07:51.418Z | 171.62 ops/sec | 5.83 ms | 5.84 ms | 6.89 ms | 9.97 ms | 8.72 MB | +| **Average** | - | - | 171.31 ops/sec | 5.84 ms | 5.85 ms | 6.93 ms | 10.28 ms | 10.21 MB |