From bbaf012efd74ad1e10c81716f2b99d7a8a334b88 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Fri, 16 Aug 2024 07:15:33 -0400 Subject: [PATCH] TensorFlow NodeJS / Kaioken demos --- docz/docs/03-demos/01-math/11-tensorflow.md | 322 +++++++++++++++--- .../03-demos/17-mobile/02-nativescript.md | 3 +- docz/static/tfjs/SheetJSTF.js | 68 ++++ docz/static/tfjs/SheetJSTF.tsx | 92 +++++ docz/static/tfjs/tf.min.js | 4 +- 5 files changed, 443 insertions(+), 46 deletions(-) create mode 100644 docz/static/tfjs/SheetJSTF.js create mode 100644 docz/static/tfjs/SheetJSTF.tsx diff --git a/docz/docs/03-demos/01-math/11-tensorflow.md b/docz/docs/03-demos/01-math/11-tensorflow.md index 43d0ab4..90afe7b 100644 --- a/docz/docs/03-demos/01-math/11-tensorflow.md +++ b/docz/docs/03-demos/01-math/11-tensorflow.md @@ -5,6 +5,11 @@ pagination_prev: demos/index pagination_next: demos/frontend/index --- +import current from '/version.js'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import CodeBlock from '@theme/CodeBlock'; + @@ -25,27 +30,151 @@ results back to spreadsheets. - ["JS Array Interchange"](#js-array-interchange) uses SheetJS to process sheets and generate rows of objects that can be post-processed. -:::info pass - -Live code blocks in this page use the TF.js `4.14.0` standalone build. - -For use in web frameworks, the `@tensorflow/tfjs` module should be used. - -For use in NodeJS, the native bindings module is `@tensorflow/tfjs-node`. - -::: - :::note Tested Deployments Each browser demo was tested in the following environments: | Browser | TF.js version | Date | |:------------|:--------------|:-----------| -| Chrome 122 | `4.14.0` | 2024-04-07 | -| Safari 17.4 | `4.14.0` | 2024-03-23 | +| Chrome 127 | `4.20.0` | 2024-08-16 | +| Safari 17.4 | `4.20.0` | 2024-08-16 | + +The NodeJS demo was tested in the following environments: + +| NodeJS | TF.js version | Date | +|:---------|:------------------------------|:-----------| +| `22.3.0` | `4.20.0` (`@tensorflow/tfjs`) | 2024-08-16 | + +The Kaioken demo was tested in the following environments: + +| Kaioken | TF.js version | Date | +|:----------|:--------------|:-----------| +| `0.25.3` | `4.20.0` | 2024-08-16 | ::: +## Installation + +#### Standalone Browser Scripts + +Live code blocks in this page use the TF.js `4.20.0` standalone build. + +Standalone scripts are available on various CDNs including UNPKG. The latest +version can be loaded with the following `SCRIPT` tag. + +The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone) +can be loaded after the TF.js standalone script. + +{`\ + + + +`} + + +#### Frameworks and Bundlers + +[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers +installation with Yarn and other package managers. + +`@tensorflow/tfjs` and SheetJS modules should be installed using a package manager: + + + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs`} + + + +{`\ +pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs`} + + + +{`\ +yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs`} + + +:::caution pass + +Newer releases of Yarn may throw an error: + +``` +Usage Error: It seems you are trying to add a package using a https:... url; we now require package names to be explicitly specified. +Try running the command again with the package name prefixed: yarn add my-package@https:... +``` + +The workaround is to prepend the URL with `xlsx@`: + +{`\ +yarn add xlsx@https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs`} + + +::: + + + + +#### NodeJS + +The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be +imported in NodeJS scripts that use TF.js. + +There are two options for NodeJS: + +- the pure JavaScript bindings module is `@tensorflow/tfjs` +- the native bindings module is `@tensorflow/tfjs-node` + +:::danger pass + +When this demo was last tested, there were issues with the native binding: + +``` +Error: The specified module could not be found. +\\?\C:\Users\SheetJS\node_modules\@tensorflow\tfjs-node\lib\napi-v8\tfjs_binding.node +``` + +For general compatibility, the demos use the pure `@tensorflow/tfjs` binding. + +::: + + + + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs @tensorflow/tfjs-node`} + + + +{`\ +pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs @tensorflow/tfjs-node`} + + + +{`\ +yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs @tensorflow/tfjs-node`} + + +:::caution pass + +Newer releases of Yarn may throw an error: + +``` +Usage Error: It seems you are trying to add a package using a https:... url; we now require package names to be explicitly specified. +Try running the command again with the package name prefixed: yarn add my-package@https:... +``` + +The workaround is to prepend the URL with `xlsx@`: + +{`\ +yarn add xlsx@https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs @tensorflow/tfjs-node`} + + +::: + + + + ## CSV Data Interchange `tf.data.csv`[^1] generates a Dataset from CSV data. The function expects a URL. @@ -126,6 +255,8 @@ The demo builds a model for predicting MPG from Horsepower data. It: - builds a model and trains with `fitDataset`[^8] - predicts MPG from a set of sample inputs and displays results in a table +#### Live Demo +
Live Demo (click to show) @@ -186,8 +317,8 @@ function SheetJSToTFJSCSV() { hasHeader: true, configuredColumnsOnly: true, columnConfigs:{ - "Horsepower": {required: false, default: 0}, - "Miles_per_Gallon":{required: false, default: 0, isLabel:true} + "Horsepower": { required: false, default: 0}, + "Miles_per_Gallon": { required: false, default: 0, isLabel: true } } }); @@ -234,6 +365,111 @@ function SheetJSToTFJSCSV() {
+#### NodeJS Demo + +0) Create a new project: + +```bash +mkdir sheetjs-tfjs-csv +cd sheetjs-tfjs-csv +npm init -y +``` + +1) Download [`SheetJSTF.js`](pathname:///tfjs/SheetJSTF.js): + +```bash +curl -LO https://docs.sheetjs.com/tfjs/SheetJSTF.js +``` + +2) Install SheetJS and TF.js dependencies: + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs @tensorflow/tfjs-node`} + + +3) Run the script: + +```bash +node SheetJSTF.js +``` + +#### Kaioken Demo + +:::tip pass + +[Kaioken](/docs/demos/frontend/kaioken) is a popular front-end framework that +uses patterns that will be familiar to ReactJS developers. + +The SheetJS team strongly recommends using Kaioken in projects using TF.js. + +::: + +1) Create a new site. + +```bash +npm create vite sheetjs-tfjs-kaioken -- --template vanilla-ts +cd sheetjs-tfjs-kaioken +npm add --save kaioken +npm add --save vite-plugin-kaioken -D +``` + +2) Create a new file `vite.config.ts` with the following content: + +```ts title="vite.config.ts (create new file)" +import { defineConfig } from "vite" +import kaioken from "vite-plugin-kaioken" + +export default defineConfig({ + plugins: [kaioken()], +}) +``` + +3) Edit `tsconfig.json` and add `"jsx": "preserve"` within `compilerOptions`: + +```js title="tsconfig.json (add highlighted line)" +{ + "compilerOptions": { +// highlight-next-line + "jsx": "preserve", +``` + +4) Replace `src/main.ts` with the following codeblock: + +```js title="src/main.ts" +import { mount } from "kaioken"; +import App from "./SheetJSTF"; + +const root = document.getElementById("app"); +mount(App, root!); +``` + +5) Download [`SheetJSTF.tsx`](pathname:///tfjs/SheetJSTF.tsx) to the `src` directory: + +```bash +curl -L -o src/SheetJSTF.tsx https://docs.sheetjs.com/tfjs/SheetJSTF.tsx +``` + +6) Install SheetJS and TF.js dependencies: + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs`} + + +7) Start the development server: + +```bash +npm run dev +``` + +The process will display a URL: + +``` + ➜ Local: http://localhost:5173/ +``` + +Open the displayed URL (`http://localhost:5173/` in this example) with a web +browser. Click the "Click to Run" button to see the results. + ## JS Array Interchange [The official Linear Regression tutorial](https://www.tensorflow.org/js/tutorials/training/linear_regression) @@ -306,7 +542,7 @@ The SheetJS `sheet_to_json` method[^10] will translate worksheet objects into an array of row objects: ```js -var aoo = [ +const aoo = [ {"sepal length": 5.1, "sepal width": 3.5, ...}, {"sepal length": 4.9, "sepal width": 3, ...}, ... @@ -316,18 +552,18 @@ var aoo = [ TF.js and other libraries tend to operate on individual columns, equivalent to: ```js -var sepal_lengths = [5.1, 4.9, ...]; -var sepal_widths = [3.5, 3, ...]; +const sepal_lengths = [5.1, 4.9, ...]; +const sepal_widths = [3.5, 3, ...]; ``` When a `tensor2d` can be exported, it will look different from the spreadsheet: ```js -var data_set_2d = [ +const data_set_2d = [ [5.1, 4.9, ...], [3.5, 3, ...], - ... -] + // ... +]; ``` This is the transpose of how people use spreadsheets! @@ -340,35 +576,35 @@ transposed. To export multiple data sets, the data should be transposed: ```js /* assuming data is an array of typed arrays */ -var aoa = []; -for(var i = 0; i < data.length; ++i) { - for(var j = 0; j < data[i].length; ++j) { +const aoa = []; +for(let i = 0; i < data.length; ++i) { + for(let j = 0; j < data[i].length; ++j) { if(!aoa[j]) aoa[j] = []; aoa[j][i] = data[i][j]; } } /* aoa can be directly converted to a worksheet object */ -var ws = XLSX.utils.aoa_to_sheet(aoa); +const ws = XLSX.utils.aoa_to_sheet(aoa); ``` ### Importing Data from a Spreadsheet -`sheet_to_json` with the option `header:1`[^12] will generate a row-major array +`sheet_to_json` with the option `header: 1`[^12] will generate a row-major array of arrays that can be transposed. However, it is more efficient to walk the sheet manually: ```js /* find worksheet range */ -var range = XLSX.utils.decode_range(ws['!ref']); -var out = [] +const range = XLSX.utils.decode_range(ws['!ref']); +const out = [] /* walk the columns */ -for(var C = range.s.c; C <= range.e.c; ++C) { +for(let C = range.s.c; C <= range.e.c; ++C) { /* create the typed array */ - var ta = new Float32Array(range.e.r - range.s.r + 1); + const ta = new Float32Array(range.e.r - range.s.r + 1); /* walk the rows */ - for(var R = range.s.r; R <= range.e.r; ++R) { + for(let R = range.s.r; R <= range.e.r; ++R) { /* find the cell, skip it if the cell isn't numeric or boolean */ - var cell = ws["!data"] ? (ws["!data"][R]||[])[C] : ws[XLSX.utils.encode_cell({r:R, c:C})]; + const cell = ws["!data"] ? (ws["!data"][R]||[])[C] : ws[XLSX.utils.encode_cell({r:R, c:C})]; if(!cell || cell.t != 'n' && cell.t != 'b') continue; /* assign to the typed array */ ta[R - range.s.r] = cell.v; @@ -393,38 +629,38 @@ const tensor = tf.tensor1d(lengths); `tf.Tensor` objects can be directly transposed using `transpose`: ```js -var aoo = XLSX.utils.sheet_to_json(worksheet); +const aoo = XLSX.utils.sheet_to_json(worksheet); // "x" and "y" are the fields we want to pull from the data -var data = aoo.map(row => ([row["x"], row["y"]])); +con st data = aoo.map(row => ([row["x"], row["y"]])); // create a tensor representing two column datasets -var tensor = tf.tensor2d(data).transpose(); +const tensor = tf.tensor2d(data).transpose(); // individual columns can be accessed -var col1 = tensor.slice([0,0], [1,tensor.shape[1]]).flatten(); -var col2 = tensor.slice([1,0], [1,tensor.shape[1]]).flatten(); +const col1 = tensor.slice([0,0], [1,tensor.shape[1]]).flatten(); +const col2 = tensor.slice([1,0], [1,tensor.shape[1]]).flatten(); ``` For exporting, `stack` can be used to collapse the columns into a linear array: ```js /* pull data into a Float32Array */ -var result = tf.stack([col1, col2]).transpose(); -var shape = tensor.shape; -var f32 = tensor.dataSync(); +const result = tf.stack([col1, col2]).transpose(); +const shape = tensor.shape; +const f32 = tensor.dataSync(); /* construct an array of arrays of the data in spreadsheet order */ -var aoa = []; -for(var j = 0; j < shape[0]; ++j) { +const aoa = []; +for(let j = 0; j < shape[0]; ++j) { aoa[j] = []; - for(var i = 0; i < shape[1]; ++i) aoa[j][i] = f32[j * shape[1] + i]; + for(let i = 0; i < shape[1]; ++i) aoa[j][i] = f32[j * shape[1] + i]; } /* add headers to the top */ aoa.unshift(["x", "y"]); /* generate worksheet */ -var worksheet = XLSX.utils.aoa_to_sheet(aoa); +const worksheet = XLSX.utils.aoa_to_sheet(aoa); ``` [^1]: See [`tf.data.csv`](https://js.tensorflow.org/api/latest/#data.csv) in the TensorFlow.js documentation diff --git a/docz/docs/03-demos/17-mobile/02-nativescript.md b/docz/docs/03-demos/17-mobile/02-nativescript.md index a801711..e1683e3 100644 --- a/docz/docs/03-demos/17-mobile/02-nativescript.md +++ b/docz/docs/03-demos/17-mobile/02-nativescript.md @@ -828,4 +828,5 @@ file named `SheetJSNS.xls`. [^4]: See [`write` in "Writing Files"](/docs/api/write-options) [^5]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input) [^6]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`. -[^7]: See [`read` in "Reading Files"](/docs/api/parse-options) \ No newline at end of file +[^7]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^8]: See ["Local setup"](https://docs.nativescript.org/setup/#local-setup) in the NativeScript documentation. For Windows and Linux, follow the "Android" instructions. For macOS, follow both the iOS and Android instructions. diff --git a/docz/static/tfjs/SheetJSTF.js b/docz/static/tfjs/SheetJSTF.js new file mode 100644 index 0000000..5b74795 --- /dev/null +++ b/docz/static/tfjs/SheetJSTF.js @@ -0,0 +1,68 @@ +const XLSX = require('xlsx'); +const tf = require("@tensorflow/tfjs"); +//const tf = require("@tensorflow/tfjs-node"); + +function worksheet_to_csv_url(worksheet) { + /* generate CSV */ + const csv = XLSX.utils.sheet_to_csv(worksheet); + + /* CSV -> Uint8Array -> Blob */ + const u8 = new TextEncoder().encode(csv); + const blob = new Blob([u8], { type: "text/csv" }); + + /* generate a blob URL */ + return URL.createObjectURL(blob); +} + +(async() => { try { + /* fetch file */ + const f = await fetch("https://docs.sheetjs.com/cd.xls"); + const ab = await f.arrayBuffer(); + /* parse file and get first worksheet */ + const wb = XLSX.read(ab); + const ws = wb.Sheets[wb.SheetNames[0]]; + + /* generate blob URL */ + const url = worksheet_to_csv_url(ws); + + /* feed to tf.js */ + const dataset = tf.data.csv(url, { + hasHeader: true, + configuredColumnsOnly: true, + columnConfigs:{ + "Horsepower": {required: false, default: 0}, + "Miles_per_Gallon":{required: false, default: 0, isLabel:true} + } + }); + + /* pre-process data */ + let flat = dataset + .map(({xs,ys}) =>({xs: Object.values(xs), ys: Object.values(ys)})) + .filter(({xs,ys}) => [...xs,...ys].every(v => v>0)); + + /* normalize manually :( */ + let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; + await flat.forEachAsync(({xs, ys}) => { + minX = Math.min(minX, xs[0]); maxX = Math.max(maxX, xs[0]); + minY = Math.min(minY, ys[0]); maxY = Math.max(maxY, ys[0]); + }); + flat = flat.map(({xs, ys}) => ({xs:xs.map(v => (v-minX)/(maxX - minX)),ys:ys.map(v => (v-minY)/(maxY-minY))})); + flat = flat.batch(32); + + /* build and train model */ + const model = tf.sequential(); + model.add(tf.layers.dense({inputShape: [1], units: 1})); + model.compile({ optimizer: tf.train.sgd(0.000001), loss: 'meanSquaredError' }); + await model.fitDataset(flat, { epochs: 100, callbacks: { onEpochEnd: async (epoch, logs) => { + console.error(`${epoch}:${logs.loss}`); + }}}); + + /* predict values */ + const inp = tf.linspace(0, 1, 9); + const pred = model.predict(inp); + const xs = await inp.dataSync(), ys = await pred.dataSync(); + + for (let i=0; i; + +export default function SheetJSToTFJSCSV() { + const [output, setOutput] = useState(""); + const [results, setResults] = useState<[number, number][]>([]); + const [disabled, setDisabled] = useState(false); + + function worksheet_to_csv_url(worksheet: WorkSheet) { + /* generate CSV */ + const csv = utils.sheet_to_csv(worksheet); + + /* CSV -> Uint8Array -> Blob */ + const u8 = new TextEncoder().encode(csv); + const blob = new Blob([u8], { type: "text/csv" }); + + /* generate a blob URL */ + return URL.createObjectURL(blob); + } + + const doit = useCallback(async () => { + setResults([]); setOutput(""); setDisabled(true); + try { + /* fetch file */ + const f = await fetch("https://docs.sheetjs.com/cd.xls"); + const ab = await f.arrayBuffer(); + /* parse file and get first worksheet */ + const wb = read(ab); + const ws = wb.Sheets[wb.SheetNames[0]]; + + /* generate blob URL */ + const url = worksheet_to_csv_url(ws); + + /* feed to tf.js */ + const dataset = data.csv(url, { + hasHeader: true, + configuredColumnsOnly: true, + columnConfigs:{ + "Horsepower": {required: false, default: 0}, + "Miles_per_Gallon":{required: false, default: 0, isLabel:true} + } + }); + + /* pre-process data */ + let flat = (dataset as unknown as DSet) + .map(({xs,ys}) =>({xs: Object.values(xs), ys: Object.values(ys)})) + .filter(({xs,ys}) => [...xs,...ys].every(v => v>0)); + + /* normalize manually :( */ + let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; + await flat.forEachAsync(({xs, ys}) => { + minX = Math.min(minX, xs[0]); maxX = Math.max(maxX, xs[0]); + minY = Math.min(minY, ys[0]); maxY = Math.max(maxY, ys[0]); + }); + flat = flat.map(({xs, ys}) => ({xs:xs.map(v => (v-minX)/(maxX - minX)),ys:ys.map(v => (v-minY)/(maxY-minY))})); + let batch = flat.batch(32); + + /* build and train model */ + const model = sequential(); + model.add(layers.dense({inputShape: [1], units: 1})); + model.compile({ optimizer: train.sgd(0.000001), loss: 'meanSquaredError' }); + await model.fitDataset(batch, { epochs: 100, callbacks: { onEpochEnd: async (epoch, logs) => { + setOutput(`${epoch}:${logs?.loss}`); + }}}); + + /* predict values */ + const inp = linspace(0, 1, 9); + const pred = model.predict(inp) as Tensor; + const xs = await inp.dataSync(), ys = await pred.dataSync(); + setResults(Array.from(xs).map((x, i) => [ x * (maxX - minX) + minX, ys[i] * (maxY - minY) + minY ])); + setOutput(""); + } catch(e) { setOutput(`ERROR: ${String(e)}`); } finally { setDisabled(false);} + }, []); + + return ( <> +
+ {output &&
{output}
|| <>} + {results.length && + {results.map((r,i) => )} +
HorsepowerMPG
{r[0]}{r[1].toFixed(2)}
|| <>} + ); +} diff --git a/docz/static/tfjs/tf.min.js b/docz/static/tfjs/tf.min.js index 00adab9..29e4008 100644 --- a/docz/static/tfjs/tf.min.js +++ b/docz/static/tfjs/tf.min.js @@ -1,6 +1,6 @@ /** * @license - * Copyright 2023 Google LLC. All Rights Reserved. + * Copyright 2024 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -14,5 +14,5 @@ * limitations under the License. * ============================================================================= */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).tf=e.tf||{})}(this,(function(e){"use strict";function t(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(n){if("default"!==n&&!(n in e)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}))})),e}var n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function r(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function a(e){var t,n;function r(t,n){try{var o=e[t](n),s=o.value,u=s instanceof i;Promise.resolve(u?s.v:s).then((function(n){if(u){var i="return"===t?"return":"next";if(!s.k||n.done)return r(i,n);n=e[i](n).value}a(o.done?"return":"normal",n)}),(function(e){r("throw",e)}))}catch(e){a("throw",e)}}function a(e,a){switch(e){case"return":t.resolve({value:a,done:!0});break;case"throw":t.reject(a);break;default:t.resolve({value:a,done:!1})}(t=t.next)?r(t.key,t.arg):n=null}this._invoke=function(e,a){return new Promise((function(i,o){var s={key:e,arg:a,resolve:i,reject:o,next:null};n?n=n.next=s:(t=n=s,r(e,a))}))},"function"!=typeof e.return&&(this.return=void 0)}function i(e,t){this.v=e,this.k=t}function o(){o=function(){return e};var e={},t=Object.prototype,n=t.hasOwnProperty,r=Object.defineProperty||function(e,t,n){e[t]=n.value},a="function"==typeof Symbol?Symbol:{},i=a.iterator||"@@iterator",s=a.asyncIterator||"@@asyncIterator",u=a.toStringTag||"@@toStringTag";function c(e,t,n){return Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}),e[t]}try{c({},"")}catch(e){c=function(e,t,n){return e[t]=n}}function l(e,t,n,a){var i=t&&t.prototype instanceof f?t:f,o=Object.create(i.prototype),s=new T(a||[]);return r(o,"_invoke",{value:w(e,n,s)}),o}function h(e,t,n){try{return{type:"normal",arg:e.call(t,n)}}catch(e){return{type:"throw",arg:e}}}e.wrap=l;var p={};function f(){}function d(){}function v(){}var m={};c(m,i,(function(){return this}));var g=Object.getPrototypeOf,y=g&&g(g(E([])));y&&y!==t&&n.call(y,i)&&(m=y);var b=v.prototype=f.prototype=Object.create(m);function x(e){["next","throw","return"].forEach((function(t){c(e,t,(function(e){return this._invoke(t,e)}))}))}function k(e,t){function a(r,i,o,s){var u=h(e[r],e,i);if("throw"!==u.type){var c=u.arg,l=c.value;return l&&"object"==typeof l&&n.call(l,"__await")?t.resolve(l.__await).then((function(e){a("next",e,o,s)}),(function(e){a("throw",e,o,s)})):t.resolve(l).then((function(e){c.value=e,o(c)}),(function(e){return a("throw",e,o,s)}))}s(u.arg)}var i;r(this,"_invoke",{value:function(e,n){function r(){return new t((function(t,r){a(e,n,t,r)}))}return i=i?i.then(r,r):r()}})}function w(e,t,n){var r="suspendedStart";return function(a,i){if("executing"===r)throw new Error("Generator is already running");if("completed"===r){if("throw"===a)throw i;return C()}for(n.method=a,n.arg=i;;){var o=n.delegate;if(o){var s=I(o,n);if(s){if(s===p)continue;return s}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if("suspendedStart"===r)throw r="completed",n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);r="executing";var u=h(e,t,n);if("normal"===u.type){if(r=n.done?"completed":"suspendedYield",u.arg===p)continue;return{value:u.arg,done:n.done}}"throw"===u.type&&(r="completed",n.method="throw",n.arg=u.arg)}}}function I(e,t){var n=t.method,r=e.iterator[n];if(void 0===r)return t.delegate=null,"throw"===n&&e.iterator.return&&(t.method="return",t.arg=void 0,I(e,t),"throw"===t.method)||"return"!==n&&(t.method="throw",t.arg=new TypeError("The iterator does not provide a '"+n+"' method")),p;var a=h(r,e.iterator,t.arg);if("throw"===a.type)return t.method="throw",t.arg=a.arg,t.delegate=null,p;var i=a.arg;return i?i.done?(t[e.resultName]=i.value,t.next=e.nextLoc,"return"!==t.method&&(t.method="next",t.arg=void 0),t.delegate=null,p):i:(t.method="throw",t.arg=new TypeError("iterator result is not an object"),t.delegate=null,p)}function N(e){var t={tryLoc:e[0]};1 in e&&(t.catchLoc=e[1]),2 in e&&(t.finallyLoc=e[2],t.afterLoc=e[3]),this.tryEntries.push(t)}function S(e){var t=e.completion||{};t.type="normal",delete t.arg,e.completion=t}function T(e){this.tryEntries=[{tryLoc:"root"}],e.forEach(N,this),this.reset(!0)}function E(e){if(e){var t=e[i];if(t)return t.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var r=-1,a=function t(){for(;++r=0;--a){var i=this.tryEntries[a],o=i.completion;if("root"===i.tryLoc)return r("end");if(i.tryLoc<=this.prev){var s=n.call(i,"catchLoc"),u=n.call(i,"finallyLoc");if(s&&u){if(this.prev=0;--r){var a=this.tryEntries[r];if(a.tryLoc<=this.prev&&n.call(a,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),S(n),p}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var r=n.completion;if("throw"===r.type){var a=r.arg;S(n)}return a}}throw new Error("illegal catch attempt")},delegateYield:function(e,t,n){return this.delegate={iterator:E(e),resultName:t,nextLoc:n},"next"===this.method&&(this.arg=void 0),p}},e}function s(e){return s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},s(e)}function u(e,t,n,r,a,i,o){try{var s=e[i](o),u=s.value}catch(e){return void n(e)}s.done?t(u):Promise.resolve(u).then(r,a)}function c(e){return function(){var t=this,n=arguments;return new Promise((function(r,a){var i=e.apply(t,n);function o(e){u(i,r,a,o,s,"next",e)}function s(e){u(i,r,a,o,s,"throw",e)}o(void 0)}))}}function l(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function h(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:a}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,o=!0,s=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return o=e.done,e},e:function(e){s=!0,i=e},f:function(){try{o||null==n.return||n.return()}finally{if(s)throw i}}}}function F(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:String(t)}a.prototype["function"==typeof Symbol&&Symbol.asyncIterator||"@@asyncIterator"]=function(){return this},a.prototype.next=function(e){return this._invoke("next",e)},a.prototype.throw=function(e){return this._invoke("throw",e)},a.prototype.return=function(e){return this._invoke("return",e)};var D,M,L=function(e){return e&&e.Math==Math&&e},z=L("object"==("undefined"==typeof globalThis?"undefined":s(globalThis))&&globalThis)||L("object"==("undefined"==typeof window?"undefined":s(window))&&window)||L("object"==("undefined"==typeof self?"undefined":s(self))&&self)||L("object"==s(n)&&n)||function(){return this}()||Function("return this")(),P={},B=function(e){try{return!!e()}catch(e){return!0}},W=!B((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),V=!B((function(){var e=function(){}.bind();return"function"!=typeof e||e.hasOwnProperty("prototype")})),U=V,G=Function.prototype.call,j=U?G.bind(G):function(){return G.apply(G,arguments)},H={},q={}.propertyIsEnumerable,K=Object.getOwnPropertyDescriptor,X=K&&!q.call({1:2},1),Y=(H.f=X?function(e){var t=K(this,e);return!!t&&t.enumerable}:q,function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}),J=V,Z=Function.prototype,Q=Z.call,$=J&&Z.bind.bind(Q,Q),ee=J?$:function(e){return function(){return Q.apply(e,arguments)}},te=ee,ne=te({}.toString),re=te("".slice),ae=function(e){return re(ne(e),8,-1)},ie=B,oe=ae,se=Object,ue=ee("".split),ce=ie((function(){return!se("z").propertyIsEnumerable(0)}))?function(e){return"String"==oe(e)?ue(e,""):se(e)}:se,le=function(e){return null==e},he=le,pe=TypeError,fe=function(e){if(he(e))throw pe("Can't call method on "+e);return e},de=ce,ve=fe,me=function(e){return de(ve(e))},ge="object"==("undefined"==typeof document?"undefined":s(document))&&document.all,ye={all:ge,IS_HTMLDDA:void 0===ge&&void 0!==ge},be=ye.all,xe=ye.IS_HTMLDDA?function(e){return"function"==typeof e||e===be}:function(e){return"function"==typeof e},ke=xe,we=ye.all,Ie=ye.IS_HTMLDDA?function(e){return"object"==s(e)?null!==e:ke(e)||e===we}:function(e){return"object"==s(e)?null!==e:ke(e)},Ne=z,Se=xe,Te=function(e){return Se(e)?e:void 0},Ee=function(e,t){return arguments.length<2?Te(Ne[e]):Ne[e]&&Ne[e][t]},Ce=ee({}.isPrototypeOf),Ae="undefined"!=typeof navigator&&String(navigator.userAgent)||"",Re=z,_e=Ae,Oe=Re.process,Fe=Re.Deno,De=Oe&&Oe.versions||Fe&&Fe.version,Me=De&&De.v8;Me&&(M=(D=Me.split("."))[0]>0&&D[0]<4?1:+(D[0]+D[1])),!M&&_e&&(!(D=_e.match(/Edge\/(\d+)/))||D[1]>=74)&&(D=_e.match(/Chrome\/(\d+)/))&&(M=+D[1]);var Le=M,ze=Le,Pe=B,Be=!!Object.getOwnPropertySymbols&&!Pe((function(){var e=Symbol();return!String(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&ze&&ze<41})),We=Be&&!Symbol.sham&&"symbol"==s(Symbol.iterator),Ve=Ee,Ue=xe,Ge=Ce,je=Object,He=We?function(e){return"symbol"==s(e)}:function(e){var t=Ve("Symbol");return Ue(t)&&Ge(t.prototype,je(e))},qe=String,Ke=function(e){try{return qe(e)}catch(e){return"Object"}},Xe=xe,Ye=Ke,Je=TypeError,Ze=function(e){if(Xe(e))return e;throw Je(Ye(e)+" is not a function")},Qe=Ze,$e=le,et=function(e,t){var n=e[t];return $e(n)?void 0:Qe(n)},tt=j,nt=xe,rt=Ie,at=TypeError,it=function(e,t){var n,r;if("string"===t&&nt(n=e.toString)&&!rt(r=tt(n,e)))return r;if(nt(n=e.valueOf)&&!rt(r=tt(n,e)))return r;if("string"!==t&&nt(n=e.toString)&&!rt(r=tt(n,e)))return r;throw at("Can't convert object to primitive value")},ot={exports:{}},st=!1,ut=z,ct=Object.defineProperty,lt=function(e,t){try{ct(ut,e,{value:t,configurable:!0,writable:!0})}catch(n){ut[e]=t}return t},ht=lt,pt="__core-js_shared__",ft=z[pt]||ht(pt,{}),dt=(ot.exports,ft);(ot.exports=function(e,t){return dt[e]||(dt[e]=void 0!==t?t:{})})("versions",[]).push({version:"3.29.1",mode:"global",copyright:"© 2014-2023 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.29.1/LICENSE",source:"https://github.com/zloirock/core-js"});var vt=ot.exports,mt=fe,gt=Object,yt=function(e){return gt(mt(e))},bt=yt,xt=ee({}.hasOwnProperty),kt=Object.hasOwn||function(e,t){return xt(bt(e),t)},wt=ee,It=0,Nt=Math.random(),St=wt(1..toString),Tt=function(e){return"Symbol("+(void 0===e?"":e)+")_"+St(++It+Nt,36)},Et=vt,Ct=kt,At=Tt,Rt=Be,_t=We,Ot=z.Symbol,Ft=Et("wks"),Dt=_t?Ot.for||Ot:Ot&&Ot.withoutSetter||At,Mt=function(e){return Ct(Ft,e)||(Ft[e]=Rt&&Ct(Ot,e)?Ot[e]:Dt("Symbol."+e)),Ft[e]},Lt=j,zt=Ie,Pt=He,Bt=et,Wt=it,Vt=TypeError,Ut=Mt("toPrimitive"),Gt=function(e,t){if(!zt(e)||Pt(e))return e;var n,r=Bt(e,Ut);if(r){if(void 0===t&&(t="default"),n=Lt(r,e,t),!zt(n)||Pt(n))return n;throw Vt("Can't convert object to primitive value")}return void 0===t&&(t="number"),Wt(e,t)},jt=Gt,Ht=He,qt=function(e){var t=jt(e,"string");return Ht(t)?t:t+""},Kt=Ie,Xt=z.document,Yt=Kt(Xt)&&Kt(Xt.createElement),Jt=function(e){return Yt?Xt.createElement(e):{}},Zt=Jt,Qt=!W&&!B((function(){return 7!=Object.defineProperty(Zt("div"),"a",{get:function(){return 7}}).a})),$t=W,en=j,tn=H,nn=Y,rn=me,an=qt,on=kt,sn=Qt,un=Object.getOwnPropertyDescriptor,cn=(P.f=$t?un:function(e,t){if(e=rn(e),t=an(t),sn)try{return un(e,t)}catch(e){}if(on(e,t))return nn(!en(tn.f,e,t),e[t])},{}),ln=W&&B((function(){return 42!=Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype})),hn=Ie,pn=String,fn=TypeError,dn=function(e){if(hn(e))return e;throw fn(pn(e)+" is not an object")},vn=W,mn=Qt,gn=ln,yn=dn,bn=qt,xn=TypeError,kn=Object.defineProperty,wn=Object.getOwnPropertyDescriptor,In="enumerable",Nn="configurable",Sn="writable",Tn=(cn.f=vn?gn?function(e,t,n){if(yn(e),t=bn(t),yn(n),"function"==typeof e&&"prototype"===t&&"value"in n&&Sn in n&&!n.writable){var r=wn(e,t);r&&r.writable&&(e[t]=n.value,n={configurable:Nn in n?n.configurable:r.configurable,enumerable:In in n?n.enumerable:r.enumerable,writable:!1})}return kn(e,t,n)}:kn:function(e,t,n){if(yn(e),t=bn(t),yn(n),mn)try{return kn(e,t,n)}catch(e){}if("get"in n||"set"in n)throw xn("Accessors not supported");return"value"in n&&(e[t]=n.value),e},cn),En=Y,Cn=W?function(e,t,n){return Tn.f(e,t,En(1,n))}:function(e,t,n){return e[t]=n,e},An={exports:{}},Rn=W,_n=kt,On=Function.prototype,Fn=Rn&&Object.getOwnPropertyDescriptor,Dn=_n(On,"name"),Mn={EXISTS:Dn,PROPER:Dn&&"something"===function(){}.name,CONFIGURABLE:Dn&&(!Rn||Rn&&Fn(On,"name").configurable)},Ln=xe,zn=ft,Pn=ee(Function.toString);Ln(zn.inspectSource)||(zn.inspectSource=function(e){return Pn(e)});var Bn,Wn,Vn,Un=zn.inspectSource,Gn=xe,jn=z.WeakMap,Hn=Gn(jn)&&/native code/.test(String(jn)),qn=Tt,Kn=vt("keys"),Xn=function(e){return Kn[e]||(Kn[e]=qn(e))},Yn={},Jn=Hn,Zn=z,Qn=Ie,$n=Cn,er=kt,tr=ft,nr=Xn,rr=Yn,ar="Object already initialized",ir=Zn.TypeError,or=Zn.WeakMap;if(Jn||tr.state){var sr=tr.state||(tr.state=new or);sr.get=sr.get,sr.has=sr.has,sr.set=sr.set,Bn=function(e,t){if(sr.has(e))throw ir(ar);return t.facade=e,sr.set(e,t),t},Wn=function(e){return sr.get(e)||{}},Vn=function(e){return sr.has(e)}}else{var ur=nr("state");rr[ur]=!0,Bn=function(e,t){if(er(e,ur))throw ir(ar);return t.facade=e,$n(e,ur,t),t},Wn=function(e){return er(e,ur)?e[ur]:{}},Vn=function(e){return er(e,ur)}}var cr={set:Bn,get:Wn,has:Vn,enforce:function(e){return Vn(e)?Wn(e):Bn(e,{})},getterFor:function(e){return function(t){var n;if(!Qn(t)||(n=Wn(t)).type!==e)throw ir("Incompatible receiver, "+e+" required");return n}}},lr=(An.exports,ee),hr=B,pr=xe,fr=kt,dr=W,vr=Mn.CONFIGURABLE,mr=Un,gr=cr.enforce,yr=cr.get,br=String,xr=Object.defineProperty,kr=lr("".slice),wr=lr("".replace),Ir=lr([].join),Nr=dr&&!hr((function(){return 8!==xr((function(){}),"length",{value:8}).length})),Sr=String(String).split("String"),Tr=An.exports=function(e,t,n){"Symbol("===kr(br(t),0,7)&&(t="["+wr(br(t),/^Symbol\(([^)]*)\)/,"$1")+"]"),n&&n.getter&&(t="get "+t),n&&n.setter&&(t="set "+t),(!fr(e,"name")||vr&&e.name!==t)&&(dr?xr(e,"name",{value:t,configurable:!0}):e.name=t),Nr&&n&&fr(n,"arity")&&e.length!==n.arity&&xr(e,"length",{value:n.arity});try{n&&fr(n,"constructor")&&n.constructor?dr&&xr(e,"prototype",{writable:!1}):e.prototype&&(e.prototype=void 0)}catch(e){}var r=gr(e);return fr(r,"source")||(r.source=Ir(Sr,"string"==typeof t?t:"")),e};Function.prototype.toString=Tr((function(){return pr(this)&&yr(this).source||mr(this)}),"toString");var Er=An.exports,Cr=xe,Ar=cn,Rr=Er,_r=lt,Or=function(e,t,n,r){r||(r={});var a=r.enumerable,i=void 0!==r.name?r.name:t;if(Cr(n)&&Rr(n,i,r),r.global)a?e[t]=n:_r(t,n);else{try{r.unsafe?e[t]&&(a=!0):delete e[t]}catch(e){}a?e[t]=n:Ar.f(e,t,{value:n,enumerable:!1,configurable:!r.nonConfigurable,writable:!r.nonWritable})}return e},Fr={},Dr=Math.ceil,Mr=Math.floor,Lr=Math.trunc||function(e){var t=+e;return(t>0?Mr:Dr)(t)},zr=Lr,Pr=function(e){var t=+e;return t!=t||0===t?0:zr(t)},Br=Pr,Wr=Math.max,Vr=Math.min,Ur=function(e,t){var n=Br(e);return n<0?Wr(n+t,0):Vr(n,t)},Gr=Pr,jr=Math.min,Hr=function(e){return e>0?jr(Gr(e),9007199254740991):0},qr=Hr,Kr=function(e){return qr(e.length)},Xr=me,Yr=Ur,Jr=Kr,Zr=function(e){return function(t,n,r){var a,i=Xr(t),o=Jr(i),s=Yr(r,o);if(e&&n!=n){for(;o>s;)if((a=i[s++])!=a)return!0}else for(;o>s;s++)if((e||s in i)&&i[s]===n)return e||s||0;return!e&&-1}},Qr={includes:Zr(!0),indexOf:Zr(!1)},$r=kt,ea=me,ta=Qr.indexOf,na=Yn,ra=ee([].push),aa=function(e,t){var n,r=ea(e),a=0,i=[];for(n in r)!$r(na,n)&&$r(r,n)&&ra(i,n);for(;t.length>a;)$r(r,n=t[a++])&&(~ta(i,n)||ra(i,n));return i},ia=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],oa=aa,sa=ia.concat("length","prototype"),ua=(Fr.f=Object.getOwnPropertyNames||function(e){return oa(e,sa)},{}),ca=(ua.f=Object.getOwnPropertySymbols,Ee),la=Fr,ha=ua,pa=dn,fa=ee([].concat),da=ca("Reflect","ownKeys")||function(e){var t=la.f(pa(e)),n=ha.f;return n?fa(t,n(e)):t},va=kt,ma=da,ga=P,ya=cn,ba=function(e,t,n){for(var r=ma(t),a=ya.f,i=ga.f,o=0;oo;)ni.f(e,n=a[o++],r[n]);return e},Ee("document","documentElement")),si=dn,ui=Ja,ci=ia,li=Yn,hi=oi,pi=Jt,fi=Xn("IE_PROTO"),di=function(){},vi=function(e){return"