From: Mathieu Baudier Date: Thu, 9 Nov 2023 11:20:40 +0000 (+0100) Subject: Merge tag 'v2.3.19' into testing X-Git-Tag: v2.1.29~3 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=6360b46535b91e4d94fa79d658c6f98ae88663f9;hp=c27369172d8f9724f73b0e6be692238931851211;p=gpl%2Fargeo-suite.git Merge tag 'v2.3.19' into testing --- diff --git a/.gitignore b/.gitignore index c769bb1..305a343 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ **/.DS_Store /sdk.mk /output/ +**/node_modules diff --git a/Makefile b/Makefile index d83a224..ad5bd8b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ include sdk.mk -.PHONY: clean all osgi +.PHONY: clean all osgi web -all: osgi +all: web osgi install: osgi-install @@ -13,14 +13,16 @@ BUNDLES = \ org.argeo.app.api \ org.argeo.app.core \ org.argeo.app.jcr \ +org.argeo.app.geo \ org.argeo.app.servlet.odk \ org.argeo.app.servlet.publish \ org.argeo.app.theme.default \ org.argeo.app.profile.acr.fs \ org.argeo.app.profile.acr.jcr \ +org.argeo.suite.knowledge \ swt/org.argeo.app.swt \ +swt/org.argeo.app.geo.swt \ swt/org.argeo.app.ui \ -org.argeo.suite.knowledge \ DEP_CATEGORIES = \ org.argeo.tp \ @@ -42,5 +44,13 @@ swt/rap/org.argeo.cms \ clean: rm -rf $(BUILD_BASE) + make -C js clean + +native-deps-debian: + sudo apt install npm + +## WEB +web: + make -C js all -include $(SDK_SRC_BASE)/sdk/argeo-build/osgi.mk \ No newline at end of file +include $(SDK_SRC_BASE)/sdk/argeo-build/osgi.mk diff --git a/NOTICE b/NOTICE index 583ff42..de09206 100644 --- a/NOTICE +++ b/NOTICE @@ -39,6 +39,27 @@ whether to do so. The GNU General Public License gives permission to release a modified version without this exception; this exception also makes it possible to release a modified version which carries forward this exception. +# Apache License Permission + +Linking Argeo Suite statically or dynamically with other modules is making a +combined work based on Argeo Suite. Thus, the terms and conditions of the GNU +General Public License cover the whole combination when this license becomes +applicable. + +In addition, as a special exception, the copyright holders of Argeo Suite give +you permission to combine Argeo Suite with any program released under the +terms and conditions of the Apache License v2.0 or any later version of this +license. You may copy and distribute such a system following the terms of +the GNU GPL for Argeo Suite and the licenses of the other code concerned, +provided that you include the source code of that other code when and as +the GNU GPL requires distribution of source code. + +Note that people who make modified versions of Argeo Suite are not obligated +to grant this special exception for their modified versions; it is their choice +whether to do so. The GNU General Public License gives permission to release a +modified version without this exception; this exception also makes it possible +to release a modified version which carries forward this exception. + # Java Content Repository API version 2.0 Permission Linking Argeo Suite statically or dynamically with other modules is making a diff --git a/js/.externalToolBuilders/npm run build.launch b/js/.externalToolBuilders/npm run build.launch new file mode 100644 index 0000000..c706fc1 --- /dev/null +++ b/js/.externalToolBuilders/npm run build.launch @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/js/.gitignore b/js/.gitignore new file mode 100644 index 0000000..cf1db2e --- /dev/null +++ b/js/.gitignore @@ -0,0 +1 @@ +/org/ diff --git a/js/.project b/js/.project new file mode 100644 index 0000000..07e0c1b --- /dev/null +++ b/js/.project @@ -0,0 +1,19 @@ + + + argeo-suite-js + + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + auto,full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/npm run build.launch + + + + + diff --git a/js/.settings/org.eclipse.core.resources.prefs b/js/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/js/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/js/.settings/org.eclipse.pde.core.prefs b/js/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000..f29e940 --- /dev/null +++ b/js/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/js/Makefile b/js/Makefile new file mode 100644 index 0000000..a43be73 --- /dev/null +++ b/js/Makefile @@ -0,0 +1,29 @@ +include ../sdk.mk + +A2_CATEGORY = org.argeo.suite + +BUNDLES = \ +org.argeo.app.js \ + +all: npm-ci webpack osgi + +webpack: + npm run build-prod + +webpack-dev: + npm run build + +clean: + $(foreach bundle, $(BUNDLES), rm -rf $(bundle)/org) + +npm-ci: + npm ci + +npm-install: + npm install + +jsdoc: + node_modules/.bin/jsdoc -r src \ + -d $(SDK_BUILD_BASE)/jsdoc/argeo-suite-js + +include $(SDK_SRC_BASE)/sdk/argeo-build/osgi.mk diff --git a/js/org.argeo.app.js/.gitignore b/js/org.argeo.app.js/.gitignore new file mode 100644 index 0000000..cf1db2e --- /dev/null +++ b/js/org.argeo.app.js/.gitignore @@ -0,0 +1 @@ +/org/ diff --git a/js/org.argeo.app.js/.project b/js/org.argeo.app.js/.project new file mode 100644 index 0000000..a2edfff --- /dev/null +++ b/js/org.argeo.app.js/.project @@ -0,0 +1,22 @@ + + + org.argeo.app.js + + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + + diff --git a/js/org.argeo.app.js/bnd.bnd b/js/org.argeo.app.js/bnd.bnd new file mode 100644 index 0000000..cac0263 --- /dev/null +++ b/js/org.argeo.app.js/bnd.bnd @@ -0,0 +1,6 @@ +Export-Package: \ +org.argeo.app.js,\ + + +Provide-Capability:\ +cms.publish;pkg=org.argeo.app.js;file="*.png,*.js,*.map,*.css,*.html",\ diff --git a/js/org.argeo.app.js/build.properties b/js/org.argeo.app.js/build.properties new file mode 100644 index 0000000..9b31242 --- /dev/null +++ b/js/org.argeo.app.js/build.properties @@ -0,0 +1,2 @@ +bin.includes = META-INF/,\ + org/ diff --git a/js/package-lock.json b/js/package-lock.json new file mode 100644 index 0000000..5d82b6a --- /dev/null +++ b/js/package-lock.json @@ -0,0 +1,6847 @@ +{ + "name": "org.argeo.app.js", + "version": "2.3.0.next", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "org.argeo.app.js", + "version": "2.3.0.next", + "license": "GPL", + "dependencies": { + "@nieuwlandgeo/sldreader": "0.3.x", + "chart.js": "4.x.x", + "chartjs-plugin-annotation": "^3.0.1", + "ol": "8.x.x" + }, + "devDependencies": { + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^5.0.1", + "html-webpack-plugin": "^5.5.3", + "jsdoc": "^4.0.2", + "mini-css-extract-plugin": "^2.7.6", + "npm-check-updates": "^16.13.2", + "style-loader": "^3.3.3", + "webpack": "^5.83.1", + "webpack-cli": "^5.1.1", + "webpack-merge": "^5.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "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/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsdoc/salty": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz", + "integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, + "node_modules/@nieuwlandgeo/sldreader": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nieuwlandgeo/sldreader/-/sldreader-0.3.1.tgz", + "integrity": "sha512-gP1dw7ftVT34L6nv8dDtERNIJYENwe2I37Vwdm3NQH+KKHDk7vwrTANxvgKgbNybMXHF29jvI97Z/bkZYBqdxQ==", + "peerDependencies": { + "ol": ">= 5.3.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "dev": true, + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", + "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@petamoriken/float16": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.8.4.tgz", + "integrity": "sha512-kB+NJ5Br56ZhElKsf0pM7/PQfrDdDVMRz8f0JM6eVOGE+L89z9hwcst9QvWBBnazzuqGTGtPsJNZoQ1JdNiGSQ==" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@sigstore/bundle": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", + "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", + "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", + "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "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, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tufjs/canonical-json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", + "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", + "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@types/eslint": { + "version": "8.44.3", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.3.tgz", + "integrity": "sha512-iM/WfkwAhwmPff3wZuPLYiHX18HI24jU8k1ZSH7P8FHwxTjZ2P6CoX2wnF43oprR+YXJM6UUxATkNvyv/JHd+g==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.5.tgz", + "integrity": "sha512-JNvhIEyxVW6EoMIFIvj93ZOywYFatlpu9deeH6eSx6PE3WHYvHaQtmHmQeNw7aA81bYGBPPQqdtBm6b1SsQMmA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", + "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", + "dev": true + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", + "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-gPQuzaPR5h/djlAv2apEG1HVOyj1IUs7GpfMZixU0/0KXT3pm64ylHuMUI1/Akh+sq/iikxg6Z2j+fcMDXaaTQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-kv43F9eb3Lhj+lr/Hn6OcLCs/sSM8bt+fIaP11rCYngfV6NVjzWXJ17owQtDQTL9tQ8WSLUrGsSJ6rJz0F1w1A==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "dev": true + }, + "node_modules/@types/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.3.tgz", + "integrity": "sha512-T5k6kTXak79gwmIOaDF2UUQXFbnBE0zBUzF20pz7wDYu0RQMzWg+Ml/Pz50214NsFHBITkoi5VtdjFZnJ2ijjA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz", + "integrity": "sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.28", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.28.tgz", + "integrity": "sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "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, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dev": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/boxen/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "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/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/cacache": { + "version": "17.1.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", + "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^7.7.1", + "minipass": "^7.0.3", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001546", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz", + "integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chart.js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.0.tgz", + "integrity": "sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=7" + } + }, + "node_modules/chartjs-plugin-annotation": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/chartjs-plugin-annotation/-/chartjs-plugin-annotation-3.0.1.tgz", + "integrity": "sha512-hlIrXXKqSDgb+ZjVYHefmlZUXK8KbkCPiynSVrTb/HjTMkT62cOInaT1NTQCKtxKKOm9oHp958DY3RTAFKtkHg==", + "peerDependencies": { + "chart.js": ">=4.0.0" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-css": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "dev": true, + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "cssnano": "^6.0.1", + "jest-worker": "^29.4.3", + "postcss": "^8.4.24", + "schema-utils": "^4.0.1", + "serialize-javascript": "^6.0.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", + "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", + "dev": true, + "dependencies": { + "cssnano-preset-default": "^6.0.1", + "lilconfig": "^2.1.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", + "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^4.0.0", + "postcss-calc": "^9.0.0", + "postcss-colormin": "^6.0.0", + "postcss-convert-values": "^6.0.0", + "postcss-discard-comments": "^6.0.0", + "postcss-discard-duplicates": "^6.0.0", + "postcss-discard-empty": "^6.0.0", + "postcss-discard-overridden": "^6.0.0", + "postcss-merge-longhand": "^6.0.0", + "postcss-merge-rules": "^6.0.1", + "postcss-minify-font-values": "^6.0.0", + "postcss-minify-gradients": "^6.0.0", + "postcss-minify-params": "^6.0.0", + "postcss-minify-selectors": "^6.0.0", + "postcss-normalize-charset": "^6.0.0", + "postcss-normalize-display-values": "^6.0.0", + "postcss-normalize-positions": "^6.0.0", + "postcss-normalize-repeat-style": "^6.0.0", + "postcss-normalize-string": "^6.0.0", + "postcss-normalize-timing-functions": "^6.0.0", + "postcss-normalize-unicode": "^6.0.0", + "postcss-normalize-url": "^6.0.0", + "postcss-normalize-whitespace": "^6.0.0", + "postcss-ordered-values": "^6.0.0", + "postcss-reduce-initial": "^6.0.0", + "postcss-reduce-transforms": "^6.0.0", + "postcss-svgo": "^6.0.0", + "postcss-unique-selectors": "^6.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", + "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.544", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.544.tgz", + "integrity": "sha512-54z7squS1FyFRSUqq/knOFSptjjogLZXbKcYk3B0qkE1KZzvqASwRZnY2KzZQJqIYLVD38XZeoiMRflYSwyO4w==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", + "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/es-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-memoize": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/fp-and-or": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/fp-and-or/-/fp-and-or-0.1.4.tgz", + "integrity": "sha512-+yRYRhpnFPWXSly/6V4Lw9IfOV26uu30kynGJ03PW+MnjOEQe45RZ141QcS0aJehYBYA50GfCDnsRbFJdhssRw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/geotiff": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.0.7.tgz", + "integrity": "sha512-FKvFTNowMU5K6lHYY2f83d4lS2rsCNdpUC28AX61x9ZzzqPNaWFElWv93xj0eJFaNyOYA63ic5OzJ88dHpoA5Q==", + "dependencies": { + "@petamoriken/float16": "^3.4.7", + "lerc": "^3.0.0", + "pako": "^2.0.4", + "parse-headers": "^2.0.2", + "quick-lru": "^6.1.1", + "web-worker": "^1.2.0", + "xml-utils": "^1.0.2" + }, + "engines": { + "node": ">=10.19" + } + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "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, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/http2-wrapper/node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", + "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", + "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-parse-helpfulerror": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", + "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==", + "dev": true, + "dependencies": { + "jju": "^1.1.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonlines": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsonlines/-/jsonlines-0.1.1.tgz", + "integrity": "sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==", + "dev": true + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dev": true, + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lerc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", + "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==" + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "dev": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, + "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 + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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, + "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, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-gyp": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", + "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^11.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/node-gyp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-check-updates": { + "version": "16.14.5", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.5.tgz", + "integrity": "sha512-f7v3YzPUgadtkB2LAVhiWMjrSejJ0N8OM9JjjVfxBz2neHqmPSWQUAUA+U/p3xeXHl9bghRD6knRqBhm9dkRGg==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "cli-table3": "^0.6.3", + "commander": "^10.0.1", + "fast-memoize": "^2.5.2", + "find-up": "5.0.0", + "fp-and-or": "^0.1.3", + "get-stdin": "^8.0.0", + "globby": "^11.0.4", + "hosted-git-info": "^5.1.0", + "ini": "^4.1.1", + "js-yaml": "^4.1.0", + "json-parse-helpfulerror": "^1.0.3", + "jsonlines": "^0.1.1", + "lodash": "^4.17.21", + "make-fetch-happen": "^11.1.1", + "minimatch": "^9.0.3", + "p-map": "^4.0.0", + "pacote": "15.2.0", + "parse-github-url": "^1.0.2", + "progress": "^2.0.3", + "prompts-ncu": "^3.0.0", + "rc-config-loader": "^4.1.3", + "remote-git-tags": "^3.0.0", + "rimraf": "^5.0.1", + "semver": "^7.5.4", + "semver-utils": "^1.1.4", + "source-map-support": "^0.5.21", + "spawn-please": "^2.0.1", + "strip-ansi": "^7.1.0", + "strip-json-comments": "^5.0.1", + "untildify": "^4.0.0", + "update-notifier": "^6.0.2" + }, + "bin": { + "ncu": "build/src/bin/cli.js", + "npm-check-updates": "build/src/bin/cli.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/npm-check-updates/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm-check-updates/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm-check-updates/node_modules/strip-json-comments": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", + "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz", + "integrity": "sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", + "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/ol": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/ol/-/ol-8.1.0.tgz", + "integrity": "sha512-cx3SH2plpFS9fM8pp1nCypgQXGJD7Mcb1E3mEySmy5XEw1DUEo+kkNzgtAZz5qupekqi7aU9iBJEjCoMfqvO2Q==", + "dependencies": { + "earcut": "^2.2.3", + "geotiff": "^2.0.7", + "pbf": "3.2.1", + "rbush": "^3.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/openlayers" + } + }, + "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, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dev": true, + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pacote": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", + "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", + "dev": true, + "dependencies": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^5.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.3.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parse-github-url": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", + "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", + "dev": true, + "bin": { + "parse-github-url": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pbf": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", + "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", + "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", + "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", + "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", + "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", + "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", + "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", + "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", + "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", + "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", + "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", + "dev": true, + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^4.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", + "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^4.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", + "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", + "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", + "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", + "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", + "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", + "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", + "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", + "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", + "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", + "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", + "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", + "dev": true, + "dependencies": { + "cssnano-utils": "^4.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", + "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", + "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", + "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.0.2" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", + "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prompts-ncu": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prompts-ncu/-/prompts-ncu-3.0.0.tgz", + "integrity": "sha512-qyz9UxZ5MlPKWVhWrCmSZ1ahm2GVYdjLb8og2sg0IPth1KRuhcggHGuijz0e41dkx35p1t1q3GRISGH7QGALFA==", + "dev": true, + "dependencies": { + "kleur": "^4.0.1", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "dev": true, + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz", + "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rbush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", + "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "dependencies": { + "quickselect": "^2.0.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc-config-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "js-yaml": "^4.1.0", + "json5": "^2.2.2", + "require-from-string": "^2.0.2" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-package-json": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remote-git-tags": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-3.0.0.tgz", + "integrity": "sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/renderkid/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/resolve": { + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "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" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-utils": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/semver-utils/-/semver-utils-1.1.4.tgz", + "integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA==", + "dev": true + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", + "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/sign": "^1.0.0", + "@sigstore/tuf": "^1.0.3", + "make-fetch-happen": "^11.0.1" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spawn-please": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-2.0.2.tgz", + "integrity": "sha512-KM8coezO6ISQ89c1BzyWNtcn2V2kAVtwIXd3cN/V5a0xPYc1F/vydrRc01wsKFEQ/p+V1a4sw4z2yMITIXrgGw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "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, + "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==", + "dev": true, + "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": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylehacks": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", + "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svgo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.2.1", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/svgo/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser": { + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz", + "integrity": "sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/tuf-js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", + "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", + "dev": true, + "dependencies": { + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "dev": true, + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.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==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/web-worker": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", + "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==" + }, + "node_modules/webpack": { + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", + "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "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/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "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/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 + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-utils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.7.0.tgz", + "integrity": "sha512-bWB489+RQQclC7A9OW8e5BzbT8Tu//jtAOvkYwewFr+Q9T9KDGvfzC1lp0pYPEQPEoPQLDkmxkepSC/2gIAZGw==" + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/js/package.json b/js/package.json new file mode 100644 index 0000000..4cef5e9 --- /dev/null +++ b/js/package.json @@ -0,0 +1,31 @@ +{ + "name": "org.argeo.app.js", + "version": "2.3.0.next", + "description": "", + "private": "true", + "scripts": { + "build": "webpack --config webpack.dev.js", + "build-prod": "webpack --config webpack.prod.js" + }, + "keywords": [], + "author": "", + "license": "GPL", + "devDependencies": { + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^5.0.1", + "html-webpack-plugin": "^5.5.3", + "jsdoc": "^4.0.2", + "mini-css-extract-plugin": "^2.7.6", + "npm-check-updates": "^16.13.2", + "style-loader": "^3.3.3", + "webpack": "^5.83.1", + "webpack-cli": "^5.1.1", + "webpack-merge": "^5.9.0" + }, + "dependencies": { + "@nieuwlandgeo/sldreader": "0.3.x", + "chart.js": "4.x.x", + "chartjs-plugin-annotation": "^3.0.1", + "ol": "8.x.x" + } +} diff --git a/js/src/chart/BarChart.js b/js/src/chart/BarChart.js new file mode 100644 index 0000000..d65b9cc --- /dev/null +++ b/js/src/chart/BarChart.js @@ -0,0 +1,27 @@ +import Chart from 'chart.js/auto'; + +import ChartJsPart from './ChartJsPart.js'; + +export default class BarChart extends ChartJsPart { + /** Constructor taking the mapName as an argument. */ + constructor(chartName) { + super(chartName); + this.setChart(new Chart(this.getChartCanvas(), { + type: 'bar', + data: { + datasets: [] + }, + options: { + scales: { + y: { + beginAtZero: true + }, + }, + animation: false, + } + })); + + } + + +} diff --git a/js/src/chart/ChartJsPart.js b/js/src/chart/ChartJsPart.js new file mode 100644 index 0000000..ac60ce3 --- /dev/null +++ b/js/src/chart/ChartJsPart.js @@ -0,0 +1,65 @@ +import ChartPart from './ChartPart.js'; + +import { Chart } from 'chart.js'; +import annotationPlugin from 'chartjs-plugin-annotation'; + +Chart.register(annotationPlugin); + +export default class ChartJsPart extends ChartPart { + #chart; + + /** Constructor taking the mapName as an argument. */ + constructor(chartName) { + super(chartName); + } + + setChart(chart) { + this.#chart = chart; + } + + getChart() { + return this.#chart; + } + + // + // DATA + // + setLabels(labels) { + const chart = this.getChart(); + chart.data.labels = labels; + this.update(); + } + + addDataset(label, data) { + const chart = this.getChart(); + chart.data.datasets.push({ + label: label, + data: data, + borderWidth: 1 + }); + this.update(); + } + + setData(labels, label, data) { + this.clearDatasets(); + this.setLabels(labels); + this.addDataset(label, data); + } + + setDatasets(labels, datasets) { + const chart = this.getChart(); + chart.data.datasets = datasets; + chart.data.labels = labels; + this.update(); + } + + clearDatasets() { + const chart = this.getChart(); + chart.data.datasets = []; + this.update(); + } + + update() { + this.#chart.update(); + } +} diff --git a/js/src/chart/ChartPart.js b/js/src/chart/ChartPart.js new file mode 100644 index 0000000..1fe9221 --- /dev/null +++ b/js/src/chart/ChartPart.js @@ -0,0 +1,34 @@ +/** API to be used by Java. + * @module MapPart + */ + +/** Abstract base class for displaying a map. */ +export default class ChartPart { + + /** The name of the chart, will also be the name of the variable */ + #chartName; + + constructor(chartName) { + this.#chartName = chartName; + this.createChartCanvas(this.#chartName); + } + + + // + // HTML + // + /** Create the div element where the chart will be displayed. */ + createChartCanvas(id) { + const chartDiv = document.createElement('canvas'); + chartDiv.id = id; + //chartDiv.style.cssText = 'width: 100%;'; + chartDiv.style.cssText = 'width: 100%; height: 100vh;'; + document.body.appendChild(chartDiv); + } + + /** Get the div element where the chart is displayed. */ + getChartCanvas() { + return document.getElementById(this.#chartName); + } + +} \ No newline at end of file diff --git a/js/src/chart/TestGraph.js b/js/src/chart/TestGraph.js new file mode 100644 index 0000000..9cc67db --- /dev/null +++ b/js/src/chart/TestGraph.js @@ -0,0 +1,27 @@ +import Chart from 'chart.js/auto'; + +export default class TestGraph { + + init() { + const ctx = document.getElementById('myChart'); + + new Chart(ctx, { + type: 'bar', + data: { + labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], + datasets: [{ + label: '# of Votes', + data: [12, 19, 3, 5, 2, 3], + borderWidth: 1 + }] + }, + options: { + scales: { + y: { + beginAtZero: true + } + } + } + }); + } +} diff --git a/js/src/chart/export-package.js b/js/src/chart/export-package.js new file mode 100644 index 0000000..5fbcc0a --- /dev/null +++ b/js/src/chart/export-package.js @@ -0,0 +1,21 @@ +import BarChart from './BarChart.js'; +import TestGraph from './TestGraph.js'; +//import { rectY, binX } from "@observablehq/plot"; + +// PSEUDO PACKAGE +if (typeof globalThis.argeo === 'undefined') + globalThis.argeo = {}; +if (typeof globalThis.argeo.app === 'undefined') + globalThis.argeo.app = {}; +if (typeof globalThis.argeo.app.chart === 'undefined') + globalThis.argeo.app.chart = {}; + +// PUBLIC CLASSES +globalThis.argeo.app.chart.BarChart = BarChart; +globalThis.argeo.app.chart.TestGraph = TestGraph; + +//const plot = rectY({ length: 10000 }, binX({ y: "count" }, { x: Math.random })).plot(); +//const div = document.querySelector("#myplot"); +//div.append(plot); + +"use strict"; diff --git a/js/src/chart/index.html b/js/src/chart/index.html new file mode 100644 index 0000000..72f6094 --- /dev/null +++ b/js/src/chart/index.html @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/js/src/chart/index.js b/js/src/chart/index.js new file mode 100644 index 0000000..6ff32b0 --- /dev/null +++ b/js/src/chart/index.js @@ -0,0 +1 @@ +import './export-package.js'; diff --git a/js/src/geo/BboxVectorSource.js b/js/src/geo/BboxVectorSource.js new file mode 100644 index 0000000..e1051b0 --- /dev/null +++ b/js/src/geo/BboxVectorSource.js @@ -0,0 +1,25 @@ + +import VectorSource from 'ol/source/Vector.js'; +import { bbox } from 'ol/loadingstrategy'; +import { transformToEpsg4326LatLonExtent } from './OpenLayersUtils.js'; + +export default class BboxVectorSource extends VectorSource { + constructor(options) { + super(BboxVectorSource.processOptions(options)); + } + + static processOptions(options) { + options.strategy = bbox; + options.url = function(extent, resolution, projection) { + var bbox = transformToEpsg4326LatLonExtent(extent, projection); + + const baseUrl = options.baseUrl; + // invert bbox order in order to have minLat,minLon,maxLat,maxLon as required by WFS 2.0.0 + const url = baseUrl + '&bbox=' + bbox.join(',') + ',EPSG:4326'; + return url; + } + return options; + } + + +} \ No newline at end of file diff --git a/js/src/geo/MapPart.js b/js/src/geo/MapPart.js new file mode 100644 index 0000000..b7fd086 --- /dev/null +++ b/js/src/geo/MapPart.js @@ -0,0 +1,62 @@ +/** API to be used by Java. + * @module MapPart + */ + +/** Abstract base class for displaying a map. */ +export default class MapPart { + + /** The name of the map, will also be the name of the variable */ + #mapName; + + constructor(mapName) { + this.#mapName = mapName; + this.createMapDiv(this.#mapName); + } + + // + // ABSTRACT METHODS + // + /** Set the center of the map to the given coordinates. */ + setCenter(lng, lat) { + throw new Error("Abstract method"); + } + + // + // EXTENSIONS + // + loadMapModule(url) { + var script = document.createElement("script"); + script.src = url; + document.head.appendChild(script); + // import(url) + // .then(module => { }) + // .catch((error) => 'An error occurred while loading the component'); + } + + // + // ACCESSORS + // + getMapName() { + return this.#mapName; + } + + // + // HTML + // + createMapDiv(id) { + var mapDiv = document.createElement('div'); + mapDiv.id = id; + mapDiv.className = this.getMapDivCssClass(); + mapDiv.style.cssText = 'width: 100%; height: 100vh;'; + document.body.appendChild(mapDiv); + } + + getMapDivCssClass() { + throw new Error("Abstract method"); + } + + newObject(js) { + const func = new Function(js); + return (func()); + } +} diff --git a/js/src/geo/OpenLayersMapPart.js b/js/src/geo/OpenLayersMapPart.js new file mode 100644 index 0000000..d033e30 --- /dev/null +++ b/js/src/geo/OpenLayersMapPart.js @@ -0,0 +1,303 @@ +/** OpenLayers-based implementation. + * @module OpenLayersMapPart + */ + +import { fromLonLat, getPointResolution } from 'ol/proj.js'; + +import TileLayer from 'ol/layer/Tile.js'; + +import OSM from 'ol/source/OSM.js'; +import { isEmpty } from 'ol/extent'; + +import Select from 'ol/interaction/Select.js'; +import Overlay from 'ol/Overlay.js'; + +import Map from 'ol/Map.js'; + +import { OverviewMap, ScaleLine, defaults as defaultControls } from 'ol/control.js'; +import { easeOut } from 'ol/easing'; + +import * as SLDReader from '@nieuwlandgeo/sldreader'; + +import MapPart from './MapPart.js'; +import { transformToOlLonLatExtent } from './OpenLayersUtils.js'; + +/** OpenLayers implementation of MapPart. */ +export default class OpenLayersMapPart extends MapPart { + /** The OpenLayers Map. */ + #map; + + /** The overview map */ + #overviewMap; + + /** Styled layer descriptor */ + #sld; + + /** The select interaction */ + select; + + /** Externally added callback functions. */ + callbacks = {}; + + /** Constructor taking the mapName as an argument. */ + constructor(mapName) { + super(mapName); + this.#overviewMap = new OverviewMap({ + layers: [ + new TileLayer({ + source: new OSM(), + }), + ], + }); + this.select = new Select(); + this.#map = new Map({ + controls: defaultControls({ + attribution: false, + rotate: false, + }).extend([this.#overviewMap, new ScaleLine({ + bar: false, + steps: 2, + text: false, + minWidth: 150, + maxWidth: 200, + })]), + layers: [ + ], + // view: new View({ + // projection: 'EPSG:4326', + // center: [0, 0], + // zoom: 2, + // }), + target: this.getMapName(), + }); + this.#map.addInteraction(this.select); + //this.#map.getView().set('projection', 'EPSG:4326', true); + } + + /* GEOGRAPHICAL METHODS */ + + setCenter(lat, lon) { + this.#map.getView().setCenter(fromLonLat([lon, lat])); + } + + fit(extent, options) { + var transformed = transformToOlLonLatExtent(extent, this.#map.getView().getProjection()); + this.#map.getView().fit(transformed, options); + } + + /** Accessors */ + getMap() { + return this.#map; + } + + getLayerByName(name) { + let layers = this.#map.getLayers(); + for (let i = 0; i < layers.getLength(); i++) { + let layer = layers.item(i); + let n = layer.get('name'); + if (n !== undefined) { + if (name === n) + return layer; + } + } + return undefined; + } + + /* CALLBACKS */ + enableFeatureSingleClick() { + // we cannot use 'this' in the function provided to OpenLayers + let mapPart = this; + this.#map.on('singleclick', function(e) { + let feature = null; + // we chose the first one + e.map.forEachFeatureAtPixel(e.pixel, function(f) { + feature = f; + return true; + }); + if (feature !== null) + mapPart.callbacks['onFeatureSingleClick'](feature.get('cr:path')); + }); + } + + enableFeatureSelected() { + // we cannot use 'this' in the function provided to OpenLayers + let mapPart = this; + var select = new Select(); + this.#map.addInteraction(select); + select.on('select', function(e) { + if (e.selected.length > 0) { + let feature = e.selected[0]; + mapPart.callbacks['onFeatureSelected'](feature.get('cr:path')); + } + }); + } + + enableFeaturePopup() { + // we cannot use 'this' in the function provided to OpenLayers + let mapPart = this; + /** + * Elements that make up the popup. + */ + const container = document.getElementById('popup'); + const content = document.getElementById('popup-content'); + const closer = document.getElementById('popup-closer'); + + /** + * Create an overlay to anchor the popup to the map. + */ + const overlay = new Overlay({ + element: container, + autoPan: false, + autoPanAnimation: { + duration: 250, + }, + }); + this.#map.addOverlay(overlay); + + let selected = null; + this.#map.on('pointermove', function(e) { + if (selected !== null) { + selected.setStyle(undefined); + selected = null; + } + + e.map.forEachFeatureAtPixel(e.pixel, function(f) { + selected = f; + return true; + }); + + if (selected == null) { + overlay.setPosition(undefined); + return; + } + const coordinate = e.coordinate; + const path = selected.get('cr:path'); + if (path === null) + return true; + const res = mapPart.callbacks['onFeaturePopup'](path); + if (res != null) { + content.innerHTML = res; + overlay.setPosition(coordinate); + } else { + overlay.setPosition(undefined); + } + }); + } + + selectFeatures(layerName, featureIds) { + // we cannot use 'this' in the function provided to OpenLayers + let mapPart = this; + this.select.getFeatures().clear(); + const layer = this.getLayerByName(layerName); + const source = layer.getSource(); + for (const featureId of featureIds) { + let feature = source.getFeatureById(featureId); + if (feature === null) { + source.on('featuresloadend', function(e) { + feature = source.getFeatureById(featureId); + if (feature !== null) + mapPart.select.getFeatures().push(feature); + }); + } else { + this.select.getFeatures().push(feature); + } + } + } + + fitToLayer(layerName) { + // we cannot use 'this' in the function provided to OpenLayers + let mapPart = this; + const layer = this.getLayerByName(layerName); + const source = layer.getSource(); + const extent = source.getExtent(); + const options = { + duration: 1000, + padding: [20, 20, 20, 20], + easing: easeOut, + }; + if (!isEmpty(extent)) + this.#map.getView().fit(source.getExtent(), options); + source.on('featuresloadend', function(e) { + mapPart.getMap().getView().fit(source.getExtent(), options); + }); + } + + // + // HTML + // + getMapDivCssClass() { + return 'map'; + } + + + // + // STATIC FOR EXTENSION + // + static newStyle(args) { + return new Style(args); + } + + static newIcon(args) { + return new Icon(args); + } + + // + // SLD STYLING + // + + setSld(xml) { + this.#sld = SLDReader.Reader(xml); + } + + /** Get a FeatureTypeStyle (https://nieuwlandgeo.github.io/SLDReader/api.html#FeatureTypeStyle). */ + getFeatureTypeStyle(styledLayerName, styleName) { + const sldLayer = SLDReader.getLayer(this.#sld, styledLayerName); + const style = styleName === undefined ? SLDReader.getStyle(sldLayer) : SLDReader.getStyle(sldLayer, styleName); + // OpenLayers can only use one definition + const featureTypeStyle = style.featuretypestyles[0]; + return featureTypeStyle; + } + + applyStyle(layerName, styledLayerName, styleName) { + const layer = this.getLayerByName(layerName); + const featureTypeStyle = this.getFeatureTypeStyle(styledLayerName, styleName); + const viewProjection = this.#map.getView().getProjection(); + const olStyleFunction = SLDReader.createOlStyleFunction(featureTypeStyle, { + // Use the convertResolution option to calculate a more accurate resolution. + convertResolution: viewResolution => { + const viewCenter = this.#map.getView().getCenter(); + return getPointResolution(viewProjection, viewResolution, viewCenter); + }, + // If you use point icons with an ExternalGraphic, you have to use imageLoadCallback + // to update the vector layer when an image finishes loading. + // If you do not do this, the image will only be visible after next layer pan/zoom. + imageLoadedCallback: () => { + layer.changed(); + }, + }); + layer.setStyle(olStyleFunction); + } + + #applySLD(vectorLayer, text) { + const sldObject = SLDReader.Reader(text); + const sldLayer = SLDReader.getLayer(sldObject); + const style = SLDReader.getStyle(sldLayer); + const featureTypeStyle = style.featuretypestyles[0]; + + const viewProjection = this.#map.getView().getProjection(); + const olStyleFunction = SLDReader.createOlStyleFunction(featureTypeStyle, { + // Use the convertResolution option to calculate a more accurate resolution. + convertResolution: viewResolution => { + const viewCenter = this.#map.getView().getCenter(); + return getPointResolution(viewProjection, viewResolution, viewCenter); + }, + // If you use point icons with an ExternalGraphic, you have to use imageLoadCallback + // to update the vector layer when an image finishes loading. + // If you do not do this, the image will only be visible after next layer pan/zoom. + imageLoadedCallback: () => { + vectorLayer.changed(); + }, + }); + vectorLayer.setStyle(olStyleFunction); + } +} diff --git a/js/src/geo/OpenLayersUtils.js b/js/src/geo/OpenLayersUtils.js new file mode 100644 index 0000000..b85ad7d --- /dev/null +++ b/js/src/geo/OpenLayersUtils.js @@ -0,0 +1,31 @@ +import { transformExtent } from 'ol/proj.js'; + + +export function transformToEpsg4326LatLonExtent(extent, projection) { + const proj = projection.getCode(); + if (proj === 'EPSG:4326') + return toLatLonExtent(extent); + var transformed = transformExtent(extent, proj, 'EPSG:4326'); + return toLatLonExtent(transformed); +} + +/** From EPSG:4326 lat/lon to a proj lon/lat */ +export function transformToOlLonLatExtent(extent, projection) { + const proj = projection.getCode(); + if (proj === 'EPSG:4326') + return toLonLatExtent(extent); + const reordered = toLonLatExtent(extent); + var transformed = transformExtent(reordered, 'EPSG:4326', proj); + return transformed; +} + +/** Converts from an extent in OpenLayers order (lon/lat) to WFS 2.0 order (lat/lon). */ +export function toLatLonExtent(extent) { + return [extent[1], extent[0], extent[3], extent[2]]; +} + +/** Converts from an extent in WFS 2.0 order (lat/lon) to OpenLayers order (lon/lat) . */ +export function toLonLatExtent(extent) { + return [extent[1], extent[0], extent[3], extent[2]]; +} + diff --git a/js/src/geo/SentinelCloudless.js b/js/src/geo/SentinelCloudless.js new file mode 100644 index 0000000..820a440 --- /dev/null +++ b/js/src/geo/SentinelCloudless.js @@ -0,0 +1,54 @@ + +import WMTS from 'ol/source/WMTS.js'; +import WMTSTileGrid from 'ol/tilegrid/WMTS'; +import { getTopLeft } from 'ol/extent'; +import { getWidth } from 'ol/extent'; +import { get as getProjection } from 'ol/proj'; + +export default class SentinelCloudless extends WMTS { + static source_s2CL2019; + static EPSG4326 = getProjection('EPSG:4326'); + + static resolutions; + static matrixIds; + + static { + let min_zoom = 6; + let max_zoom = 17; + let zoomOffset = 1; + + // from https://s2maps.eu/ + let size = getWidth(this.EPSG4326.getExtent()) / 512; + this.resolutions = new Array(max_zoom + zoomOffset); + this.matrixIds = new Array(max_zoom + zoomOffset); + for (let z = min_zoom; z <= max_zoom; ++z) { + // generate resolutions and matrixIds arrays for this WMTS + this.resolutions[z] = size / Math.pow(2, z); + this.matrixIds[z] = z; + } + } + + constructor() { + super({ + urls: [ + "//a.s2maps-tiles.eu/wmts/", + "//b.s2maps-tiles.eu/wmts/", + "//c.s2maps-tiles.eu/wmts/", + "//d.s2maps-tiles.eu/wmts/", + "//e.s2maps-tiles.eu/wmts/" + ], + layer: 's2cloudless-2021', + matrixSet: 'WGS84', + format: 'image/jpeg', + projection: SentinelCloudless.EPSG4326, + tileGrid: new WMTSTileGrid({ + origin: getTopLeft(SentinelCloudless.EPSG4326.getExtent()), + resolutions: SentinelCloudless.resolutions, + matrixIds: SentinelCloudless.matrixIds, + }), + style: 'default', + transition: 0, + wrapX: true + }); + } +} \ No newline at end of file diff --git a/js/src/geo/export-package.js b/js/src/geo/export-package.js new file mode 100644 index 0000000..50b9d04 --- /dev/null +++ b/js/src/geo/export-package.js @@ -0,0 +1,44 @@ +import OpenLayersMapPart from './OpenLayersMapPart.js'; +import BboxVectorSource from './BboxVectorSource.js'; +import SentinelCloudless from './SentinelCloudless.js'; + +import Map from 'ol/Map.js'; +import View from 'ol/View.js'; +import OSM from 'ol/source/OSM.js'; +import TileLayer from 'ol/layer/Tile.js'; +import VectorSource from 'ol/source/Vector.js'; +import VectorLayer from 'ol/layer/Vector.js'; +import GeoJSON from 'ol/format/GeoJSON.js'; +import { Style, Icon } from 'ol/style.js'; + +// PSEUDO PACKAGE +if (typeof globalThis.argeo === 'undefined') + globalThis.argeo = {}; +if (typeof globalThis.argeo.app === 'undefined') + globalThis.argeo.app = {}; +if (typeof globalThis.argeo.app.geo === 'undefined') + globalThis.argeo.app.geo = {}; + +// THIRD PARTY +if (typeof globalThis.argeo.tp === 'undefined') + globalThis.argeo.tp = {}; +if (typeof globalThis.argeo.tp.ol === 'undefined') + globalThis.argeo.tp.ol = {}; + +// PUBLIC CLASSES +globalThis.argeo.app.geo.OpenLayersMapPart = OpenLayersMapPart; +globalThis.argeo.app.geo.BboxVectorSource = BboxVectorSource; +globalThis.argeo.app.geo.SentinelCloudless = SentinelCloudless; + +globalThis.argeo.tp.ol.Map = Map; +globalThis.argeo.tp.ol.View = View; +globalThis.argeo.tp.ol.TileLayer = TileLayer; +globalThis.argeo.tp.ol.OSM = OSM; +globalThis.argeo.tp.ol.VectorSource = VectorSource; +globalThis.argeo.tp.ol.VectorLayer = VectorLayer; +globalThis.argeo.tp.ol.GeoJSON = GeoJSON; +globalThis.argeo.tp.ol.Style = Style; +globalThis.argeo.tp.ol.Icon = Icon; + +"use strict"; + diff --git a/js/src/geo/index.html b/js/src/geo/index.html new file mode 100644 index 0000000..bfc2233 --- /dev/null +++ b/js/src/geo/index.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/js/src/geo/index.js b/js/src/geo/index.js new file mode 100644 index 0000000..f389db0 --- /dev/null +++ b/js/src/geo/index.js @@ -0,0 +1,4 @@ +import './export-package.js'; + +// webpack specific +import 'ol/ol.css'; diff --git a/js/webpack.common.js b/js/webpack.common.js new file mode 100644 index 0000000..ba57965 --- /dev/null +++ b/js/webpack.common.js @@ -0,0 +1,61 @@ +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +//const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const path = require('path'); + +module.exports = { + entry: { + "geo": './src/geo/index.js', + "chart": './src/chart/index.js', + }, + output: { + filename: '[name].[contenthash].js', + path: path.resolve(__dirname, 'org.argeo.app.js/org/argeo/app/js'), + publicPath: '/pkg/org.argeo.app.js', + clean: true, + }, + optimization: { + moduleIds: 'deterministic', + runtimeChunk: 'single', + // split code + splitChunks: { + chunks: 'all', + }, + // minimizer: [ + // // For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line + // `...`, + // new CssMinimizerPlugin(), + // ], + }, + module: { + rules: [ + { + test: /\.(css)$/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + ], + }, + ], + }, + plugins: [ + // deal with CSS + new MiniCssExtractPlugin(), + // deal with HTML generation + new HtmlWebpackPlugin({ + title: 'Argeo Suite Geo JS', + template: 'src/geo/index.html', + scriptLoading: 'module', + filename: 'geo.html', + chunks: ['geo'], + }), + new HtmlWebpackPlugin({ + title: 'Argeo Suite Chart JS', + template: 'src/chart/index.html', + scriptLoading: 'module', + filename: 'chart.html', + chunks: ['chart'], + }), + + ], +}; \ No newline at end of file diff --git a/js/webpack.dev.js b/js/webpack.dev.js new file mode 100644 index 0000000..3d79473 --- /dev/null +++ b/js/webpack.dev.js @@ -0,0 +1,11 @@ +const { merge } = require('webpack-merge'); +const common = require('./webpack.common.js'); + +module.exports = merge(common, { + mode: 'development', + //devtool: 'source-map', // original code + devtool: 'eval-source-map', + devServer: { + static: './dist', + }, +}); \ No newline at end of file diff --git a/js/webpack.prod.js b/js/webpack.prod.js new file mode 100644 index 0000000..adb905a --- /dev/null +++ b/js/webpack.prod.js @@ -0,0 +1,7 @@ +const { merge } = require('webpack-merge'); +const common = require('./webpack.common.js'); + +module.exports = merge(common, { + mode: 'production', + devtool: 'source-map', // original code +}); \ No newline at end of file diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityConstants.java b/org.argeo.app.api/src/org/argeo/app/api/EntityConstants.java index c7885be..f04a6d0 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/EntityConstants.java +++ b/org.argeo.app.api/src/org/argeo/app/api/EntityConstants.java @@ -3,6 +3,6 @@ package org.argeo.app.api; /** Constant related to entities, typically used in an OSGi context. */ public interface EntityConstants { final static String TYPE = "entity.type"; - final static String DEFAULT_EDITOR_ID = "entity.defaultEditorId"; +// final static String DEFAULT_EDITOR_ID = "entity.defaultEditorId"; } diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityDefinition.java b/org.argeo.app.api/src/org/argeo/app/api/EntityDefinition.java index e1280cf..97f7d7c 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/EntityDefinition.java +++ b/org.argeo.app.api/src/org/argeo/app/api/EntityDefinition.java @@ -1,10 +1,8 @@ package org.argeo.app.api; -import javax.jcr.Node; - /** The definition of an entity, a composite configurable data structure. */ public interface EntityDefinition { - String getEditorId(Node entity); +// String getEditorId(Node entity); String getType(); } diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityName.java b/org.argeo.app.api/src/org/argeo/app/api/EntityName.java index 308f459..4330294 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/EntityName.java +++ b/org.argeo.app.api/src/org/argeo/app/api/EntityName.java @@ -2,8 +2,16 @@ package org.argeo.app.api; import org.argeo.api.acr.QNamed; +/** Names used in the entity namespace http://www.argeo.org/ns/entity. */ public enum EntityName implements QNamed { - type, // + type, relatedTo, // + // time, + date, + // geography + minLat, minLon, maxLat, maxLon, + // geo entities + place, + // ; @Override diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java b/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java index 5b0707e..b6240b3 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java +++ b/org.argeo.app.api/src/org/argeo/app/api/EntityNames.java @@ -18,16 +18,16 @@ public interface EntityNames { final String ADM = "adm"; @Deprecated - final String ENTITY_TYPE = "entity:type"; + final String ENTITY_TYPE = EntityName.type.get(); // GENERIC CONCEPTS // /** The language which is relevant. */ // final String XML_LANG = "xml:lang"; /** The date which is relevant. */ @Deprecated - final String ENTITY_DATE = "entity:date"; + final String ENTITY_DATE = EntityName.date.get(); @Deprecated - final String ENTITY_RELATED_TO = "entity:relatedTo"; + final String ENTITY_RELATED_TO = EntityName.relatedTo.get(); // DEFAULT FOLDER NAMES final String MEDIA = "media"; @@ -35,22 +35,22 @@ public interface EntityNames { // LDAP-LIKE ENTITIES @Deprecated - final String DISPLAY_NAME = LdapAttr.displayName.property(); + final String DISPLAY_NAME = LdapAttr.displayName.get(); // Persons @Deprecated - final String GIVEN_NAME = LdapAttr.givenName.property(); + final String GIVEN_NAME = LdapAttr.givenName.get(); @Deprecated - final String SURNAME = LdapAttr.sn.property(); + final String SURNAME = LdapAttr.sn.get(); @Deprecated - final String EMAIL = LdapAttr.mail.property(); + final String EMAIL = LdapAttr.mail.get(); @Deprecated - final String OU = LdapAttr.ou.property(); + final String OU = LdapAttr.ou.get(); // WGS84 @Deprecated final String GEO_LAT = WGS84PosName.lat.get(); @Deprecated - final String GEO_LONG = WGS84PosName.lng.get(); + final String GEO_LONG = WGS84PosName.lon.get(); @Deprecated final String GEO_ALT = WGS84PosName.alt.get(); diff --git a/org.argeo.app.api/src/org/argeo/app/api/EntityType.java b/org.argeo.app.api/src/org/argeo/app/api/EntityType.java index 1e30821..8a258eb 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/EntityType.java +++ b/org.argeo.app.api/src/org/argeo/app/api/EntityType.java @@ -2,7 +2,7 @@ package org.argeo.app.api; import org.argeo.api.acr.QNamed; -/** Types related to entities. */ +/** Types used in the entity namespace http://www.argeo.org/ns/entity. */ public enum EntityType implements QNamed { // entity entity, local, relatedTo, @@ -15,7 +15,7 @@ public enum EntityType implements QNamed { // graphics box, // geography - geopoint, bearing, + geopoint, bearing, geobounded, // ldap person, user; diff --git a/org.argeo.app.api/src/org/argeo/app/api/WGS84PosName.java b/org.argeo.app.api/src/org/argeo/app/api/WGS84PosName.java index 49de2d8..4ba1a13 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/WGS84PosName.java +++ b/org.argeo.app.api/src/org/argeo/app/api/WGS84PosName.java @@ -8,7 +8,7 @@ import org.argeo.api.acr.QNamed; * @see https://www.w3.org/2003/01/geo/ */ public enum WGS84PosName implements QNamed { - lat, lng("long"), alt; + lat, lon("long"), alt; private final String localName; diff --git a/org.argeo.app.api/src/org/argeo/app/api/entity.cnd b/org.argeo.app.api/src/org/argeo/app/api/entity.cnd index 396b6f2..9da2af7 100644 --- a/org.argeo.app.api/src/org/argeo/app/api/entity.cnd +++ b/org.argeo.app.api/src/org/argeo/app/api/entity.cnd @@ -115,3 +115,12 @@ mixin [entity:bearing] mixin - svg:direction (DOUBLE) + +[entity:geobounded] +mixin +- entity:minLat (DOUBLE) +- entity:minLon (DOUBLE) +- entity:maxLat (DOUBLE) +- entity:maxLon (DOUBLE) +- entity:minAlt (DOUBLE) +- entity:maxAlt (DOUBLE) diff --git a/org.argeo.app.api/src/org/argeo/app/api/entity.xsd b/org.argeo.app.api/src/org/argeo/app/api/entity.xsd new file mode 100644 index 0000000..a2fbfcd --- /dev/null +++ b/org.argeo.app.api/src/org/argeo/app/api/entity.xsd @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.app.api/src/org/argeo/app/api/entityFeature.xsd b/org.argeo.app.api/src/org/argeo/app/api/entityFeature.xsd new file mode 100644 index 0000000..805bd1a --- /dev/null +++ b/org.argeo.app.api/src/org/argeo/app/api/entityFeature.xsd @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.app.core/bnd.bnd b/org.argeo.app.core/bnd.bnd index c07e947..7671c88 100644 --- a/org.argeo.app.core/bnd.bnd +++ b/org.argeo.app.core/bnd.bnd @@ -5,9 +5,9 @@ OSGI-INF/suiteMaintenance.xml,\ OSGI-INF/termsContentProvider.xml,\ Import-Package:\ -tech.units.indriya.unit,\ +javax.measure.quantity,\ org.osgi.service.useradmin,\ -com.fasterxml.jackson.core,\ +tech.units.indriya.unit,\ org.argeo.cms.acr,\ * diff --git a/org.argeo.app.core/src/org/argeo/app/core/AbstractEntityDefinition.java b/org.argeo.app.core/src/org/argeo/app/core/AbstractEntityDefinition.java new file mode 100644 index 0000000..7e10bf0 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/core/AbstractEntityDefinition.java @@ -0,0 +1,14 @@ +package org.argeo.app.core; + +import org.argeo.app.api.EntityDefinition; + +public abstract class AbstractEntityDefinition implements EntityDefinition { + + public void init() { + + } + + public void destroy() { + + } +} diff --git a/org.argeo.app.core/src/org/argeo/app/core/SuiteContentNamespace.java b/org.argeo.app.core/src/org/argeo/app/core/SuiteContentNamespace.java index 48c508b..6b5ab3c 100644 --- a/org.argeo.app.core/src/org/argeo/app/core/SuiteContentNamespace.java +++ b/org.argeo.app.core/src/org/argeo/app/core/SuiteContentNamespace.java @@ -10,7 +10,7 @@ public enum SuiteContentNamespace implements ContentNamespace { // // ARGEO // - ENTITY("entity", "http://www.argeo.org/ns/entity", "entity.xsd", null), + ENTITY("entity", "http://www.argeo.org/ns/entity", "/org/argeo/app/api/entity.xsd", null), // ARGEO_DBK("argeodbk", "http://www.argeo.org/ns/argeodbk", null, null), // @@ -62,7 +62,10 @@ public enum SuiteContentNamespace implements ContentNamespace { Objects.requireNonNull(namespace); this.namespace = namespace; if (resourceFileName != null) { - resource = getClass().getResource(RESOURCE_BASE + resourceFileName); + if (!resourceFileName.startsWith("/")) + resource = getClass().getResource(RESOURCE_BASE + resourceFileName); + else + resource = getClass().getResource(resourceFileName); Objects.requireNonNull(resource); } if (publicUrl != null) diff --git a/org.argeo.app.core/src/org/argeo/app/core/schemas/entity.xsd b/org.argeo.app.core/src/org/argeo/app/core/schemas/entity.xsd deleted file mode 100644 index a2fbfcd..0000000 --- a/org.argeo.app.core/src/org/argeo/app/core/schemas/entity.xsd +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GeoJsonUtils.java b/org.argeo.app.core/src/org/argeo/app/geo/GeoJsonUtils.java deleted file mode 100644 index 84610c8..0000000 --- a/org.argeo.app.core/src/org/argeo/app/geo/GeoJsonUtils.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.argeo.app.geo; - -import java.util.Map; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -/** Geo data utilities. */ -public class GeoJsonUtils { - - /** Add these properties to all features. */ - public static void addProperties(JsonNode tree, Map map) { - for (JsonNode feature : tree.get("features")) { - ObjectNode properties = (ObjectNode) feature.get("properties"); - for (String key : map.keySet()) { - properties.put(key, map.get(key)); - } - } - } - - /** Singleton. */ - private GeoJsonUtils() { - } -} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GeoToSvg.java b/org.argeo.app.core/src/org/argeo/app/geo/GeoToSvg.java deleted file mode 100644 index abb5b39..0000000 --- a/org.argeo.app.core/src/org/argeo/app/geo/GeoToSvg.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.argeo.app.geo; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** Converts a geographical feature to an SVG. */ -public class GeoToSvg { - public void convertGeoJsonToSvg(Path source, Path target) { - ObjectMapper objectMapper = new ObjectMapper(); - try (InputStream in = Files.newInputStream(source); - Writer out = Files.newBufferedWriter(target, StandardCharsets.UTF_8)) { - JsonNode tree = objectMapper.readTree(in); - JsonNode coord = tree.get("features").get(0).get("geometry").get("coordinates"); - double ratio = 100; - double minX = Double.POSITIVE_INFINITY; - double maxX = Double.NEGATIVE_INFINITY; - double minY = Double.POSITIVE_INFINITY; - double maxY = Double.NEGATIVE_INFINITY; - List shapes = new ArrayList<>(); - for (JsonNode shape : coord) { - StringBuffer sb = new StringBuffer(); - sb.append(" maxY) - maxY = y; - double lng = latlng.get(1).asDouble(); - double x = lng * ratio; - if (x < minX) - minX = x; - if (x > maxX) - maxX = x; - sb.append(y + "," + x + " "); - } - sb.append("\">"); - sb.append("\n"); - shapes.add(sb.toString()); - } - - double width = maxX - minX; - double height = maxY - minY; - out.write("\n"); - for (String shape : shapes) { - out.write(shape); - out.write("\n"); - } - out.write(""); - } catch (IOException e) { - throw new RuntimeException("Cannot convert " + source + " to " + target, e); - } - } - -} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GeoToolsTest.java b/org.argeo.app.core/src/org/argeo/app/geo/GeoToolsTest.java deleted file mode 100644 index a771196..0000000 --- a/org.argeo.app.core/src/org/argeo/app/geo/GeoToolsTest.java +++ /dev/null @@ -1,221 +0,0 @@ -package org.argeo.app.geo; - -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStreamReader; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.geotools.data.DataUtilities; -import org.geotools.data.DefaultTransaction; -import org.geotools.data.Transaction; -import org.geotools.data.collection.ListFeatureCollection; -import org.geotools.data.shapefile.ShapefileDataStore; -import org.geotools.data.shapefile.ShapefileDataStoreFactory; -import org.geotools.data.simple.SimpleFeatureCollection; -import org.geotools.data.simple.SimpleFeatureSource; -import org.geotools.data.simple.SimpleFeatureStore; -import org.geotools.feature.simple.SimpleFeatureBuilder; -import org.geotools.geometry.jts.JTSFactoryFinder; -import org.geotools.swing.data.JFileDataStoreChooser; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.LineString; -import org.locationtech.jts.geom.Point; -import org.opengis.feature.simple.SimpleFeature; -import org.opengis.feature.simple.SimpleFeatureType; - -public class GeoToolsTest { - public GeoToolsTest() { - - } - - public void init() { - try { - main(null); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void destroy() { - - } - - public static void main(String[] args) throws Exception { - final SimpleFeatureType TYPE = DataUtilities.createType("Location", "the_geom:Point:srid=4326," + // <- the - // geometry - // attribute: - // Point - // type - "name:String," + // <- a String attribute - "number:Integer" // a number attribute - ); - final SimpleFeatureType TYPE_HULL = DataUtilities.createType("Hull", "the_geom:MultiPolygon:srid=4326"); - System.out.println("TYPE:" + TYPE); - - /* - * A list to collect features as we create them. - */ - List features = new ArrayList<>(); - List coordinates = new ArrayList<>(); - - /* - * GeometryFactory will be used to create the geometry attribute of each - * feature, using a Point object for the location. - */ - GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); - - SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE); - - try (BufferedReader reader = new BufferedReader( - new InputStreamReader(GeoToolsTest.class.getResourceAsStream("/org/djapps/on/apaf/locations.csv")))) { - /* First line of the data file is the header */ - String line = reader.readLine(); - System.out.println("Header: " + line); - - for (line = reader.readLine(); line != null; line = reader.readLine()) { - if (line.trim().length() > 0) { // skip blank lines - String[] tokens = line.split("\\,"); - - double latitude = Double.parseDouble(tokens[0]); - double longitude = Double.parseDouble(tokens[1]); - String name = tokens[2].trim(); - int number = Integer.parseInt(tokens[3].trim()); - - /* Longitude (= x coord) first ! */ - Coordinate coordinate = new Coordinate(longitude, latitude); - coordinates.add(coordinate); - Point point = geometryFactory.createPoint(coordinate); - - featureBuilder.add(point); - featureBuilder.add(name); - featureBuilder.add(number); - SimpleFeature feature = featureBuilder.buildFeature(null); - features.add(feature); - } - } - } - - LineString lineString = geometryFactory - .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); - Geometry convexHull = lineString.convexHull(); - System.out.println(convexHull.toText()); - SimpleFeatureBuilder hullFeatureBuilder = new SimpleFeatureBuilder(TYPE_HULL); - hullFeatureBuilder.add(convexHull); - SimpleFeature hull = hullFeatureBuilder.buildFeature(null); - - /* - * Get an output file name and create the new shapefile - */ - File newFile = getNewShapeFile(); - - ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory(); - - Map params = new HashMap<>(); - params.put("url", newFile.toURI().toURL()); - params.put("create spatial index", Boolean.TRUE); - - ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params); - - /* - * TYPE is used as a template to describe the file contents - */ - newDataStore.createSchema(TYPE_HULL); - - /* - * Write the features to the shapefile - */ - Transaction transaction = new DefaultTransaction("create"); - - String typeName = newDataStore.getTypeNames()[0]; - SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName); - SimpleFeatureType SHAPE_TYPE = featureSource.getSchema(); - /* - * The Shapefile format has a couple limitations: - "the_geom" is always first, - * and used for the geometry attribute name - "the_geom" must be of type Point, - * MultiPoint, MuiltiLineString, MultiPolygon - Attribute names are limited in - * length - Not all data types are supported (example Timestamp represented as - * Date) - * - * Each data store has different limitations so check the resulting - * SimpleFeatureType. - */ - System.out.println("SHAPE:" + SHAPE_TYPE); - - if (featureSource instanceof SimpleFeatureStore) { - SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; - /* - * SimpleFeatureStore has a method to add features from a - * SimpleFeatureCollection object, so we use the ListFeatureCollection class to - * wrap our list of features. - */ - SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, Collections.singletonList(hull)); - featureStore.setTransaction(transaction); - try { - featureStore.addFeatures(collection); - transaction.commit(); - } catch (Exception problem) { - problem.printStackTrace(); - transaction.rollback(); - } finally { - transaction.close(); - } - } else { - System.out.println(typeName + " does not support read/write access"); - } -// if (featureSource instanceof SimpleFeatureStore) { -// SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; -// /* -// * SimpleFeatureStore has a method to add features from a -// * SimpleFeatureCollection object, so we use the ListFeatureCollection class to -// * wrap our list of features. -// */ -// SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features); -// featureStore.setTransaction(transaction); -// try { -// featureStore.addFeatures(collection); -// transaction.commit(); -// } catch (Exception problem) { -// problem.printStackTrace(); -// transaction.rollback(); -// } finally { -// transaction.close(); -// } -// } else { -// System.out.println(typeName + " does not support read/write access"); -// } - } - - /** - * Prompt the user for the name and path to use for the output shapefile - * - * @param csvFile the input csv file used to create a default shapefile name - * @return name and path for the shapefile as a new File object - */ - private static File getNewShapeFile() { -// String path = csvFile.getAbsolutePath(); -// String newPath = path.substring(0, path.length() - 4) + ".shp"; - - JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp"); - chooser.setDialogTitle("Save shapefile"); -// chooser.setSelectedFile(new File(newPath)); - - int returnVal = chooser.showSaveDialog(null); - - if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) { - // the user cancelled the dialog - System.exit(0); - } - - File newFile = chooser.getSelectedFile(); - - return newFile; - } - -} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GeoUtils.java b/org.argeo.app.core/src/org/argeo/app/geo/GeoUtils.java deleted file mode 100644 index 1f8846d..0000000 --- a/org.argeo.app.core/src/org/argeo/app/geo/GeoUtils.java +++ /dev/null @@ -1,159 +0,0 @@ -package org.argeo.app.geo; - -import java.io.IOException; -import java.io.Serializable; -import java.io.Writer; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.measure.Quantity; -import javax.measure.quantity.Area; - -import org.geotools.data.DefaultTransaction; -import org.geotools.data.Transaction; -import org.geotools.data.collection.ListFeatureCollection; -import org.geotools.data.shapefile.ShapefileDataStore; -import org.geotools.data.shapefile.ShapefileDataStoreFactory; -import org.geotools.data.simple.SimpleFeatureCollection; -import org.geotools.data.simple.SimpleFeatureIterator; -import org.geotools.data.simple.SimpleFeatureSource; -import org.geotools.data.simple.SimpleFeatureStore; -import org.geotools.geometry.jts.JTS; -import org.geotools.referencing.CRS; -import org.geotools.referencing.crs.DefaultGeographicCRS; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.Point; -import org.locationtech.jts.geom.Polygon; -import org.opengis.feature.simple.SimpleFeature; -import org.opengis.feature.simple.SimpleFeatureType; -import org.opengis.geometry.MismatchedDimensionException; -import org.opengis.referencing.FactoryException; -import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.operation.MathTransform; -import org.opengis.referencing.operation.TransformException; - -import si.uom.SI; -import tech.units.indriya.quantity.Quantities; - -/** Utilities around geographical format, mostly wrapping GeoTools patterns. */ -public class GeoUtils { - - /** In square meters. */ - public static Quantity calcArea(SimpleFeature feature) { - try { - Polygon p = (Polygon) feature.getDefaultGeometry(); - Point centroid = p.getCentroid(); - String code = "AUTO:42001," + centroid.getX() + "," + centroid.getY(); - CoordinateReferenceSystem auto = CRS.decode(code); - - MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto); - - Polygon projed = (Polygon) JTS.transform(p, transform); - return Quantities.getQuantity(projed.getArea(), SI.SQUARE_METRE); - } catch (MismatchedDimensionException | FactoryException | TransformException e) { - throw new IllegalStateException("Cannot claculate area of feature"); - } - } - - public static void exportToSvg(SimpleFeatureCollection features, Writer out, int width, int height) { - try { - double minY = Double.POSITIVE_INFINITY; - double maxY = Double.NEGATIVE_INFINITY; - double minX = Double.POSITIVE_INFINITY; - double maxX = Double.NEGATIVE_INFINITY; - List shapes = new ArrayList<>(); - for (SimpleFeatureIterator it = features.features(); it.hasNext();) { - SimpleFeature feature = it.next(); - StringBuffer sb = new StringBuffer(); - sb.append(" maxX) - maxX = x; - double y = -coord.y; - if (y < minY) - minY = y; - if (y > maxY) - maxY = y; - sb.append(x + "," + y + " "); - } - sb.append("\">"); - sb.append("\n"); - shapes.add(sb.toString()); - - } - double viewportHeight = maxY - minY; - double viewportWidth = maxX - minX; - out.write("\n"); - for (String shape : shapes) { - out.write(shape); - out.write("\n"); - } - out.write(""); - } catch (IOException | FactoryException | MismatchedDimensionException | TransformException e) { - throw new RuntimeException("Cannot export to SVG", e); - } - } - - /** Write a list of simple features to a shapefile. */ - public static void saveFeaturesAsShapefile(SimpleFeatureType featureType, List features, - Path shpFile) { - try { - ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory(); - - Map params = new HashMap<>(); - params.put("url", shpFile.toUri().toURL()); - - params.put("create spatial index", Boolean.TRUE); - - ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params); - newDataStore.createSchema(featureType); - - String typeName = newDataStore.getTypeNames()[0]; - SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName); - if (featureSource instanceof SimpleFeatureStore) { - SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; - SimpleFeatureCollection collection = new ListFeatureCollection(featureType, features); - - try (Transaction transaction = new DefaultTransaction("create")) { - try { - featureStore.setTransaction(transaction); - featureStore.addFeatures(collection); - transaction.commit(); - } catch (Exception problem) { - transaction.rollback(); - throw new RuntimeException("Cannot write shapefile " + shpFile, problem); - } - } - } else { - throw new IllegalArgumentException(typeName + " does not support read/write access"); - } - } catch (IOException e) { - throw new RuntimeException("Cannot write shapefile " + shpFile, e); - } - } - - /** Singleton. */ - private GeoUtils() { - } -} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GmlAttr.java b/org.argeo.app.core/src/org/argeo/app/geo/GmlAttr.java deleted file mode 100644 index 77b0885..0000000 --- a/org.argeo.app.core/src/org/argeo/app/geo/GmlAttr.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.argeo.app.geo; - -import org.argeo.api.acr.QNamed; - -public enum GmlAttr implements QNamed { - uom - // - ; - - public final static String UOM_SQUARE_METERS = "m2"; - - @Override - public String getNamespace() { - return "http://www.opengis.net/gml/3.2"; - } - - @Override - public String getDefaultPrefix() { - return "gml"; - } - -} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GmlType.java b/org.argeo.app.core/src/org/argeo/app/geo/GmlType.java deleted file mode 100644 index 980a5e4..0000000 --- a/org.argeo.app.core/src/org/argeo/app/geo/GmlType.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.argeo.app.geo; - -import org.argeo.api.acr.QNamed; - -public enum GmlType implements QNamed { - measure - // - ; - - @Override - public String getNamespace() { - return "http://www.opengis.net/gml/3.2"; - } - - @Override - public String getDefaultPrefix() { - return "gml"; - } - -} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/GpxUtils.java b/org.argeo.app.core/src/org/argeo/app/geo/GpxUtils.java deleted file mode 100644 index 645b08b..0000000 --- a/org.argeo.app.core/src/org/argeo/app/geo/GpxUtils.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.argeo.app.geo; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.StringTokenizer; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.geotools.data.DataUtilities; -import org.geotools.feature.SchemaException; -import org.geotools.feature.simple.SimpleFeatureBuilder; -import org.geotools.geometry.jts.JTSFactoryFinder; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.Polygon; -import org.opengis.feature.simple.SimpleFeature; -import org.opengis.feature.simple.SimpleFeatureType; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -/** Utilities around the GPX format. */ -public class GpxUtils { - - public static SimpleFeature parseGpxToPolygon(InputStream in) throws IOException { - try { - final SimpleFeatureType TYPE = DataUtilities.createType("Area", "the_geom:Polygon:srid=4326"); - SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE); - - GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); - List coordinates = new ArrayList<>(); - SAXParserFactory factory = SAXParserFactory.newInstance(); - SAXParser saxParser = factory.newSAXParser(); - - saxParser.parse(in, new DefaultHandler() { - - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) - throws SAXException { - if ("trkpt".equals(qName)) { - Double latitude = Double.parseDouble(attributes.getValue("lat")); - Double longitude = Double.parseDouble(attributes.getValue("lon")); - Coordinate coordinate = new Coordinate(longitude, latitude); - coordinates.add(coordinate); - } - } - - }); - // close the line string - coordinates.add(coordinates.get(0)); - - Polygon polygon = geometryFactory.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); - featureBuilder.add(polygon); - SimpleFeature area = featureBuilder.buildFeature(null); - return area; - } catch (ParserConfigurationException | SAXException | SchemaException e) { - throw new RuntimeException("Cannot convert GPX", e); - } - } - - public static void writeGeoShapeAsGpx(String geoShape, OutputStream out) throws IOException { - Objects.requireNonNull(geoShape); - Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); - writer.append(""); - StringTokenizer stSeg = new StringTokenizer(geoShape.trim(), ";"); - while (stSeg.hasMoreTokens()) { - StringTokenizer stPt = new StringTokenizer(stSeg.nextToken().trim(), " "); - String lat = stPt.nextToken(); - String lng = stPt.nextToken(); - String alt = stPt.nextToken(); - // String precision = stPt.nextToken(); - writer.append("'); - writer.append("").append(alt).append(""); - writer.append(""); - } else { - writer.append("/>"); - } - } - writer.append(""); - writer.flush(); - } - - /** Singleton. */ - private GpxUtils() { - } -} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/geonames/GeonamesAdm.java b/org.argeo.app.core/src/org/argeo/app/geo/geonames/GeonamesAdm.java deleted file mode 100644 index 45febd2..0000000 --- a/org.argeo.app.core/src/org/argeo/app/geo/geonames/GeonamesAdm.java +++ /dev/null @@ -1,157 +0,0 @@ -package org.argeo.app.geo.geonames; - -import java.time.LocalDate; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -/** A Geonames administrative subdivision. */ -public class GeonamesAdm { - private final Long geonameId; - private final String countryCode; - private final String adminCode1; - private final String admLevel; - private final Integer level; - private final String name; - private final String asciiName; - private final List alternateNames; - private final Double lat; - private final Double lng; - private final LocalDate lastUpdated; - private final ZoneId timeZone; - - private final Long[] upperLevelIds = new Long[5]; - private final List upperLevels = new ArrayList<>(); - - private List row; - - /** Initialise from a row in the main Geonames table. */ - public GeonamesAdm(List row) { - geonameId = Long.parseLong(row.get(0)); - admLevel = row.get(7); - countryCode = row.get(8); - adminCode1 = row.get(10); - if (admLevel.startsWith("ADM")) { - if (admLevel.endsWith("H")) - level = Integer.parseInt(admLevel.substring(3, admLevel.length() - 1)); - else - level = Integer.parseInt(admLevel.substring(3)); - } else if (admLevel.equals("PCLI")) { - level = 0; - } else { - throw new IllegalArgumentException("Unsupported admin level " + admLevel); - } - name = row.get(1); - asciiName = row.get(2); - alternateNames = Arrays.asList(row.get(3).split(",")); - lat = Double.parseDouble(row.get(4)); - lng = Double.parseDouble(row.get(5)); - lastUpdated = LocalDate.parse(row.get(18)); - timeZone = ZoneId.of(row.get(17)); - // upper levels - if (row.get(11) != null && !row.get(11).trim().equals("")) - upperLevelIds[2] = Long.parseLong(row.get(11)); - if (row.get(12) != null && !row.get(12).trim().equals("")) - upperLevelIds[3] = Long.parseLong(row.get(12)); - if (row.get(13) != null && !row.get(13).trim().equals("")) - upperLevelIds[4] = Long.parseLong(row.get(13)); - this.row = row; - } - - public void mapUpperLevels(Map index) { - for (int i = 0; i < level; i++) { - Long geonameId = upperLevelIds[i]; - upperLevels.add(i, index.get(geonameId)); - } - } - - public Long getGeonameId() { - return geonameId; - } - - public Integer getLevel() { - return level; - } - - public String getName() { - return name; - } - - public String getName(Function transform) { - if (transform != null) - return transform.apply(name); - else - return name; - - } - - public String getAsciiName() { - return asciiName; - } - - public List getAlternateNames() { - return alternateNames; - } - - public Double getLat() { - return lat; - } - - public Double getLng() { - return lng; - } - - public String getCountryCode() { - return countryCode; - } - - public String getAdmLevel() { - return admLevel; - } - - public List getRow() { - return row; - } - - public LocalDate getLastUpdated() { - return lastUpdated; - } - - public ZoneId getTimeZone() { - return timeZone; - } - - public String getAdminCode1() { - return adminCode1; - } - - public Long[] getUpperLevelIds() { - return upperLevelIds; - } - - public List getUpperLevels() { - return upperLevels; - } - - @Override - public int hashCode() { - return geonameId.intValue(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof GeonamesAdm)) - return false; - GeonamesAdm other = (GeonamesAdm) obj; - return geonameId.equals(other.geonameId); - } - - @Override - public String toString() { - return name + " (ADM" + level + " " + geonameId + ")"; - } - -} diff --git a/org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java b/org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java deleted file mode 100644 index be2b507..0000000 --- a/org.argeo.app.core/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.argeo.app.geo.geonames; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.argeo.cms.util.CsvParser; -import org.argeo.cms.util.CsvWriter; - -/** Import GeoNames administrative division from the main table. */ -public class ImportGeonamesAdmin { - // private Log log = LogFactory.getLog(ImportGeonamesAdmin.class); - private Map geonamesAdms = new HashMap<>(); - - /** Loads the data. */ - public void parse(InputStream in) { - Map countryGeonameIds = new HashMap<>(); - Map admin1GeonameIds = new HashMap<>(); - CsvParser csvParser = new CsvParser() { - - @Override - protected void processLine(Integer lineNumber, List header, List tokens) { - if (!"A".equals(tokens.get(6))) - return; - GeonamesAdm geonamesAdm = new GeonamesAdm(tokens); - geonamesAdms.put(geonamesAdm.getGeonameId(), geonamesAdm); - if (geonamesAdm.getAdmLevel().equals("PCLI")) - countryGeonameIds.put(geonamesAdm.getCountryCode(), geonamesAdm.getGeonameId()); - if (geonamesAdm.getAdmLevel().equals("ADM1")) - admin1GeonameIds.put(geonamesAdm.getAdminCode1(), geonamesAdm.getGeonameId()); - } - }; - csvParser.setSeparator('\t'); - csvParser.setNoHeader(true); - csvParser.parse(in, StandardCharsets.UTF_8); - - // fill upper levels - for (GeonamesAdm adm : geonamesAdms.values()) { - adm.getUpperLevelIds()[0] = countryGeonameIds.get(adm.getCountryCode()); - if (adm.getLevel() > 0) - adm.getUpperLevelIds()[1] = admin1GeonameIds.get(adm.getAdminCode1()); - adm.mapUpperLevels(geonamesAdms); - } - - } - - public Map getGeonamesAdms() { - return geonamesAdms; - } - - /** - * Copies only the Geonames of feature class 'A' (administrative subdivisions). - */ - public static void filterGeonamesAdm(InputStream in, OutputStream out) { - CsvWriter csvWriter = new CsvWriter(out, StandardCharsets.UTF_8); - csvWriter.setSeparator('\t'); - CsvParser csvParser = new CsvParser() { - - @Override - protected void processLine(Integer lineNumber, List header, List tokens) { - if (tokens.size() < 7 || !"A".equals(tokens.get(6))) - return; - csvWriter.writeLine(tokens); - } - }; - csvParser.setSeparator('\t'); - csvParser.setNoHeader(true); - csvParser.parse(in, StandardCharsets.UTF_8); - } - - public static void main(String[] args) throws IOException { -// String country = "allCountries"; - String country = "CI"; -// try (InputStream in = Files -// .newInputStream(Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + ".txt")); -// OutputStream out = Files.newOutputStream( -// Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) { -// ImportGeonamesAdmin.filterGeonamesAdm(in, out); -// } - try (InputStream in = Files.newInputStream( - Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) { - ImportGeonamesAdmin importGeonamesAdmin = new ImportGeonamesAdmin(); - importGeonamesAdmin.parse(in); - } - } - -} diff --git a/org.argeo.app.core/src/org/argeo/app/ux/js/AbstractJsObject.java b/org.argeo.app.core/src/org/argeo/app/ux/js/AbstractJsObject.java new file mode 100644 index 0000000..3e13b68 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/ux/js/AbstractJsObject.java @@ -0,0 +1,114 @@ +package org.argeo.app.ux.js; + +import java.util.Optional; + +public abstract class AbstractJsObject { + /** + * JavaScript expression returning a reference to the object. It can be either a + * variable or a function call. If it is not set the object is assumed to be a + * new. + */ + private String reference; + + private JsClient jsClient; + + private Object[] jsConstructorArgs; + +// public AbstractJsObject(JsClient jsClient, String reference) { +// Objects.requireNonNull(jsClient); +// Objects.requireNonNull(reference, "JS reference cannot be null"); +// this.jsClient = jsClient; +// this.reference = reference; +// } + + public AbstractJsObject(Object... args) { + if (args.length == 2 && args[0] instanceof JsClient jsClient) { + this.jsClient = jsClient; + this.reference = args[1].toString(); + } else { + this.jsConstructorArgs = args; + } + } + + public abstract String getJsPackage(); + + public void create(JsClient jsClient, String varName) { + if (!isNew()) + throw new IllegalStateException("JS object " + getJsClassName() + " is not new"); + if (isFunctionReference()) + throw new IllegalStateException( + "JS object " + getJsClassName() + " cannot be created since it is a function reference"); + jsClient.execute(jsClient.getJsVarName(varName) + " = " + newJs() + ";"); + reference = varName; + this.jsClient = jsClient; + } + + public void delete() { + if (isNew()) + throw new IllegalStateException( + "JS object " + getJsClassName() + " cannot be deleted since it is anonymous"); + if (isFunctionReference()) + throw new IllegalStateException( + "JS object " + getJsClassName() + " cannot be deleted since it is a function reference"); + jsClient.execute(reference + " = undefined; delete " + reference + ";"); + } + + public boolean isNew() { + return reference == null; + } + + public boolean isFunctionReference() { + return !isNew() && !getReference().endsWith(")"); + } + + public String getReference() { + return reference; + } + + protected String getJsReference() { + return jsClient.getJsVarName(reference); + } + + protected String newJs() { + StringBuilder sb = new StringBuilder(); + sb.append("new "); + sb.append(getJsClassName()); + sb.append("("); + sb.append(JsClient.toJsArgs(jsConstructorArgs)); + sb.append(")"); + return sb.toString(); + } + + public String getJsClassName() { + return getJsPackage() + "." + getClass().getSimpleName(); + } + + public Object callMethod(String methodName, Object... args) { + return jsClient.callMethod(getJsReference(), methodName + "(" + JsClient.toJsArgs(args) + ")"); + } + + public void executeMethod(String methodName, Object... args) { + jsClient.executeMethod(getJsReference(), methodName + "(" + JsClient.toJsArgs(args) + ")"); + } + + protected String getMethodName() { + StackWalker walker = StackWalker.getInstance(); + Optional methodName = walker.walk(frames -> { + return frames.skip(1).findFirst().map(StackWalker.StackFrame::getMethodName); + }); + return methodName.orElseThrow(); + } + + protected JsClient getJsClient() { + return jsClient; + } + + protected Object[] getJsConstructorArgs() { + return jsConstructorArgs; + } + + protected void setJsConstructorArgs(Object[] jsConstructorArgs) { + this.jsConstructorArgs = jsConstructorArgs; + } + +} diff --git a/org.argeo.app.core/src/org/argeo/app/ux/js/JsClient.java b/org.argeo.app.core/src/org/argeo/app/ux/js/JsClient.java new file mode 100644 index 0000000..2503cf0 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/ux/js/JsClient.java @@ -0,0 +1,148 @@ +package org.argeo.app.ux.js; + +import java.util.Arrays; +import java.util.Locale; +import java.util.Map; +import java.util.StringJoiner; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + +/** + * A remote JavaScript view (typically in a web browser) which is tightly + * integrated with a local UX part. + */ +public interface JsClient { + + /* + * TO IMPLEMENT + */ + + /** + * Execute this JavaScript on the client side after making sure that the page + * has been loaded and the map object has been created. + * + * @param js the JavaScript code, possibly formatted according to + * {@link String#format}, with {@link Locale#ROOT} as locale (for + * stability of decimal separator, as expected by JavaScript. + * @param args the optional arguments of + * {@link String#format(String, Object...)} + */ + Object evaluate(String js, Object... args); + + /** + * Executes this JavaScript without expecting a return value. + * + * @param js the JavaScript code, possibly formatted according to + * {@link String#format}, with {@link Locale#ROOT} as locale (for + * stability of decimal separator, as expected by JavaScript. + * @param args the optional arguments of + * {@link String#format(String, Object...)} + */ + void execute(String js, Object... args); + + /** @return the globally usable function name. */ + String createJsFunction(String name, Function toDo); + + /** Get a global variable name. */ + String getJsVarName(String name); + + /** + * Completion stage when the client is ready (typically the page has loaded in + * the browser). + */ + CompletionStage getReadyStage(); + + /* + * DEFAULTS + */ + + default Object callMethod(String jsObject, String methodCall, Object... args) { + return evaluate(jsObject + '.' + methodCall, args); + } + + default void executeMethod(String jsObject, String methodCall, Object... args) { + execute(jsObject + '.' + methodCall, args); + } + + default boolean isInstanceOf(String reference, String jsClass) { + return (Boolean) evaluate("return "+getJsVarName(reference) + " instanceof " + jsClass); + } + + /* + * UTILITIES + */ + + static String toJsValue(Object o) { + if (o instanceof CharSequence) + return '\'' + o.toString() + '\''; + else if (o instanceof Number) + return o.toString(); + else if (o instanceof Boolean) + return o.toString(); + else if (o instanceof Map map) + return toJsMap(map); + else if (o instanceof Object[] arr) + return toJsArray(arr); + else if (o instanceof int[] arr) + return toJsArray(arr); + else if (o instanceof long[] arr) + return toJsArray(arr); + else if (o instanceof double[] arr) + return toJsArray(arr); + else if (o instanceof AbstractJsObject jsObject) { + if (jsObject.isNew()) + return jsObject.newJs(); + else + return jsObject.getJsReference(); + } else if (o instanceof JsReference jsReference) { + return jsReference.get(); + } else + return '\'' + o.toString() + '\''; + } + + static String toJsArgs(Object... arr) { + StringJoiner sj = new StringJoiner(","); + for (Object o : arr) { + sj.add(toJsValue(o)); + } + return sj.toString(); + } + + static String toJsArray(Object... arr) { + StringJoiner sj = new StringJoiner(",", "[", "]"); + for (Object o : arr) { + sj.add(toJsValue(o)); + } + return sj.toString(); + } + + static String toJsArray(String... arr) { + return toJsArray((Object[]) arr); + } + + static String toJsArray(double... arr) { + return Arrays.toString(arr); + } + + static String toJsArray(long... arr) { + return Arrays.toString(arr); + } + + static String toJsArray(int... arr) { + return Arrays.toString(arr); + } + + static String toJsMap(Map map) { + StringJoiner sj = new StringJoiner(",", "{", "}"); + // TODO escape forbidden characters + for (Object key : map.keySet()) { + sj.add("'" + key + "':" + toJsValue(map.get(key))); + } + return sj.toString(); + } + + static String escapeQuotes(String str) { + return str.replace("'", "\\'").replace("\"", "\\\""); + } + +} diff --git a/org.argeo.app.core/src/org/argeo/app/ux/js/JsReference.java b/org.argeo.app.core/src/org/argeo/app/ux/js/JsReference.java new file mode 100644 index 0000000..0cd8d81 --- /dev/null +++ b/org.argeo.app.core/src/org/argeo/app/ux/js/JsReference.java @@ -0,0 +1,17 @@ +package org.argeo.app.ux.js; + +import java.util.function.Supplier; + +/** Plain JS reference, to be directly serialised. */ +public class JsReference implements Supplier { + private final String reference; + + public JsReference(String reference) { + this.reference = reference; + } + + public String get() { + return reference; + } + +} diff --git a/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java b/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java index 6fee2f9..feea106 100644 --- a/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java +++ b/org.argeo.app.core/src/org/argeo/app/xforms/FormSubmissionListener.java @@ -4,9 +4,11 @@ import org.argeo.api.acr.Content; /** Called when a user has received a new form submission. */ public interface FormSubmissionListener { + final static String XML_SUBMISSION_FILE = "xml_submission_file"; + /** * Called after a form submission has been stored in the user area. The * submission will be deleted if any exception is thrown. */ - void formSubmissionReceived(Content content); + void formSubmissionReceived(Content content, boolean isIncomplete); } diff --git a/org.argeo.app.core/src/org/argeo/app/xforms/xforms.cnd b/org.argeo.app.core/src/org/argeo/app/xforms/xforms.cnd index c24dbae..9d4dc51 100644 --- a/org.argeo.app.core/src/org/argeo/app/xforms/xforms.cnd +++ b/org.argeo.app.core/src/org/argeo/app/xforms/xforms.cnd @@ -37,3 +37,4 @@ - * (STRING) + xforms:label (jcrx:xmlvalue) = jcrx:xmlvalue + xforms:hint (jcrx:xmlvalue) = jcrx:xmlvalue * ++ xforms:setvalue (xforms:setvalue) = xforms:setvalue * diff --git a/org.argeo.app.geo/.classpath b/org.argeo.app.geo/.classpath new file mode 100644 index 0000000..81fe078 --- /dev/null +++ b/org.argeo.app.geo/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.argeo.app.geo/.project b/org.argeo.app.geo/.project new file mode 100644 index 0000000..a41594e --- /dev/null +++ b/org.argeo.app.geo/.project @@ -0,0 +1,33 @@ + + + org.argeo.app.geo + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.argeo.app.geo/.settings/org.eclipse.core.resources.prefs b/org.argeo.app.geo/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/org.argeo.app.geo/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/org.argeo.app.geo/.settings/org.eclipse.jdt.core.prefs b/org.argeo.app.geo/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..62ef348 --- /dev/null +++ b/org.argeo.app.geo/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/org.argeo.app.geo/.settings/org.eclipse.pde.core.prefs b/org.argeo.app.geo/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000..f29e940 --- /dev/null +++ b/org.argeo.app.geo/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/org.argeo.app.geo/OSGI-INF/wfsHttpHandler.xml b/org.argeo.app.geo/OSGI-INF/wfsHttpHandler.xml new file mode 100644 index 0000000..0347631 --- /dev/null +++ b/org.argeo.app.geo/OSGI-INF/wfsHttpHandler.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/org.argeo.app.geo/bnd.bnd b/org.argeo.app.geo/bnd.bnd new file mode 100644 index 0000000..37b6d31 --- /dev/null +++ b/org.argeo.app.geo/bnd.bnd @@ -0,0 +1,8 @@ +Import-Package:\ +tech.units.indriya.unit,\ +com.fasterxml.jackson.core,\ +org.geotools.xml.transform,\ +* + +Service-Component:\ +OSGI-INF/wfsHttpHandler.xml,\ diff --git a/org.argeo.app.geo/build.properties b/org.argeo.app.geo/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/org.argeo.app.geo/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.argeo.app.geo/src/org/argeo/app/api/geo/FeatureAdapter.java b/org.argeo.app.geo/src/org/argeo/app/api/geo/FeatureAdapter.java new file mode 100644 index 0000000..69689a9 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/api/geo/FeatureAdapter.java @@ -0,0 +1,39 @@ +package org.argeo.app.api.geo; + +import javax.xml.namespace.QName; + +import org.argeo.api.acr.Content; +import org.argeo.api.acr.search.AndFilter; +import org.argeo.app.api.EntityType; +import org.argeo.app.geo.acr.GeoEntityUtils; +import org.locationtech.jts.geom.Geometry; + +import jakarta.json.stream.JsonGenerator; + +public interface FeatureAdapter { + default Geometry getDefaultGeometry(Content c, QName targetFeature) { + // TODO deal with more defaults + // TODO deal with target feature + if (c.hasContentClass(EntityType.geopoint)) { + return getGeoPointGeometry(c); + } + return null; + } + + void writeProperties(JsonGenerator g, Content content, QName targetFeature); + + void addConstraintsForFeature(AndFilter filter, QName targetFeature); + + static Geometry getGeoPointGeometry(Content c) { + if (c.hasContentClass(EntityType.geopoint)) { + return GeoEntityUtils.toPoint(c); +// double latitude = c.get(WGS84PosName.lat, Double.class).get(); +// double longitude = c.get(WGS84PosName.lon, Double.class).get(); +// +// Coordinate coordinate = new Coordinate(longitude, latitude); +// Point the_geom = JTS.GEOMETRY_FACTORY.createPoint(coordinate); +// return the_geom; + } + return null; + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/api/geo/WfsKvp.java b/org.argeo.app.geo/src/org/argeo/app/api/geo/WfsKvp.java new file mode 100644 index 0000000..166cdf0 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/api/geo/WfsKvp.java @@ -0,0 +1,24 @@ +package org.argeo.app.api.geo; + +/** Keys used for WFS KVP (key-value pair) encoding. */ +public enum WfsKvp { + CQL_FILTER("cql_filter"), // + OUTPUT_FORMAT("outputFormat"), // + TYPE_NAMES("typeNames"), // + BBOX("bbox"), // + FORMAT_OPTIONS("format_options"), // + ; + + public final static String FILENAME_ = "filename:"; + + private final String key; + + private WfsKvp(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/CqlUtils.java b/org.argeo.app.geo/src/org/argeo/app/geo/CqlUtils.java new file mode 100644 index 0000000..2186c54 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/CqlUtils.java @@ -0,0 +1,59 @@ +package org.argeo.app.geo; + +import org.argeo.api.acr.NamespaceUtils; +import org.argeo.api.acr.search.AndFilter; +import org.argeo.api.acr.search.BasicSearch; +import org.argeo.api.acr.search.ContentFilter; +import org.geotools.api.filter.And; +import org.geotools.api.filter.Filter; +import org.geotools.api.filter.PropertyIsEqualTo; +import org.geotools.api.filter.expression.Literal; +import org.geotools.api.filter.expression.PropertyName; +import org.geotools.filter.text.cql2.CQL; +import org.geotools.filter.text.cql2.CQLException; + +/** Utilities around the CQL query format. */ +public class CqlUtils { + + public static void filter(BasicSearch search, String cql) { + try { + filter(search, CQL.toFilter(cql)); + } catch (CQLException e) { + throw new IllegalArgumentException("Cannot parse CQL: " + cql, e); + } + } + + public static void filter(BasicSearch search, Filter filter) { + search.where((where) -> { + if (filter instanceof And and) { + processAnd(where, and); + } else if (filter instanceof PropertyIsEqualTo propertyIsEqualTo) { + processIsEqualTo(where, propertyIsEqualTo); + } else { + throw new IllegalArgumentException("Unsupported filter " + filter.getClass()); + } + }); + } + + private static void processAnd(AndFilter contentFilter, And filter) { + for (Filter child : filter.getChildren()) { + if (child instanceof PropertyIsEqualTo propertyIsEqualTo) { + processIsEqualTo(contentFilter, propertyIsEqualTo); + } + } + + } + + private static void processIsEqualTo(ContentFilter contentFilter, PropertyIsEqualTo propertyIsEqualTo) { + // TODO properly deal with types etc. + // see GeoTools org.geotools.filter.text.commons.ExpressionToText + PropertyName propertyName = (PropertyName) propertyIsEqualTo.getExpression1(); + Literal value = (Literal) propertyIsEqualTo.getExpression2(); + // String escaped = literal.toString().replaceAll("'", "''"); + contentFilter.eq(NamespaceUtils.parsePrefixedName(propertyName.toString()), value.toString()); + } + + /** singleton */ + private CqlUtils() { + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GeoJson.java b/org.argeo.app.geo/src/org/argeo/app/geo/GeoJson.java new file mode 100644 index 0000000..8c4c7b2 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GeoJson.java @@ -0,0 +1,172 @@ +package org.argeo.app.geo; + +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Envelope; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryCollection; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.LinearRing; +import org.locationtech.jts.geom.MultiPoint; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Polygon; + +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.stream.JsonGenerator; + +/** + * GeoJSon format. + * + * @see https://datatracker.ietf.org/doc/html/rfc7946 + */ +public class GeoJson { + public final static String POINT_TYPE = "Point"; + public final static String MULTI_POINT_TYPE = "MultiPoint"; + public final static String LINE_STRING_TYPE = "LineString"; + public final static String POLYGON_TYPE = "Polygon"; + public final static String GEOMETRY_COLLECTION_TYPE = "GeometryCollection"; + + public final static String TYPE = "type"; + public final static String GEOMETRY = "geometry"; + public final static String GEOMETRIES = "geometries"; + public final static String COORDINATES = "coordinates"; + public final static String BBOX = "bbox"; + public final static String PROPERTIES = "properties"; + + /* + * WRITE + */ + /** Writes a {@link Geometry} as GeoJSON. */ + public static void writeGeometry(JsonGenerator g, Geometry geometry) { + if (geometry instanceof Point point) { + g.write(TYPE, POINT_TYPE); + g.writeStartArray(COORDINATES); + writeCoordinate(g, point.getCoordinate()); + g.writeEnd();// coordinates array + } else if (geometry instanceof MultiPoint multiPoint) { + g.write(TYPE, MULTI_POINT_TYPE); + g.writeStartArray(COORDINATES); + writeCoordinates(g, multiPoint.getCoordinates()); + g.writeEnd();// coordinates array + } else if (geometry instanceof LineString lineString) { + g.write(TYPE, LINE_STRING_TYPE); + g.writeStartArray(COORDINATES); + writeCoordinates(g, lineString.getCoordinates()); + g.writeEnd();// coordinates array + } else if (geometry instanceof Polygon polygon) { + g.write(TYPE, POLYGON_TYPE); + g.writeStartArray(COORDINATES); + LinearRing exteriorRing = polygon.getExteriorRing(); + g.writeStartArray(); + writeCoordinates(g, exteriorRing.getCoordinates()); + g.writeEnd(); + for (int i = 0; i < polygon.getNumInteriorRing(); i++) { + LinearRing interiorRing = polygon.getInteriorRingN(i); + // TODO verify that holes are clockwise + g.writeStartArray(); + writeCoordinates(g, interiorRing.getCoordinates()); + g.writeEnd(); + } + g.writeEnd();// coordinates array + } else if (geometry instanceof GeometryCollection geometryCollection) {// must be last + g.write(TYPE, GEOMETRY_COLLECTION_TYPE); + g.writeStartArray(GEOMETRIES); + for (int i = 0; i < geometryCollection.getNumGeometries(); i++) { + g.writeStartObject(); + writeGeometry(g, geometryCollection.getGeometryN(i)); + g.writeEnd();// geometry object + } + g.writeEnd();// geometries array + } else { + throw new IllegalArgumentException(geometry.getClass() + " is not supported."); + } + } + + /** Writes a sequence of coordinates [[lat,lon],[lat,lon]] */ + public static void writeCoordinates(JsonGenerator g, Coordinate[] coordinates) { + for (Coordinate coordinate : coordinates) { + g.writeStartArray(); + writeCoordinate(g, coordinate); + g.writeEnd(); + } + } + + /** Writes a pair of coordinates [lat,lon]. */ + public static void writeCoordinate(JsonGenerator g, Coordinate coordinate) { + // !! longitude is first in GeoJSON + g.write(coordinate.getY()); + g.write(coordinate.getX()); + double z = coordinate.getZ(); + if (!Double.isNaN(z)) { + g.write(z); + } + } + + /** + * Writes the {@link Envelope} of a {@link Geometry} as a bbox GeoJSON object. + */ + public static void writeBBox(JsonGenerator g, Geometry geometry) { + g.writeStartArray(BBOX); + Envelope envelope = geometry.getEnvelopeInternal(); + g.write(envelope.getMinX()); + g.write(envelope.getMinY()); + g.write(envelope.getMaxX()); + g.write(envelope.getMaxY()); + g.writeEnd(); + } + + /* + * READ + */ + /** Reads a geometry from the geometry object of a GEoJSON feature. */ + @SuppressWarnings("unchecked") + public static T readGeometry(JsonObject geom, Class clss) { + String type = geom.getString(TYPE); + JsonArray coordinates = geom.getJsonArray(COORDINATES); + Geometry res = switch (type) { + case POINT_TYPE: { + Coordinate coord = readCoordinate(coordinates); + yield JTS.GEOMETRY_FACTORY_WGS84.createPoint(coord); + } + case LINE_STRING_TYPE: { + Coordinate[] coords = readCoordinates(coordinates); + yield JTS.GEOMETRY_FACTORY_WGS84.createLineString(coords); + } + case POLYGON_TYPE: { + assert coordinates.size() > 0; + LinearRing exterior = JTS.GEOMETRY_FACTORY_WGS84 + .createLinearRing(readCoordinates(coordinates.getJsonArray(0))); + LinearRing[] holes = new LinearRing[coordinates.size() - 1]; + for (int i = 0; i < coordinates.size() - 1; i++) { + holes[i] = JTS.GEOMETRY_FACTORY_WGS84 + .createLinearRing(readCoordinates(coordinates.getJsonArray(i + 1))); + } + yield JTS.GEOMETRY_FACTORY_WGS84.createPolygon(exterior, holes); + } + default: + throw new IllegalArgumentException("Unexpected value: " + type); + }; +// res.normalize(); + return (T) res; + } + + /** Reads a coordinate pair [lon,lat]. */ + public static Coordinate readCoordinate(JsonArray arr) { + assert arr.size() >= 2; + // !! longitude is first in GeoJSon + return new Coordinate(arr.getJsonNumber(1).doubleValue(), arr.getJsonNumber(0).doubleValue()); + } + + /** Reads a coordinate sequence [[lon,lat],[lon,lat]]. */ + public static Coordinate[] readCoordinates(JsonArray arr) { + Coordinate[] coords = new Coordinate[arr.size()]; + for (int i = 0; i < arr.size(); i++) + coords[i] = readCoordinate(arr.getJsonArray(i)); + return coords; + } + + /** singleton */ + private GeoJson() { + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GeoJsonUtils.java b/org.argeo.app.geo/src/org/argeo/app/geo/GeoJsonUtils.java new file mode 100644 index 0000000..84610c8 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GeoJsonUtils.java @@ -0,0 +1,24 @@ +package org.argeo.app.geo; + +import java.util.Map; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** Geo data utilities. */ +public class GeoJsonUtils { + + /** Add these properties to all features. */ + public static void addProperties(JsonNode tree, Map map) { + for (JsonNode feature : tree.get("features")) { + ObjectNode properties = (ObjectNode) feature.get("properties"); + for (String key : map.keySet()) { + properties.put(key, map.get(key)); + } + } + } + + /** Singleton. */ + private GeoJsonUtils() { + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GeoShapeUtils.java b/org.argeo.app.geo/src/org/argeo/app/geo/GeoShapeUtils.java new file mode 100644 index 0000000..d35492a --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GeoShapeUtils.java @@ -0,0 +1,100 @@ +package org.argeo.app.geo; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.StringTokenizer; + +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.MultiPoint; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Polygon; + +/** Utilities around ODK's GeoShape format */ +public class GeoShapeUtils { + + @SuppressWarnings("unchecked") + public static T geoShapeToGeometry(String geoShape, Class clss) { + Objects.requireNonNull(geoShape); + GeometryFactory geometryFactory = JTS.GEOMETRY_FACTORY_WGS84; + List coordinates = new ArrayList<>(); + StringTokenizer stSeg = new StringTokenizer(geoShape.trim(), ";"); + while (stSeg.hasMoreTokens()) { + StringTokenizer stPt = new StringTokenizer(stSeg.nextToken().trim(), " "); + String lat = stPt.nextToken(); + String lng = stPt.nextToken(); + String alt = stPt.nextToken(); + // String precision = stPt.nextToken(); + Coordinate coord; + if (!alt.equals("0.0")) { + coord = new Coordinate(Double.parseDouble(lat), Double.parseDouble(lng), Double.parseDouble(alt)); + } else { + coord = new Coordinate(Double.parseDouble(lat), Double.parseDouble(lng)); + } + coordinates.add(coord); + } + if (LineString.class.isAssignableFrom(clss)) { + LineString lineString = geometryFactory + .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); + return (T) lineString; + } else if (MultiPoint.class.isAssignableFrom(clss)) { + MultiPoint multiPoint = geometryFactory + .createMultiPointFromCoords(coordinates.toArray(new Coordinate[coordinates.size()])); + return (T) multiPoint; + } else if (Polygon.class.isAssignableFrom(clss)) { + Coordinate first = coordinates.get(0); + Coordinate last = coordinates.get(coordinates.size() - 1); + if (!(first.getX() == last.getX() && first.getY() == last.getY())) { + // close the line string + coordinates.add(first); + } + Polygon polygon = geometryFactory.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); + return (T) polygon; + } else { + throw new IllegalArgumentException("Unsupported format " + clss); + } + } + + /** Converts a {@link Geometry} with WGS84 coordinates to a GeoShape. */ + public static String geometryToGeoShape(Geometry geometry) { + if (geometry instanceof Point point) { + Coordinate coordinate = point.getCoordinate(); + StringBuilder sb = new StringBuilder(); + appendToGeoShape(sb, coordinate.getX(), coordinate.getY(), coordinate.getZ()); + return sb.toString(); + } else if (geometry instanceof Polygon || geometry instanceof LineString) { + StringBuilder sb = new StringBuilder(); + for (Coordinate coordinate : geometry.getCoordinates()) { + appendToGeoShape(sb, coordinate.getX(), coordinate.getY(), coordinate.getZ()); + sb.append(';'); + } + return sb.toString(); + } else { + throw new IllegalArgumentException("Unsupported geometry " + geometry.getClass()); + } + } + + public static String geoPointToGeoShape(double lon, double lat, double alt) { + StringBuilder sb = new StringBuilder(); + appendToGeoShape(sb, lon, lat, alt); + return sb.toString(); + } + + private static void appendToGeoShape(StringBuilder sb, double lon, double lat, double alt) { + sb.append(lat).append(' '); + sb.append(lon).append(' '); + if (alt != Double.NaN) + sb.append(alt).append(' '); + else + sb.append("0 "); + sb.append('0'); + } + + /** singleton */ + private GeoShapeUtils() { + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GeoToSvg.java b/org.argeo.app.geo/src/org/argeo/app/geo/GeoToSvg.java new file mode 100644 index 0000000..abb5b39 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GeoToSvg.java @@ -0,0 +1,69 @@ +package org.argeo.app.geo; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** Converts a geographical feature to an SVG. */ +public class GeoToSvg { + public void convertGeoJsonToSvg(Path source, Path target) { + ObjectMapper objectMapper = new ObjectMapper(); + try (InputStream in = Files.newInputStream(source); + Writer out = Files.newBufferedWriter(target, StandardCharsets.UTF_8)) { + JsonNode tree = objectMapper.readTree(in); + JsonNode coord = tree.get("features").get(0).get("geometry").get("coordinates"); + double ratio = 100; + double minX = Double.POSITIVE_INFINITY; + double maxX = Double.NEGATIVE_INFINITY; + double minY = Double.POSITIVE_INFINITY; + double maxY = Double.NEGATIVE_INFINITY; + List shapes = new ArrayList<>(); + for (JsonNode shape : coord) { + StringBuffer sb = new StringBuffer(); + sb.append(" maxY) + maxY = y; + double lng = latlng.get(1).asDouble(); + double x = lng * ratio; + if (x < minX) + minX = x; + if (x > maxX) + maxX = x; + sb.append(y + "," + x + " "); + } + sb.append("\">"); + sb.append("\n"); + shapes.add(sb.toString()); + } + + double width = maxX - minX; + double height = maxY - minY; + out.write("\n"); + for (String shape : shapes) { + out.write(shape); + out.write("\n"); + } + out.write(""); + } catch (IOException e) { + throw new RuntimeException("Cannot convert " + source + " to " + target, e); + } + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GeoTools.java b/org.argeo.app.geo/src/org/argeo/app/geo/GeoTools.java new file mode 100644 index 0000000..7571da7 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GeoTools.java @@ -0,0 +1,30 @@ +package org.argeo.app.geo; + +import org.argeo.api.cms.CmsLog; +import org.geotools.api.filter.FilterFactory; +import org.geotools.api.style.StyleFactory; +import org.geotools.factory.CommonFactoryFinder; + +/** + * Factories initialisation and workarounds for the GeoTools library. The idea + * is to code defensively around factory initialisation, API changes, and issues + * related to running in an OSGi environment. Rather see {@link GeoUtils} for + * functional static utilities. + */ +public class GeoTools { + private final static CmsLog log = CmsLog.getLog(GeoTools.class); + + public final static StyleFactory STYLE_FACTORY; + public final static FilterFactory FILTER_FACTORY; + + static { + try { + STYLE_FACTORY = CommonFactoryFinder.getStyleFactory(); + FILTER_FACTORY = CommonFactoryFinder.getFilterFactory(); + } catch (RuntimeException e) { + log.error("Basic GeoTools initialisation failed, geographical utilities are probably not available", e); + throw e; + } + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GeoToolsTest.java b/org.argeo.app.geo/src/org/argeo/app/geo/GeoToolsTest.java new file mode 100644 index 0000000..e6f9c19 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GeoToolsTest.java @@ -0,0 +1,221 @@ +package org.argeo.app.geo; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.geotools.api.data.SimpleFeatureSource; +import org.geotools.api.data.SimpleFeatureStore; +import org.geotools.api.data.Transaction; +import org.geotools.api.feature.simple.SimpleFeature; +import org.geotools.api.feature.simple.SimpleFeatureType; +import org.geotools.data.DataUtilities; +import org.geotools.data.DefaultTransaction; +import org.geotools.data.collection.ListFeatureCollection; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.ShapefileDataStoreFactory; +import org.geotools.data.simple.SimpleFeatureCollection; +import org.geotools.feature.simple.SimpleFeatureBuilder; +import org.geotools.geometry.jts.JTSFactoryFinder; +import org.geotools.swing.data.JFileDataStoreChooser; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.Point; + +public class GeoToolsTest { + public GeoToolsTest() { + + } + + public void init() { + try { + main(null); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void destroy() { + + } + + public static void main(String[] args) throws Exception { + final SimpleFeatureType TYPE = DataUtilities.createType("Location", "the_geom:Point:srid=4326," + // <- the + // geometry + // attribute: + // Point + // type + "name:String," + // <- a String attribute + "number:Integer" // a number attribute + ); + final SimpleFeatureType TYPE_HULL = DataUtilities.createType("Hull", "the_geom:MultiPolygon:srid=4326"); + System.out.println("TYPE:" + TYPE); + + /* + * A list to collect features as we create them. + */ + List features = new ArrayList<>(); + List coordinates = new ArrayList<>(); + + /* + * GeometryFactory will be used to create the geometry attribute of each + * feature, using a Point object for the location. + */ + GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); + + SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE); + + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(GeoToolsTest.class.getResourceAsStream("/org/djapps/on/apaf/locations.csv")))) { + /* First line of the data file is the header */ + String line = reader.readLine(); + System.out.println("Header: " + line); + + for (line = reader.readLine(); line != null; line = reader.readLine()) { + if (line.trim().length() > 0) { // skip blank lines + String[] tokens = line.split("\\,"); + + double latitude = Double.parseDouble(tokens[0]); + double longitude = Double.parseDouble(tokens[1]); + String name = tokens[2].trim(); + int number = Integer.parseInt(tokens[3].trim()); + + /* Longitude (= x coord) first ! */ + Coordinate coordinate = new Coordinate(longitude, latitude); + coordinates.add(coordinate); + Point point = geometryFactory.createPoint(coordinate); + + featureBuilder.add(point); + featureBuilder.add(name); + featureBuilder.add(number); + SimpleFeature feature = featureBuilder.buildFeature(null); + features.add(feature); + } + } + } + + LineString lineString = geometryFactory + .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); + Geometry convexHull = lineString.convexHull(); + System.out.println(convexHull.toText()); + SimpleFeatureBuilder hullFeatureBuilder = new SimpleFeatureBuilder(TYPE_HULL); + hullFeatureBuilder.add(convexHull); + SimpleFeature hull = hullFeatureBuilder.buildFeature(null); + + /* + * Get an output file name and create the new shapefile + */ + File newFile = getNewShapeFile(); + + ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory(); + + Map params = new HashMap<>(); + params.put("url", newFile.toURI().toURL()); + params.put("create spatial index", Boolean.TRUE); + + ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params); + + /* + * TYPE is used as a template to describe the file contents + */ + newDataStore.createSchema(TYPE_HULL); + + /* + * Write the features to the shapefile + */ + Transaction transaction = new DefaultTransaction("create"); + + String typeName = newDataStore.getTypeNames()[0]; + SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName); + SimpleFeatureType SHAPE_TYPE = featureSource.getSchema(); + /* + * The Shapefile format has a couple limitations: - "the_geom" is always first, + * and used for the geometry attribute name - "the_geom" must be of type Point, + * MultiPoint, MuiltiLineString, MultiPolygon - Attribute names are limited in + * length - Not all data types are supported (example Timestamp represented as + * Date) + * + * Each data store has different limitations so check the resulting + * SimpleFeatureType. + */ + System.out.println("SHAPE:" + SHAPE_TYPE); + + if (featureSource instanceof SimpleFeatureStore) { + SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; + /* + * SimpleFeatureStore has a method to add features from a + * SimpleFeatureCollection object, so we use the ListFeatureCollection class to + * wrap our list of features. + */ + SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, Collections.singletonList(hull)); + featureStore.setTransaction(transaction); + try { + featureStore.addFeatures(collection); + transaction.commit(); + } catch (Exception problem) { + problem.printStackTrace(); + transaction.rollback(); + } finally { + transaction.close(); + } + } else { + System.out.println(typeName + " does not support read/write access"); + } +// if (featureSource instanceof SimpleFeatureStore) { +// SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; +// /* +// * SimpleFeatureStore has a method to add features from a +// * SimpleFeatureCollection object, so we use the ListFeatureCollection class to +// * wrap our list of features. +// */ +// SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features); +// featureStore.setTransaction(transaction); +// try { +// featureStore.addFeatures(collection); +// transaction.commit(); +// } catch (Exception problem) { +// problem.printStackTrace(); +// transaction.rollback(); +// } finally { +// transaction.close(); +// } +// } else { +// System.out.println(typeName + " does not support read/write access"); +// } + } + + /** + * Prompt the user for the name and path to use for the output shapefile + * + * @param csvFile the input csv file used to create a default shapefile name + * @return name and path for the shapefile as a new File object + */ + private static File getNewShapeFile() { +// String path = csvFile.getAbsolutePath(); +// String newPath = path.substring(0, path.length() - 4) + ".shp"; + + JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp"); + chooser.setDialogTitle("Save shapefile"); +// chooser.setSelectedFile(new File(newPath)); + + int returnVal = chooser.showSaveDialog(null); + + if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) { + // the user cancelled the dialog + System.exit(0); + } + + File newFile = chooser.getSelectedFile(); + + return newFile; + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GeoUtils.java b/org.argeo.app.geo/src/org/argeo/app/geo/GeoUtils.java new file mode 100644 index 0000000..f134678 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GeoUtils.java @@ -0,0 +1,458 @@ +package org.argeo.app.geo; + +import java.io.IOException; +import java.io.Serializable; +import java.io.Writer; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javax.measure.Quantity; +import javax.measure.quantity.Area; +import javax.xml.transform.TransformerException; + +import org.geotools.api.data.SimpleFeatureSource; +import org.geotools.api.data.SimpleFeatureStore; +import org.geotools.api.data.Transaction; +import org.geotools.api.feature.simple.SimpleFeature; +import org.geotools.api.feature.simple.SimpleFeatureType; +import org.geotools.api.filter.Filter; +import org.geotools.api.filter.FilterFactory; +import org.geotools.api.filter.expression.Expression; +import org.geotools.api.geometry.MismatchedDimensionException; +import org.geotools.api.referencing.FactoryException; +import org.geotools.api.referencing.crs.CoordinateReferenceSystem; +import org.geotools.api.referencing.operation.MathTransform; +import org.geotools.api.referencing.operation.TransformException; +import org.geotools.api.style.AnchorPoint; +import org.geotools.api.style.Displacement; +import org.geotools.api.style.FeatureTypeConstraint; +import org.geotools.api.style.FeatureTypeStyle; +import org.geotools.api.style.Fill; +import org.geotools.api.style.Graphic; +import org.geotools.api.style.GraphicalSymbol; +import org.geotools.api.style.NamedLayer; +import org.geotools.api.style.PointSymbolizer; +import org.geotools.api.style.Rule; +import org.geotools.api.style.Stroke; +import org.geotools.api.style.Style; +import org.geotools.api.style.StyleFactory; +import org.geotools.api.style.StyledLayerDescriptor; +import org.geotools.api.style.UserLayer; +import org.geotools.data.DefaultTransaction; +import org.geotools.data.collection.ListFeatureCollection; +import org.geotools.data.shapefile.ShapefileDataStore; +import org.geotools.data.shapefile.ShapefileDataStoreFactory; +import org.geotools.data.simple.SimpleFeatureCollection; +import org.geotools.factory.CommonFactoryFinder; +import org.geotools.geometry.jts.JTS; +import org.geotools.referencing.CRS; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.geotools.styling.css.CssParser; +import org.geotools.styling.css.CssTranslator; +import org.geotools.styling.css.Stylesheet; +import org.geotools.xml.styling.SLDTransformer; +import org.locationtech.jts.algorithm.hull.ConcaveHull; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Polygon; +import org.locationtech.jts.geom.util.GeometryFixer; +import org.locationtech.jts.operation.polygonize.Polygonizer; + +import si.uom.SI; +import tech.units.indriya.quantity.Quantities; + +/** Utilities around geographical format, mostly wrapping GeoTools patterns. */ +public class GeoUtils { + public final static String EPSG_4326 = "EPSG:4326"; + + /** In square meters. */ + public static Quantity calcArea(SimpleFeature feature) { + try { + Polygon polygon = (Polygon) feature.getDefaultGeometry(); + Point centroid = polygon.getCentroid(); +// CoordinateReferenceSystem crs = feature.getDefaultGeometryProperty().getType() +// .getCoordinateReferenceSystem(); + // TODO convert the centroid +// if (!crs.getName().equals(DefaultGeographicCRS.WGS84.getName())) +// throw new IllegalArgumentException("Only WGS84 CRS is currently supported"); + + // create automatic CRS for optimal computation + String code = "AUTO:42001," + centroid.getX() + "," + centroid.getY(); + CoordinateReferenceSystem auto = CRS.decode(code); + + MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto); + + Polygon projed = (Polygon) JTS.transform(polygon, transform); + return Quantities.getQuantity(projed.getArea(), SI.SQUARE_METRE); + } catch (MismatchedDimensionException | FactoryException | TransformException e) { + throw new IllegalStateException("Cannot calculate area of feature", e); + } + } + + /** In square meters. The {@link Polygon} must use WGS84 coordinates. */ + public static Quantity calcArea(Polygon polygon) { + assert polygon.getSRID() == 0 || polygon.getSRID() == 4326; + return calcArea(polygon, DefaultGeographicCRS.WGS84, polygon.getCentroid()); + } + + public static Quantity calcArea(Polygon polygon, CoordinateReferenceSystem crs, Point wgs84centroid) { + try { + // create automatic CRS for optimal computation + String code = "AUTO:42001," + wgs84centroid.getX() + "," + wgs84centroid.getY(); + CoordinateReferenceSystem auto = CRS.decode(code); + + MathTransform transform = CRS.findMathTransform(crs, auto); + + Polygon projed = (Polygon) JTS.transform(polygon, transform); + return Quantities.getQuantity(projed.getArea(), SI.SQUARE_METRE); + } catch (MismatchedDimensionException | FactoryException | TransformException e) { + throw new IllegalStateException("Cannot calculate area of feature", e); + } + } + + public static void exportToSvg(Geometry[] geometries, Writer out, int width, int height) { + try { + double minY = Double.POSITIVE_INFINITY; + double maxY = Double.NEGATIVE_INFINITY; + double minX = Double.POSITIVE_INFINITY; + double maxX = Double.NEGATIVE_INFINITY; + List shapes = new ArrayList<>(); + for (Geometry geometry : geometries) { + StringBuffer sb = new StringBuffer(); + sb.append(" maxX) + maxX = x; + double y = -coord.x; + if (y < minY) + minY = y; + if (y > maxY) + maxY = y; + sb.append(x + "," + y + " "); + } + sb.append("\">"); + sb.append("\n"); + shapes.add(sb.toString()); + } else { + throw new IllegalArgumentException("Unsuppported geometry type " + geometry.getClass().getName()); + } + } + double viewportHeight = maxY - minY; + double viewportWidth = maxX - minX; + out.write("\n"); + for (String shape : shapes) { + out.write(shape); + out.write("\n"); + } + out.write(""); + } catch (IOException | FactoryException | MismatchedDimensionException | TransformException e) { + throw new RuntimeException("Cannot export to SVG", e); + } + } + + /** Write a list of simple features to a shapefile. */ + public static void saveFeaturesAsShapefile(SimpleFeatureType featureType, List features, + Path shpFile) { + try { + ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory(); + + Map params = new HashMap<>(); + params.put("url", shpFile.toUri().toURL()); + + params.put("create spatial index", Boolean.TRUE); + + ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params); + newDataStore.createSchema(featureType); + + String typeName = newDataStore.getTypeNames()[0]; + SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName); + if (featureSource instanceof SimpleFeatureStore) { + SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; + SimpleFeatureCollection collection = new ListFeatureCollection(featureType, features); + + try (Transaction transaction = new DefaultTransaction("create")) { + try { + featureStore.setTransaction(transaction); + featureStore.addFeatures(collection); + transaction.commit(); + } catch (Exception problem) { + transaction.rollback(); + throw new RuntimeException("Cannot write shapefile " + shpFile, problem); + } + } + } else { + throw new IllegalArgumentException(typeName + " does not support read/write access"); + } + } catch (IOException e) { + throw new RuntimeException("Cannot write shapefile " + shpFile, e); + } + } + + /* + * STYLING + */ + + public static Style createStyleFromCss(String css) { + Stylesheet ss = CssParser.parse(css); + CssTranslator translator = new CssTranslator(); + Style style = translator.translate(ss); + +// try { +// SLDTransformer styleTransform = new SLDTransformer(); +// String xml = styleTransform.transform(style); +// System.out.println(xml); +// } catch (TransformerException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } + + return (Style) style; + } + + public static String createSldFromCss(String name, String title, String css) { + StyledLayerDescriptor sld = GeoTools.STYLE_FACTORY.createStyledLayerDescriptor(); + sld.setName(name); + sld.setTitle(title); + + NamedLayer layer = GeoTools.STYLE_FACTORY.createNamedLayer(); + layer.setName(name); + + Style style = createStyleFromCss(css); + layer.styles().add(style); + + sld.layers().add(layer); + return sldToXml(sld); + } + + public static String sldToXml(StyledLayerDescriptor sld) { + try { + SLDTransformer styleTransform = new SLDTransformer(); + String xml = styleTransform.transform(sld); +// System.out.println(xml); + return xml; + } catch (TransformerException e) { + throw new IllegalStateException("Cannot write SLD as XML", e); + } + } + + public static void main(String... args) { + String css = """ + * { + mark: symbol(circle); + mark-size: 6px; + } + + :mark { + fill: red; + } + + """; + createSldFromCss("test", "Test", css); + } + + public static String createTestSLD() { + + StyleFactory sf = CommonFactoryFinder.getStyleFactory(); + FilterFactory ff = CommonFactoryFinder.getFilterFactory(); + + StyledLayerDescriptor sld = sf.createStyledLayerDescriptor(); + sld.setName("sld"); + sld.setTitle("Example"); + sld.setAbstract("Example Style Layer Descriptor"); + + UserLayer layer = sf.createUserLayer(); + layer.setName("layer"); + + // + // define constraint limited what features the sld applies to + FeatureTypeConstraint constraint = sf.createFeatureTypeConstraint("Feature", Filter.INCLUDE); + + layer.layerFeatureConstraints().add(constraint); + + // + // create a "user defined" style + Style style = sf.createStyle(); + style.setName("style"); + style.getDescription().setTitle("User Style"); + style.getDescription().setAbstract("Definition of Style"); + + // + // define feature type styles used to actually define how features are rendered + FeatureTypeStyle featureTypeStyle = sf.createFeatureTypeStyle(); + + // RULE 1 + // first rule to draw cities + Rule rule1 = sf.createRule(); + rule1.setName("rule1"); + rule1.getDescription().setTitle("City"); + rule1.getDescription().setAbstract("Rule for drawing cities"); +// rule1.setFilter(ff.less(ff.property("POPULATION"), ff.literal(50000))); + + // + // create the graphical mark used to represent a city + Stroke stroke = sf.stroke(ff.literal("#000000"), null, null, null, null, null, null); + Fill fill = sf.fill(null, ff.literal(java.awt.Color.BLUE), ff.literal(1.0)); + +// // OnLineResource implemented by gt-metadata - so no factory! +// OnLineResourceImpl svg = new OnLineResourceImpl(new URI("file:city.svg")); +// svg.freeze(); // freeze to prevent modification at runtime +// +// OnLineResourceImpl png = new OnLineResourceImpl(new URI("file:city.png")); +// png.freeze(); // freeze to prevent modification at runtime + + // + // List of symbols is considered in order with the rendering engine choosing + // the first one it can handle. Allowing for svg, png, mark order + List symbols = new ArrayList<>(); +// symbols.add(sf.externalGraphic(svg, "svg", null)); // svg preferred +// symbols.add(sf.externalGraphic(png, "png", null)); // png preferred + symbols.add(sf.mark(ff.literal("circle"), fill, stroke)); // simple circle backup plan + + Expression opacity = null; // use default + Expression size = ff.literal(10); + Expression rotation = null; // use default + AnchorPoint anchor = null; // use default + Displacement displacement = null; // use default + + // define a point symbolizer of a small circle + Graphic city = sf.graphic(symbols, opacity, size, rotation, anchor, displacement); + PointSymbolizer pointSymbolizer = sf.pointSymbolizer("point", ff.property("the_geom"), null, null, city); + + rule1.symbolizers().add(pointSymbolizer); + + featureTypeStyle.rules().add(rule1); + + // + // RULE 2 Default + +// List dotSymbols = new ArrayList<>(); +// dotSymbols.add(sf.mark(ff.literal("circle"), null, null)); +// Graphic dotGraphic = sf.graphic(dotSymbols, null, ff.literal(3), null, null, null); +// PointSymbolizer dotSymbolizer = sf.pointSymbolizer("dot", ff.property("the_geom"), null, null, dotGraphic); +// List symbolizers = new ArrayList<>(); +// symbolizers.add(dotSymbolizer); +// Filter other = null; // null will mark this rule as "other" accepting all remaining features +// Rule rule2 = sf.rule("default", null, null, Double.MIN_VALUE, Double.MAX_VALUE, symbolizers, other); +// featureTypeStyle.rules().add(rule2); + + style.featureTypeStyles().add(featureTypeStyle); + + layer.userStyles().add(style); + + sld.layers().add(layer); + + try { + SLDTransformer styleTransform = new SLDTransformer(); + String xml = styleTransform.transform(sld); + System.out.println(xml); + return xml; + } catch (TransformerException e) { + throw new IllegalStateException(e); + } + + } + + public static long getScaleFromResolution(long resolution) { + // see + // https://gis.stackexchange.com/questions/242424/how-to-get-map-units-to-find-current-scale-in-openlayers + final double INCHES_PER_UNIT = 39.37;// m + // final double INCHES_PER_UNIT = 4374754;// dd + final long DOTS_PER_INCH = 72; + return Math.round(INCHES_PER_UNIT * DOTS_PER_INCH * resolution); + } + + /* + * GEOMETRY + */ + /** + * Ensure that a {@link Polygon} is valid and simple by removing artefacts + * (typically coming from GPS). + * + * @return a simple and valid polygon, or null if the ignoredArea ratio is above + * the provided threshold. + */ + public static Polygon cleanPolygon(Polygon polygon, double ignoredAreaRatio) { + Polygonizer polygonizer = new Polygonizer(true); + Geometry fixed = GeometryFixer.fix(polygon, false); + polygonizer.add(fixed); + @SuppressWarnings("unchecked") + List polygons = new ArrayList<>(polygonizer.getPolygons()); + + if (polygons.size() == 0) { + throw new IllegalStateException("Polygonizer failed to extract any polygon"); + } + + Polygon best; + if (polygons.size() == 1) { + best = polygons.get(0); + } else { + double totalArea = fixed.getArea(); + best = polygons.get(0); + double bestArea = best.getArea(); + for (int i = 1; i < polygons.size(); i++) { + Polygon p = polygons.get(i); + double a = p.getArea(); + if (a > bestArea) { + best = p; + bestArea = a; + } else { + // double ratio = a / totalArea; + } + } + double ignoredRatio = (totalArea - bestArea) / totalArea; + if (ignoredRatio > ignoredAreaRatio) + return null; + + if (!best.isValid() || !best.isSimple()) { + throw new IllegalStateException("The polygon is not simple and/or valid after cleaning"); + } + } + // while we are here, we make sure that the geometry will be normalised + best.normalize(); + return best; + } + + /** + * The smallest polygon without holes containing all the points in this + * geometry. + */ + public static Polygon concaveHull(Geometry geom, double lengthRatio) { + Objects.requireNonNull(geom); + if (geom.getNumPoints() < 3) + throw new IllegalArgumentException("At least 3 points are reuired to compute the concave hull and geometry " + + geom.getClass() + " contains only " + geom.getNumPoints()); + Geometry hull = ConcaveHull.concaveHullByLengthRatio(geom, lengthRatio, false); + if (hull instanceof Polygon polygon) + return polygon; + else + throw new IllegalStateException("Hull is not a polygon but a " + hull.getClass()); + } + + /** Singleton. */ + private GeoUtils() { + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GmlAttr.java b/org.argeo.app.geo/src/org/argeo/app/geo/GmlAttr.java new file mode 100644 index 0000000..77b0885 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GmlAttr.java @@ -0,0 +1,22 @@ +package org.argeo.app.geo; + +import org.argeo.api.acr.QNamed; + +public enum GmlAttr implements QNamed { + uom + // + ; + + public final static String UOM_SQUARE_METERS = "m2"; + + @Override + public String getNamespace() { + return "http://www.opengis.net/gml/3.2"; + } + + @Override + public String getDefaultPrefix() { + return "gml"; + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GmlType.java b/org.argeo.app.geo/src/org/argeo/app/geo/GmlType.java new file mode 100644 index 0000000..980a5e4 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GmlType.java @@ -0,0 +1,20 @@ +package org.argeo.app.geo; + +import org.argeo.api.acr.QNamed; + +public enum GmlType implements QNamed { + measure + // + ; + + @Override + public String getNamespace() { + return "http://www.opengis.net/gml/3.2"; + } + + @Override + public String getDefaultPrefix() { + return "gml"; + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/GpxUtils.java b/org.argeo.app.geo/src/org/argeo/app/geo/GpxUtils.java new file mode 100644 index 0000000..44afa2c --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/GpxUtils.java @@ -0,0 +1,151 @@ +package org.argeo.app.geo; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.StringTokenizer; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.geotools.api.feature.simple.SimpleFeature; +import org.geotools.api.feature.simple.SimpleFeatureType; +import org.geotools.data.DataUtilities; +import org.geotools.feature.SchemaException; +import org.geotools.feature.simple.SimpleFeatureBuilder; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.MultiPoint; +import org.locationtech.jts.geom.Polygon; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** Utilities around the GPX format. */ +public class GpxUtils { + /** GPX as a LineString in WGS84 (feature type with only the_geom). */ + public static final SimpleFeatureType LINESTRING_FEATURE_TYPE; + /** GPX as a Polygon in WGS84 (feature type with only the_geom). */ + public static final SimpleFeatureType POLYGON_FEATURE_TYPE; + + static { + try { + LINESTRING_FEATURE_TYPE = DataUtilities.createType("Area", "the_geom:LineString:srid=4326"); + POLYGON_FEATURE_TYPE = DataUtilities.createType("Area", "the_geom:Polygon:srid=4326"); + } catch (SchemaException e) { + throw new RuntimeException("Cannot create GPX Feature type", e); + } + } + + /** + * Converts a GPX track to either a {@link Geometry} with WGS84 coordinates + * ({@link LineString} or {@link Polygon}) or a {@link SimpleFeature} (with + * {@link #LINESTRING_FEATURE_TYPE}). + */ + @SuppressWarnings("unchecked") + public static T parseGpxTrackTo(InputStream in, Class clss) throws IOException { + GeometryFactory geometryFactory = JTS.GEOMETRY_FACTORY_WGS84; + List coordinates = new ArrayList<>(); + try { + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser saxParser = factory.newSAXParser(); + + saxParser.parse(in, new DefaultHandler() { + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if ("trkpt".equals(qName)) { + Double latitude = Double.parseDouble(attributes.getValue("lat")); + Double longitude = Double.parseDouble(attributes.getValue("lon")); + // TODO elevation in 3D context + Coordinate coordinate = new Coordinate(latitude, longitude); + coordinates.add(coordinate); + } + } + + }); + } catch (ParserConfigurationException | SAXException e) { + throw new RuntimeException("Cannot convert GPX", e); + } + + if (LineString.class.isAssignableFrom(clss)) { + LineString lineString = geometryFactory + .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); + return (T) lineString; + } else if (MultiPoint.class.isAssignableFrom(clss)) { + MultiPoint multiPoint = geometryFactory + .createMultiPointFromCoords(coordinates.toArray(new Coordinate[coordinates.size()])); + // multiPoint.normalize(); + return (T) multiPoint; + } else if (Polygon.class.isAssignableFrom(clss)) { + Coordinate first = coordinates.get(0); + Coordinate last = coordinates.get(coordinates.size() - 1); + if (!(first.getX() == last.getX() && first.getY() == last.getY())) { + // close the line string + coordinates.add(first); + } + Polygon polygon = geometryFactory.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); + return (T) polygon; + } else if (SimpleFeature.class.isAssignableFrom(clss)) { + SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(LINESTRING_FEATURE_TYPE); + LineString lineString = geometryFactory + .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); + featureBuilder.add(lineString); + SimpleFeature area = featureBuilder.buildFeature(null); + return (T) area; + } else { + throw new IllegalArgumentException("Unsupported format " + clss); + } + } + + /** @deprecated Use {@link #parseGpxTrackTo(InputStream, Class)} instead. */ + @Deprecated + public static SimpleFeature parseGpxToPolygon(InputStream in) throws IOException { + SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(POLYGON_FEATURE_TYPE); + Polygon polygon = parseGpxTrackTo(in, Polygon.class); + featureBuilder.add(polygon); + SimpleFeature area = featureBuilder.buildFeature(null); + return area; + } + + /** Write ODK GeoShape as a GPX file. */ + public static void writeGeoShapeAsGpx(String geoShape, OutputStream out) throws IOException { + Objects.requireNonNull(geoShape); + Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); + writer.append(""); + StringTokenizer stSeg = new StringTokenizer(geoShape.trim(), ";"); + while (stSeg.hasMoreTokens()) { + StringTokenizer stPt = new StringTokenizer(stSeg.nextToken().trim(), " "); + String lat = stPt.nextToken(); + String lng = stPt.nextToken(); + String alt = stPt.nextToken(); + // String precision = stPt.nextToken(); + writer.append("'); + writer.append("").append(alt).append(""); + writer.append(""); + } else { + writer.append("/>"); + } + } + writer.append(""); + writer.flush(); + } + + /** Singleton. */ + private GpxUtils() { + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/JTS.java b/org.argeo.app.geo/src/org/argeo/app/geo/JTS.java new file mode 100644 index 0000000..ba7ecf9 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/JTS.java @@ -0,0 +1,33 @@ +package org.argeo.app.geo; + +import org.argeo.api.cms.CmsLog; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.PrecisionModel; + +/** + * Factories initialisation and workarounds for the JTS library. The idea is to + * code defensively around factory initialisation, API changes, and issues + * related to running in an OSGi environment. Rather see {@link GeoUtils} for + * functional static utilities. + */ +public class JTS { + private final static CmsLog log = CmsLog.getLog(JTS.class); + + public final static int WGS84_SRID = 4326; + + /** A geometry factory with no SRID specified */ + public final static GeometryFactory GEOMETRY_FACTORY; + /** A geometry factory with SRID 4326 (WGS84 in the EPSG database) */ + public final static GeometryFactory GEOMETRY_FACTORY_WGS84; + + static { + try { + GEOMETRY_FACTORY = new GeometryFactory(); + GEOMETRY_FACTORY_WGS84 = new GeometryFactory(new PrecisionModel(), WGS84_SRID); + } catch (RuntimeException e) { + log.error("Basic JTS initialisation failed, geographical utilities are probably not available", e); + throw e; + } + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/acr/GeoEntityUtils.java b/org.argeo.app.geo/src/org/argeo/app/geo/acr/GeoEntityUtils.java new file mode 100644 index 0000000..48c3c1b --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/acr/GeoEntityUtils.java @@ -0,0 +1,159 @@ +package org.argeo.app.geo.acr; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.argeo.api.acr.Content; +import org.argeo.api.acr.ContentName; +import org.argeo.api.acr.DName; +import org.argeo.api.acr.QNamed; +import org.argeo.app.api.EntityName; +import org.argeo.app.api.EntityType; +import org.argeo.app.api.WGS84PosName; +import org.argeo.app.geo.GeoJson; +import org.argeo.app.geo.JTS; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Envelope; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryCollection; +import org.locationtech.jts.geom.Point; + +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import jakarta.json.stream.JsonGenerator; + +/** Utilities around entity types related to geography. */ +public class GeoEntityUtils { + public static final String _GEOM_JSON = ".geom.json"; + + public static void putGeometry(Content c, QNamed name, Geometry geometry) { + putGeometry(c, name.qName(), geometry); + } + + public static void putGeometry(Content c, QName name, Geometry geometry) { + QName jsonFileName = getJsonFileName(name); + Content geom = c.soleChild(jsonFileName).orElseGet( + () -> c.add(jsonFileName, Collections.singletonMap(DName.getcontenttype.qName(), "application/json"))); + try (OutputStream out = geom.open(OutputStream.class)) { + JsonGenerator g = Json.createGenerator(out); + g.writeStartObject(); + GeoJson.writeGeometry(g, geometry); + g.writeEnd(); + g.close(); + } catch (IOException e) { + throw new UncheckedIOException("Cannot add geometry " + name + " to " + c, e); + } + +// try (BufferedReader in = new BufferedReader( +// new InputStreamReader(geom.open(InputStream.class), StandardCharsets.UTF_8))) { +// System.out.println(in.readLine()); +// } catch (IOException e) { +// throw new UncheckedIOException("Cannot parse " + c, e); +// } + updateBoundingBox(c); + } + + public static boolean hasGeometry(Content c, QNamed name) { + return hasGeometry(c, name.qName()); + } + + public static boolean hasGeometry(Content c, QName name) { + QName jsonFileName = getJsonFileName(name); + return c.hasChild(jsonFileName); + } + + public static T getGeometry(Content c, QNamed name, Class clss) { + return getGeometry(c, name.qName(), clss); + } + + public static T getGeometry(Content c, QName name, Class clss) { + QName jsonFileName = getJsonFileName(name); + Content geom = c.soleChild(jsonFileName).orElse(null); + if (geom == null) + return null; + try (Reader in = new InputStreamReader(geom.open(InputStream.class), StandardCharsets.UTF_8)) { + JsonReader jsonReader = Json.createReader(in); + JsonObject jsonObject = jsonReader.readObject(); + T readGeom = GeoJson.readGeometry(jsonObject, clss); + return readGeom; + } catch (IOException e) { + throw new UncheckedIOException("Cannot parse " + c, e); + } + } + + private static QName getJsonFileName(QName name) { + QName jsonFileName = new ContentName(name.getNamespaceURI(), name.getLocalPart() + _GEOM_JSON); + return jsonFileName; + } + + public static Point toPoint(Content c) { + if (c.containsKey(WGS84PosName.lon) && c.containsKey(WGS84PosName.lat)) { + Double lat = c.get(WGS84PosName.lat, Double.class).orElseThrow(); + Double lon = c.get(WGS84PosName.lon, Double.class).orElseThrow(); + return JTS.GEOMETRY_FACTORY_WGS84.createPoint(new Coordinate(lat, lon)); +// Double alt = c.get(WGS84PosName.alt, Double.class).orElse(null); +// return JTS.GEOMETRY_FACTORY_WGS84 +// .createPoint(alt != null ? new Coordinate(lat, lon, alt) : new Coordinate(lat, lon)); + } + return null; + } + + public static GeometryCollection getGeometries(Content entity) { + List geoms = new ArrayList<>(); + Point geoPoint = toPoint(entity); + if (geoPoint != null) + geoms.add(geoPoint); + + Geometry place = getGeometry(entity, EntityName.place.qName(), Geometry.class); + if (place != null) + geoms.add(place); + + if (geoms.isEmpty()) + return null; + GeometryCollection geometryCollection = JTS.GEOMETRY_FACTORY_WGS84 + .createGeometryCollection(geoms.toArray(new Geometry[geoms.size()])); + return geometryCollection; + } + + public static void updateBoundingBox(Content entity) { + GeometryCollection geometryCollection = getGeometries(entity); + if (geometryCollection == null) + return; + entity.addContentClasses(EntityType.geobounded.qName()); + + Envelope bbox = geometryCollection.getEnvelopeInternal(); + entity.put(EntityName.minLat, bbox.getMinX()); + entity.put(EntityName.minLon, bbox.getMinY()); + entity.put(EntityName.maxLat, bbox.getMaxX()); + entity.put(EntityName.maxLon, bbox.getMaxY()); + } + + public static void updateBoundingBox(Content entity, QName prop) { + Geometry geom = getGeometry(entity, prop, Geometry.class); + if (geom == null) + return; + entity.addContentClasses(EntityType.geobounded.qName()); + + Envelope bbox = geom.getEnvelopeInternal(); + entity.put(EntityName.minLat, bbox.getMinX()); + entity.put(EntityName.minLon, bbox.getMinY()); + entity.put(EntityName.maxLat, bbox.getMaxX()); + entity.put(EntityName.maxLon, bbox.getMaxY()); + } + + /** singleton */ + private GeoEntityUtils() { + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/geonames/GeonamesAdm.java b/org.argeo.app.geo/src/org/argeo/app/geo/geonames/GeonamesAdm.java new file mode 100644 index 0000000..45febd2 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/geonames/GeonamesAdm.java @@ -0,0 +1,157 @@ +package org.argeo.app.geo.geonames; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** A Geonames administrative subdivision. */ +public class GeonamesAdm { + private final Long geonameId; + private final String countryCode; + private final String adminCode1; + private final String admLevel; + private final Integer level; + private final String name; + private final String asciiName; + private final List alternateNames; + private final Double lat; + private final Double lng; + private final LocalDate lastUpdated; + private final ZoneId timeZone; + + private final Long[] upperLevelIds = new Long[5]; + private final List upperLevels = new ArrayList<>(); + + private List row; + + /** Initialise from a row in the main Geonames table. */ + public GeonamesAdm(List row) { + geonameId = Long.parseLong(row.get(0)); + admLevel = row.get(7); + countryCode = row.get(8); + adminCode1 = row.get(10); + if (admLevel.startsWith("ADM")) { + if (admLevel.endsWith("H")) + level = Integer.parseInt(admLevel.substring(3, admLevel.length() - 1)); + else + level = Integer.parseInt(admLevel.substring(3)); + } else if (admLevel.equals("PCLI")) { + level = 0; + } else { + throw new IllegalArgumentException("Unsupported admin level " + admLevel); + } + name = row.get(1); + asciiName = row.get(2); + alternateNames = Arrays.asList(row.get(3).split(",")); + lat = Double.parseDouble(row.get(4)); + lng = Double.parseDouble(row.get(5)); + lastUpdated = LocalDate.parse(row.get(18)); + timeZone = ZoneId.of(row.get(17)); + // upper levels + if (row.get(11) != null && !row.get(11).trim().equals("")) + upperLevelIds[2] = Long.parseLong(row.get(11)); + if (row.get(12) != null && !row.get(12).trim().equals("")) + upperLevelIds[3] = Long.parseLong(row.get(12)); + if (row.get(13) != null && !row.get(13).trim().equals("")) + upperLevelIds[4] = Long.parseLong(row.get(13)); + this.row = row; + } + + public void mapUpperLevels(Map index) { + for (int i = 0; i < level; i++) { + Long geonameId = upperLevelIds[i]; + upperLevels.add(i, index.get(geonameId)); + } + } + + public Long getGeonameId() { + return geonameId; + } + + public Integer getLevel() { + return level; + } + + public String getName() { + return name; + } + + public String getName(Function transform) { + if (transform != null) + return transform.apply(name); + else + return name; + + } + + public String getAsciiName() { + return asciiName; + } + + public List getAlternateNames() { + return alternateNames; + } + + public Double getLat() { + return lat; + } + + public Double getLng() { + return lng; + } + + public String getCountryCode() { + return countryCode; + } + + public String getAdmLevel() { + return admLevel; + } + + public List getRow() { + return row; + } + + public LocalDate getLastUpdated() { + return lastUpdated; + } + + public ZoneId getTimeZone() { + return timeZone; + } + + public String getAdminCode1() { + return adminCode1; + } + + public Long[] getUpperLevelIds() { + return upperLevelIds; + } + + public List getUpperLevels() { + return upperLevels; + } + + @Override + public int hashCode() { + return geonameId.intValue(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof GeonamesAdm)) + return false; + GeonamesAdm other = (GeonamesAdm) obj; + return geonameId.equals(other.geonameId); + } + + @Override + public String toString() { + return name + " (ADM" + level + " " + geonameId + ")"; + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java b/org.argeo.app.geo/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java new file mode 100644 index 0000000..be2b507 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/geonames/ImportGeonamesAdmin.java @@ -0,0 +1,93 @@ +package org.argeo.app.geo.geonames; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.argeo.cms.util.CsvParser; +import org.argeo.cms.util.CsvWriter; + +/** Import GeoNames administrative division from the main table. */ +public class ImportGeonamesAdmin { + // private Log log = LogFactory.getLog(ImportGeonamesAdmin.class); + private Map geonamesAdms = new HashMap<>(); + + /** Loads the data. */ + public void parse(InputStream in) { + Map countryGeonameIds = new HashMap<>(); + Map admin1GeonameIds = new HashMap<>(); + CsvParser csvParser = new CsvParser() { + + @Override + protected void processLine(Integer lineNumber, List header, List tokens) { + if (!"A".equals(tokens.get(6))) + return; + GeonamesAdm geonamesAdm = new GeonamesAdm(tokens); + geonamesAdms.put(geonamesAdm.getGeonameId(), geonamesAdm); + if (geonamesAdm.getAdmLevel().equals("PCLI")) + countryGeonameIds.put(geonamesAdm.getCountryCode(), geonamesAdm.getGeonameId()); + if (geonamesAdm.getAdmLevel().equals("ADM1")) + admin1GeonameIds.put(geonamesAdm.getAdminCode1(), geonamesAdm.getGeonameId()); + } + }; + csvParser.setSeparator('\t'); + csvParser.setNoHeader(true); + csvParser.parse(in, StandardCharsets.UTF_8); + + // fill upper levels + for (GeonamesAdm adm : geonamesAdms.values()) { + adm.getUpperLevelIds()[0] = countryGeonameIds.get(adm.getCountryCode()); + if (adm.getLevel() > 0) + adm.getUpperLevelIds()[1] = admin1GeonameIds.get(adm.getAdminCode1()); + adm.mapUpperLevels(geonamesAdms); + } + + } + + public Map getGeonamesAdms() { + return geonamesAdms; + } + + /** + * Copies only the Geonames of feature class 'A' (administrative subdivisions). + */ + public static void filterGeonamesAdm(InputStream in, OutputStream out) { + CsvWriter csvWriter = new CsvWriter(out, StandardCharsets.UTF_8); + csvWriter.setSeparator('\t'); + CsvParser csvParser = new CsvParser() { + + @Override + protected void processLine(Integer lineNumber, List header, List tokens) { + if (tokens.size() < 7 || !"A".equals(tokens.get(6))) + return; + csvWriter.writeLine(tokens); + } + }; + csvParser.setSeparator('\t'); + csvParser.setNoHeader(true); + csvParser.parse(in, StandardCharsets.UTF_8); + } + + public static void main(String[] args) throws IOException { +// String country = "allCountries"; + String country = "CI"; +// try (InputStream in = Files +// .newInputStream(Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + ".txt")); +// OutputStream out = Files.newOutputStream( +// Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) { +// ImportGeonamesAdmin.filterGeonamesAdm(in, out); +// } + try (InputStream in = Files.newInputStream( + Paths.get(System.getProperty("user.home") + "/gis/data/geonames/" + country + "-adm.txt"))) { + ImportGeonamesAdmin importGeonamesAdmin = new ImportGeonamesAdmin(); + importGeonamesAdmin.parse(in); + } + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsHttpHandler.java b/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsHttpHandler.java new file mode 100644 index 0000000..c12a77b --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsHttpHandler.java @@ -0,0 +1,508 @@ +package org.argeo.app.geo.http; + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import javax.xml.namespace.QName; + +import org.argeo.api.acr.Content; +import org.argeo.api.acr.ContentSession; +import org.argeo.api.acr.NamespaceUtils; +import org.argeo.api.acr.ldap.LdapAttr; +import org.argeo.api.acr.search.AndFilter; +import org.argeo.api.acr.spi.ProvidedRepository; +import org.argeo.api.cms.CmsLog; +import org.argeo.app.api.EntityName; +import org.argeo.app.api.EntityType; +import org.argeo.app.api.WGS84PosName; +import org.argeo.app.api.geo.FeatureAdapter; +import org.argeo.app.api.geo.WfsKvp; +import org.argeo.app.geo.CqlUtils; +import org.argeo.app.geo.GeoJson; +import org.argeo.app.geo.GeoUtils; +import org.argeo.app.geo.GpxUtils; +import org.argeo.app.geo.JTS; +import org.argeo.app.geo.acr.GeoEntityUtils; +import org.argeo.cms.acr.json.AcrJsonUtils; +import org.argeo.cms.auth.RemoteAuthUtils; +import org.argeo.cms.http.HttpHeader; +import org.argeo.cms.http.RemoteAuthHttpExchange; +import org.argeo.cms.http.server.HttpServerUtils; +import org.argeo.cms.util.LangUtils; +import org.geotools.api.feature.GeometryAttribute; +import org.geotools.api.feature.simple.SimpleFeature; +import org.geotools.api.feature.simple.SimpleFeatureType; +import org.geotools.api.feature.type.AttributeDescriptor; +import org.geotools.api.feature.type.Name; +import org.geotools.api.referencing.FactoryException; +import org.geotools.api.referencing.crs.CoordinateReferenceSystem; +import org.geotools.api.referencing.operation.MathTransform; +import org.geotools.api.referencing.operation.TransformException; +import org.geotools.feature.DefaultFeatureCollection; +import org.geotools.feature.NameImpl; +import org.geotools.feature.simple.SimpleFeatureBuilder; +import org.geotools.referencing.CRS; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.geotools.wfs.GML; +import org.geotools.wfs.GML.Version; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Envelope; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.Polygon; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import jakarta.json.Json; +import jakarta.json.stream.JsonGenerator; + +/** A partially implemented WFS 2.0 server. */ +public class WfsHttpHandler implements HttpHandler { + private final static CmsLog log = CmsLog.getLog(WfsHttpHandler.class); + private ProvidedRepository contentRepository; + + private final Map featureAdapters = new HashMap<>(); + + @Override + public void handle(HttpExchange exchange) throws IOException { + ContentSession session = HttpServerUtils.getContentSession(contentRepository, exchange); + + String path = HttpServerUtils.subPath(exchange); + + // content path + final String pathToUse = path; + String fileName = null; + boolean zipped = false; +// int lastSlash = path.lastIndexOf('/'); +// if (lastSlash > 0) { +// fileName = path.substring(lastSlash + 1); +// } +// if (fileName != null) { +// pathToUse = path.substring(0, lastSlash); +// if (path.endsWith(".zip")) { +// zipped = true; +// } +// } else { +// pathToUse = path; +// } + + Map> parameters = HttpServerUtils.parseParameters(exchange); + + // PARAMETERS + String cql = getKvpParameter(parameters, WfsKvp.CQL_FILTER); + String typeNamesStr = getKvpParameter(parameters, WfsKvp.TYPE_NAMES); + String outputFormat = getKvpParameter(parameters, WfsKvp.OUTPUT_FORMAT); + if (outputFormat == null) { + outputFormat = "application/json"; + } + + // TODO deal with multiple + String formatOption = getKvpParameter(parameters, WfsKvp.FORMAT_OPTIONS); + if (formatOption != null) { + if (formatOption.startsWith(WfsKvp.FILENAME_)) + fileName = formatOption.substring(WfsKvp.FILENAME_.length()); + } + if (fileName != null && fileName.endsWith(".zip")) + zipped = true; + + // bbox + String bboxStr = getKvpParameter(parameters, WfsKvp.BBOX); + if (log.isTraceEnabled()) + log.trace(bboxStr); + final Envelope bbox; + if (bboxStr != null) { + String srs; + String[] arr = bboxStr.split(","); + // TODO check SRS and convert to WGS84 + double minLat = Double.parseDouble(arr[0]); + double minLon = Double.parseDouble(arr[1]); + double maxLat = Double.parseDouble(arr[2]); + double maxLon = Double.parseDouble(arr[3]); + if (arr.length == 5) { + srs = arr[4]; + } else { + srs = null; + } + + if (srs != null && !srs.equals(GeoUtils.EPSG_4326)) { + try { + // TODO optimise + CoordinateReferenceSystem sourceCRS = CRS.decode(srs); + CoordinateReferenceSystem targetCRS = CRS.decode(GeoUtils.EPSG_4326); + MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true); + bbox = org.geotools.geometry.jts.JTS.transform( + new Envelope(new Coordinate(minLat, minLon), new Coordinate(maxLat, maxLon)), transform); + } catch (FactoryException | TransformException e) { + throw new IllegalArgumentException("Cannot convert bounding box", e); + // bbox = null; + } + } else { + bbox = new Envelope(new Coordinate(minLat, minLon), new Coordinate(maxLat, maxLon)); + } + } else { + bbox = null; + } + + // response headers + exchange.getResponseHeaders().set(HttpHeader.DATE.getHeaderName(), Long.toString(System.currentTimeMillis())); + + if (fileName != null) { + exchange.getResponseHeaders().set(HttpHeader.CONTENT_DISPOSITION.getHeaderName(), + HttpHeader.ATTACHMENT + ";" + HttpHeader.FILENAME + "=\"" + fileName + "\""); + + } + + // content type + if (zipped) { + exchange.getResponseHeaders().set(HttpHeader.CONTENT_TYPE.getHeaderName(), "application/zip"); + + } else { + switch (outputFormat) { + case "application/json" -> { + exchange.getResponseHeaders().set(HttpHeader.CONTENT_TYPE.getHeaderName(), "application/json"); + } + case "GML3" -> { +// exchange.getResponseHeaders().set(HttpHeader.CONTENT_TYPE.getHeaderName(), "application/gml+xml"); + exchange.getResponseHeaders().set(HttpHeader.CONTENT_TYPE.getHeaderName(), "application/xml"); + } + + default -> throw new IllegalArgumentException("Unexpected value: " + outputFormat); + } + } + + List typeNames = new ArrayList<>(); + if (typeNamesStr != null) { + String[] arr = typeNamesStr.split(","); + for (int i = 0; i < arr.length; i++) { + typeNames.add(NamespaceUtils.parsePrefixedName(arr[i])); + } + } else { + typeNames.add(EntityType.local.qName()); + } + + if (typeNames.size() > 1) + throw new UnsupportedOperationException("Only one type name is currently supported"); + + // QUERY + Stream res = session.search((search) -> { + if (cql != null) { + CqlUtils.filter(search.from(pathToUse), cql); + } else { + search.from(pathToUse); + } + for (QName typeName : typeNames) { + FeatureAdapter featureAdapter = featureAdapters.get(typeName); + if (featureAdapter == null) + throw new IllegalStateException("No feature adapter found for " + typeName); + // f.isContentClass(typeName); + RemoteAuthUtils.doAs(() -> { + featureAdapter.addConstraintsForFeature((AndFilter) search.getWhere(), typeName); + return null; + }, new RemoteAuthHttpExchange(exchange)); + } + + if (bbox != null) { + search.getWhere().any((or) -> { + // box overlap, see https://stackoverflow.com/questions/20925818/algorithm-to-check-if-two-boxes-overlap + // isOverlapping = (x1min < x2max AND x2min < x1max AND y1min < y2max AND y2min < y1max) + // x1 = entity, x2 = bbox + or.all((and) -> { + and.lte(EntityName.minLat, bbox.getMaxX()); + and.gte(EntityName.maxLat, bbox.getMinX()); + and.lte(EntityName.minLon, bbox.getMaxY()); + and.gte(EntityName.maxLon, bbox.getMinY()); + }); + or.all((and) -> { + and.gte(WGS84PosName.lat, bbox.getMinX()); + and.gte(WGS84PosName.lon, bbox.getMinY()); + and.lte(WGS84PosName.lat, bbox.getMaxX()); + and.lte(WGS84PosName.lon, bbox.getMaxY()); + }); + }); + } + }); + + exchange.sendResponseHeaders(200, 0); + + final int BUFFER_SIZE = 100 * 1024; + try (OutputStream out = zipped ? new ZipOutputStream(exchange.getResponseBody()) + : new BufferedOutputStream(exchange.getResponseBody(), BUFFER_SIZE)) { + if (out instanceof ZipOutputStream zipOut) { + String unzippedFileName = fileName.substring(0, fileName.length() - ".zip".length()); + zipOut.putNextEntry(new ZipEntry(unzippedFileName)); + } + + if ("GML3".equals(outputFormat)) { + encodeCollectionAsGML(res, out); + } else if ("application/json".equals(outputFormat)) { + encodeCollectionAsGeoJSon(res, out, typeNames); + } + } + } + + /** + * Retrieve KVP (keyword-value pairs) parameters, which are lower case, as per + * specifications. + * + * @see https://docs.ogc.org/is/09-025r2/09-025r2.html#19 + */ + protected String getKvpParameter(Map> parameters, WfsKvp key) { + Objects.requireNonNull(key, "KVP key cannot be null"); + // let's first try the default (CAML case) which should be more efficient + List values = parameters.get(key.getKey()); + if (values == null) { + // then let's do an ignore case comparison of the key + keys: for (String k : parameters.keySet()) { + if (key.getKey().equalsIgnoreCase(k)) { + values = parameters.get(k); + break keys; + } + } + } + if (values == null) // nothing was found + return null; + if (values.size() != 1) { + // although not completely clear from the standard, we assume keys must be + // unique + // since lists are defined here + // https://docs.ogc.org/is/09-026r2/09-026r2.html#10 + throw new IllegalArgumentException("Key " + key + " as multiple values"); + } + String value = values.get(0); + assert value != null; + return value; + } + + protected void encodeCollectionAsGeoJSon(Stream features, OutputStream out, List typeNames) + throws IOException { + long begin = System.currentTimeMillis(); + AtomicLong count = new AtomicLong(0); + JsonGenerator generator = Json.createGenerator(out); + generator.writeStartObject(); + generator.write("type", "FeatureCollection"); + generator.writeStartArray("features"); + features.forEach((c) -> { + // TODO deal with multiple type names + FeatureAdapter featureAdapter = null; + QName typeName = null; + if (!typeNames.isEmpty()) { + typeName = typeNames.get(0); + featureAdapter = featureAdapters.get(typeName); + } + + boolean geometryWritten = false; +// if (typeName.getLocalPart().equals("fieldSimpleFeature")) { +// Content area = c.getContent("place.geom.json").orElse(null); +// if (area != null) { +// generator.writeStartObject(); +// generator.write("type", "Feature"); +// String featureId = getFeatureId(c); +// if (featureId != null) +// generator.write("id", featureId); +// +// generator.flush(); +// try (InputStream in = area.open(InputStream.class)) { +// out.write(",\"geometry\":".getBytes()); +// StreamUtils.copy(in, out); +// //out.flush(); +// } catch (Exception e) { +// log.error(c.getPath() + " : " + e.getMessage()); +// } finally { +// } +// geometryWritten = true; +// }else { +// return; +// } +// } + + if (!geometryWritten) { + + Geometry defaultGeometry = featureAdapter != null ? featureAdapter.getDefaultGeometry(c, typeName) + : getDefaultGeometry(c); + if (defaultGeometry == null) + return; + generator.writeStartObject(); + generator.write("type", "Feature"); + String featureId = getFeatureId(c); + if (featureId != null) + generator.write("id", featureId); + + GeoJson.writeBBox(generator, defaultGeometry); + generator.writeStartObject(GeoJson.GEOMETRY); + GeoJson.writeGeometry(generator, defaultGeometry); + generator.writeEnd();// geometry object + } + generator.writeStartObject(GeoJson.PROPERTIES); + AcrJsonUtils.writeTimeProperties(generator, c); + if (featureAdapter != null) + featureAdapter.writeProperties(generator, c, typeName); + else + writeProperties(generator, c); + generator.writeEnd();// properties object + + generator.writeEnd();// feature object + + if (count.incrementAndGet() % 10 == 0) + try { + out.flush(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + generator.writeEnd();// features array + generator.writeEnd().close(); + + log.debug("GeoJSon encoding took " + (System.currentTimeMillis() - begin) + " ms."); + } + + protected Geometry getDefaultGeometry(Content content) { + if (content.hasContentClass(EntityType.geopoint)) { + return GeoEntityUtils.toPoint(content); + } + return null; + } + + protected String getFeatureId(Content content) { + String uuid = content.attr(LdapAttr.entryUUID); + return uuid; + } + + public void writeProperties(JsonGenerator generator, Content content) { + String path = content.getPath(); + generator.write("path", path); + if (content.hasContentClass(EntityType.local)) { + String type = content.attr(EntityName.type); + generator.write("type", type); + } else { + List contentClasses = content.getContentClasses(); + if (!contentClasses.isEmpty()) { + generator.write("type", NamespaceUtils.toPrefixedName(contentClasses.get(0))); + } + } + + } + + protected void encodeCollectionAsGML(Stream features, OutputStream out) throws IOException { + String entityType = "entity"; + URL schemaLocation = getClass().getResource("/org/argeo/app/api/entity.xsd"); + String namespace = "http://www.argeo.org/ns/entity"; + + GML gml = new GML(Version.WFS1_1); + gml.setCoordinateReferenceSystem(DefaultGeographicCRS.WGS84); + gml.setNamespace("local", namespace); + + SimpleFeatureType featureType = gml.decodeSimpleFeatureType(schemaLocation, + new NameImpl(namespace, entityType + "Feature")); + +// CoordinateReferenceSystem crs=DefaultGeographicCRS.WGS84; +// QName featureName = new QName(namespace,"apafFieldFeature"); +// GMLConfiguration configuration = new GMLConfiguration(); +// FeatureType parsed = GTXML.parseFeatureType(configuration, featureName, crs); +// SimpleFeatureType featureType = DataUtilities.simple(parsed); + + SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType); + + DefaultFeatureCollection featureCollection = new DefaultFeatureCollection(); + + features.forEach((c) -> { +// boolean gpx = false; + Geometry the_geom = null; + Polygon the_area = null; +// if (gpx) { + Content area = c.getContent("gpx/area.gpx").orElse(null); + if (area != null) { + + try (InputStream in = area.open(InputStream.class)) { + the_area = GpxUtils.parseGpxTrackTo(in, Polygon.class); + } catch (IOException e) { + throw new UncheckedIOException("Cannot parse " + c, e); + } + } +// } else { + if (c.hasContentClass(EntityType.geopoint)) { + double latitude = c.get(WGS84PosName.lat, Double.class).get(); + double longitude = c.get(WGS84PosName.lon, Double.class).get(); + + Coordinate coordinate = new Coordinate(longitude, latitude); + the_geom = JTS.GEOMETRY_FACTORY.createPoint(coordinate); + } + +// } + if (the_geom != null) + featureBuilder.set(new NameImpl(namespace, "geopoint"), the_geom); + if (the_area != null) + featureBuilder.set(new NameImpl(namespace, "area"), the_area); + + List attrDescs = featureType.getAttributeDescriptors(); + for (AttributeDescriptor attrDesc : attrDescs) { + if (attrDesc instanceof GeometryAttribute) + continue; + Name name = attrDesc.getName(); + QName qName = new QName(name.getNamespaceURI(), name.getLocalPart()); + String value = c.attr(qName); + if (value == null) { + value = c.attr(name.getLocalPart()); + } + if (value != null) { + featureBuilder.set(name, value); + } + } + + String uuid = c.attr(LdapAttr.entryUUID); + + SimpleFeature feature = featureBuilder.buildFeature(uuid); + featureCollection.add(feature); + + }); + gml.encode(out, featureCollection); + out.close(); + + } + + /* + * DEPENDENCY INJECTION + */ + + public void addFeatureAdapter(FeatureAdapter featureAdapter, Map properties) { + List typeNames = LangUtils.toStringList(properties.get(WfsKvp.TYPE_NAMES.getKey())); + if (typeNames.isEmpty()) { + log.warn("FeatureAdapter " + featureAdapter.getClass() + " does not declare type names. Ignoring it..."); + return; + } + + for (String tn : typeNames) { + QName typeName = NamespaceUtils.parsePrefixedName(tn); + featureAdapters.put(typeName, featureAdapter); + } + } + + public void removeFeatureAdapter(FeatureAdapter featureAdapter, Map properties) { + List typeNames = LangUtils.toStringList(properties.get(WfsKvp.TYPE_NAMES.getKey())); + if (!typeNames.isEmpty()) { + // ignore if noe type name declared + return; + } + + for (String tn : typeNames) { + QName typeName = NamespaceUtils.parsePrefixedName(tn); + featureAdapters.remove(typeName); + } + } + + public void setContentRepository(ProvidedRepository contentRepository) { + this.contentRepository = contentRepository; + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsUtils.java b/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsUtils.java new file mode 100644 index 0000000..f9876d9 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/http/WfsUtils.java @@ -0,0 +1,16 @@ +package org.argeo.app.geo.http; + +import javax.xml.namespace.NamespaceContext; + +/** Utilities around the WFS specifications. */ +public class WfsUtils { + + public static NamespaceContext parseNamespacesKvpParameter() { + // TODO deal with multiple namespaces + return null; + } + + /** singleton */ + private WfsUtils() { + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/ux/AbstractGeoJsObject.java b/org.argeo.app.geo/src/org/argeo/app/geo/ux/AbstractGeoJsObject.java new file mode 100644 index 0000000..63b9351 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/ux/AbstractGeoJsObject.java @@ -0,0 +1,17 @@ +package org.argeo.app.geo.ux; + +import org.argeo.app.ux.js.AbstractJsObject; + +public class AbstractGeoJsObject extends AbstractJsObject { + public final static String ARGEO_APP_GEO_JS_URL = "/pkg/org.argeo.app.js/geo.html"; + public final static String JS_PACKAGE = "argeo.app.geo"; + + public AbstractGeoJsObject(Object... args) { + super(args); + } + + @Override + public String getJsPackage() { + return JS_PACKAGE; + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/ux/BboxVectorSource.java b/org.argeo.app.geo/src/org/argeo/app/geo/ux/BboxVectorSource.java new file mode 100644 index 0000000..fa0656c --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/ux/BboxVectorSource.java @@ -0,0 +1,26 @@ +package org.argeo.app.geo.ux; + +import org.argeo.app.ol.FeatureFormat; +import org.argeo.app.ol.VectorSource; + +public class BboxVectorSource extends VectorSource { + + public BboxVectorSource(Object... args) { + super(args); + } + + public BboxVectorSource(String baseUrl, FeatureFormat format) { + setFormat(format); + setBaseUrl(baseUrl); + } + + @Override + public String getJsPackage() { + return AbstractGeoJsObject.JS_PACKAGE; + } + + public void setBaseUrl(String baseUrl) { + doSetValue(null, "baseUrl", baseUrl); + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/ux/MapPart.java b/org.argeo.app.geo/src/org/argeo/app/geo/ux/MapPart.java new file mode 100644 index 0000000..8d5da7e --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/ux/MapPart.java @@ -0,0 +1,18 @@ +package org.argeo.app.geo.ux; + +/** An UX part displaying a map. */ +public interface MapPart { + void setCenter(double lng, double lat); + + /** Event when a feature has been single-clicked. */ + record FeatureSingleClickEvent(String path) { + }; + + /** Event when a feature has been selected. */ + record FeatureSelectedEvent(String path) { + }; + + /** Event when a feature popup is requested. */ + record FeaturePopupEvent(String path) { + }; +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/ux/OpenLayersMapPart.java b/org.argeo.app.geo/src/org/argeo/app/geo/ux/OpenLayersMapPart.java new file mode 100644 index 0000000..0d99f40 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/ux/OpenLayersMapPart.java @@ -0,0 +1,107 @@ +package org.argeo.app.geo.ux; + +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.argeo.app.ol.AbstractOlObject; +import org.argeo.app.ol.Layer; +import org.argeo.app.ol.OlMap; +import org.argeo.app.ol.TileLayer; +import org.argeo.app.ol.VectorLayer; +import org.argeo.app.ux.js.JsClient; +import org.locationtech.jts.geom.Envelope; + +/** + * A wrapper around an OpenLayers map, adding specific features, such as SLD + * styling. + */ +public class OpenLayersMapPart extends AbstractGeoJsObject implements MapPart { + private final String mapPartName; + + public OpenLayersMapPart(JsClient jsClient, String mapPartName) { + super(mapPartName); + this.mapPartName = mapPartName; + create(jsClient, mapPartName); + } + + public OlMap getMap() { + return new OlMap(getJsClient(), getReference() + ".getMap()"); + } + + public void setSld(String xml) { + executeMethod(getMethodName(), JsClient.escapeQuotes(xml)); + } + + public void setCenter(double lat, double lon) { + executeMethod(getMethodName(), lat, lon); + } + + public void fit(double[] extent, Map options) { + executeMethod(getMethodName(), extent, options); + } + + public void fit(Envelope extent, Map options) { + fit(new double[] { extent.getMinX(), extent.getMinY(), extent.getMaxX(), extent.getMaxY() }, options); + } + + public void applyStyle(String layerName, String styledLayerName) { + executeMethod(getMethodName(), layerName, styledLayerName); + } + + public Layer getLayer(String name) { + // TODO deal with not found + String reference = getReference() + ".getLayerByName('" + name + "')"; + if (getJsClient().isInstanceOf(reference, AbstractOlObject.getJsClassName(VectorLayer.class))) { + return new VectorLayer(getJsClient(), reference); + } else if (getJsClient().isInstanceOf(reference, AbstractOlObject.getJsClassName(TileLayer.class))) { + return new TileLayer(getJsClient(), reference); + } else { + return new Layer(getJsClient(), reference); + } + } + + public String getMapPartName() { + return mapPartName; + } + + public void selectFeatures(String layerName, Object... ids) { + executeMethod(getMethodName(), layerName, (Object[]) ids); + } + + public void fitToLayer(String layerName) { + executeMethod(getMethodName(), layerName); + } + + /* + * CALLBACKS + */ + public void onFeatureSelected(Consumer toDo) { + addCallback("FeatureSelected", (arr) -> { + toDo.accept(new FeatureSelectedEvent((String) arr[0])); + return null; + }); + } + + public void onFeatureSingleClick(Consumer toDo) { + addCallback("FeatureSingleClick", (arr) -> { + toDo.accept(new FeatureSingleClickEvent((String) arr[0])); + return null; + }); + } + + public void onFeaturePopup(Function toDo) { + addCallback("FeaturePopup", (arr) -> { + return toDo.apply(new FeaturePopupEvent((String) arr[0])); + }); + } + + protected void addCallback(String suffix, Function toDo) { + getJsClient().getReadyStage().thenAccept((ready) -> { + String functionName = getJsClient().createJsFunction(getMapPartName() + "__on" + suffix, toDo); + getJsClient().execute(getJsReference() + ".callbacks['on" + suffix + "']=" + functionName + ";"); + executeMethod("enable" + suffix); + }); + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/geo/ux/SentinelCloudless.java b/org.argeo.app.geo/src/org/argeo/app/geo/ux/SentinelCloudless.java new file mode 100644 index 0000000..36dcfe1 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/geo/ux/SentinelCloudless.java @@ -0,0 +1,16 @@ +package org.argeo.app.geo.ux; + +import org.argeo.app.ol.Source; + +public class SentinelCloudless extends Source { + + public SentinelCloudless(Object... args) { + super(args); + } + + @Override + public String getJsPackage() { + return "argeo.app.geo"; + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/AbstractOlObject.java b/org.argeo.app.geo/src/org/argeo/app/ol/AbstractOlObject.java new file mode 100644 index 0000000..db64d96 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/AbstractOlObject.java @@ -0,0 +1,76 @@ +package org.argeo.app.ol; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.argeo.app.ux.js.AbstractJsObject; + +public abstract class AbstractOlObject extends AbstractJsObject { + public final static String JS_PACKAGE = "argeo.tp.ol"; + + public AbstractOlObject(Object... args) { + super(args.length > 0 ? args : new Object[] { new HashMap() }); + } + +// public AbstractOlObject(Map options) { +// super(new Object[] { options }); +// } + + public String getJsPackage() { + return JS_PACKAGE; + } + + @SuppressWarnings("unchecked") + protected Map getNewOptions() { + if (!isNew()) + throw new IllegalStateException("Object " + getJsClassName() + " is not new"); + Object[] args = getJsConstructorArgs(); + if (args.length != 1 || !(args[0] instanceof Map)) + throw new IllegalStateException("Object " + getJsClassName() + " has no available options"); + return (Map) args[0]; + } + + protected void doSetValue(String methodName, String newOption, Object value) { + if (isNew()) { + Objects.requireNonNull(newOption, "Value cannot be set as an option for " + getJsClassName() + ", use " + + methodName + "() after the object has been created"); + getNewOptions().put(newOption, value); + } else { + Objects.requireNonNull(methodName, "Value cannot be set via a method for " + getJsClassName() + ", use " + + newOption + " before the object is created"); + executeMethod(methodName, value); + } + } + + public void set(String key, Object value) { + set(key, value, false); + } + + public void set(String key, Object value, boolean silent) { + if (isNew()) { + getNewOptions().put(key, value); + } else { + executeMethod(getMethodName(), new Object[] { key, value, silent }); + } + } + + public Object get(String key) { + if (isNew()) { + return getNewOptions().get(key); + } else { + // TDO deal with reference if we are trying to get an object + return callMethod(getMethodName(), key); + } + + } + + public static String getJsClassName(Class clss) { + if (AbstractOlObject.class.isAssignableFrom(clss)) { + // NB: would failed for renamed classes + return JS_PACKAGE + "." + clss.getSimpleName(); + } + throw new IllegalArgumentException(clss + " is not an OpenLayers object"); + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/FeatureFormat.java b/org.argeo.app.geo/src/org/argeo/app/ol/FeatureFormat.java new file mode 100644 index 0000000..2d0f8bc --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/FeatureFormat.java @@ -0,0 +1,9 @@ +package org.argeo.app.ol; + +public abstract class FeatureFormat extends AbstractOlObject { + + public FeatureFormat(Object... args) { + super(args); + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/GeoJSON.java b/org.argeo.app.geo/src/org/argeo/app/ol/GeoJSON.java new file mode 100644 index 0000000..3cab7bc --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/GeoJSON.java @@ -0,0 +1,9 @@ +package org.argeo.app.ol; + +public class GeoJSON extends FeatureFormat { + + public GeoJSON(Object... args) { + super(args); + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/Layer.java b/org.argeo.app.geo/src/org/argeo/app/ol/Layer.java new file mode 100644 index 0000000..feb0700 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/Layer.java @@ -0,0 +1,60 @@ +package org.argeo.app.ol; + +import java.util.Objects; + +public class Layer extends AbstractOlObject { + public final static String NAME_KEY = "name"; + + // cached + private String name; + + public Layer(Object... args) { + super(args); + } + + public void setOpacity(double opacity) { + if (opacity < 0 || opacity > 1) + throw new IllegalArgumentException("Opacity must be between 0 and 1"); +// if (isNew()) +// getNewOptions().put("opacity", opacity); +// else +// executeMethod(getMethodName(), opacity); + doSetValue(getMethodName(), "opacity", opacity); + } + + public void setSource(Source source) { + Objects.requireNonNull(source); + if (isNew()) + getNewOptions().put("source", source); + else + executeMethod(getMethodName(), source); + } + + public Source getSource() { + String reference = getReference() + ".getSource()"; + return new Source(getJsClient(), reference); + } + + public void setMinResolution(double minResolution) { + if (isNew()) + getNewOptions().put("minResolution", minResolution); + else + executeMethod(getMethodName(), minResolution); + } + + public void setMaxResolution(double maxResolution) { + if (isNew()) + getNewOptions().put("maxResolution", maxResolution); + else + executeMethod(getMethodName(), maxResolution); + } + + public void setName(String name) { + set(NAME_KEY, name); + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/OSM.java b/org.argeo.app.geo/src/org/argeo/app/ol/OSM.java new file mode 100644 index 0000000..6cc769f --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/OSM.java @@ -0,0 +1,9 @@ +package org.argeo.app.ol; + +public class OSM extends Source { + + public OSM(Object... args) { + super(args); + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/OlMap.java b/org.argeo.app.geo/src/org/argeo/app/ol/OlMap.java new file mode 100644 index 0000000..6ca37e3 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/OlMap.java @@ -0,0 +1,22 @@ +package org.argeo.app.ol; + +public class OlMap extends AbstractOlObject { + + public OlMap(Object... args) { + super(args); + } + + public void addLayer(Layer layer) { + executeMethod(getMethodName(), layer); + } + + public View getView() { + return new View(getJsClient(), getReference() + ".getView()"); + } + + @Override + public String getJsClassName() { + return getJsPackage() + ".Map"; + } + +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/Source.java b/org.argeo.app.geo/src/org/argeo/app/ol/Source.java new file mode 100644 index 0000000..541353e --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/Source.java @@ -0,0 +1,12 @@ +package org.argeo.app.ol; + +public class Source extends AbstractOlObject { + + public Source(Object... args) { + super(args); + } + + public void refresh() { + executeMethod(getMethodName()); + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/TileLayer.java b/org.argeo.app.geo/src/org/argeo/app/ol/TileLayer.java new file mode 100644 index 0000000..32f58ac --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/TileLayer.java @@ -0,0 +1,11 @@ +package org.argeo.app.ol; + +public class TileLayer extends Layer { + public TileLayer(Object... args) { + super(args); + } + + public TileLayer(Source source) { + setSource(source); + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/VectorLayer.java b/org.argeo.app.geo/src/org/argeo/app/ol/VectorLayer.java new file mode 100644 index 0000000..5a4b6b4 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/VectorLayer.java @@ -0,0 +1,16 @@ +package org.argeo.app.ol; + +public class VectorLayer extends Layer { + public VectorLayer(Object... args) { + super(args); + } + + public VectorLayer(String name, Source source) { + this(source); + setName(name); + } + + public VectorLayer(Source source) { + setSource(source); + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/VectorSource.java b/org.argeo.app.geo/src/org/argeo/app/ol/VectorSource.java new file mode 100644 index 0000000..3b60d0b --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/VectorSource.java @@ -0,0 +1,21 @@ +package org.argeo.app.ol; + +public class VectorSource extends Source { + + public VectorSource(Object... args) { + super(args); + } + + public VectorSource(String url, FeatureFormat format) { + setUrl(url); + setFormat(format); + } + + public void setUrl(String url) { + doSetValue(getMethodName(), "url", url); + } + + public void setFormat(FeatureFormat format) { + doSetValue(null, "format", format); + } +} diff --git a/org.argeo.app.geo/src/org/argeo/app/ol/View.java b/org.argeo.app.geo/src/org/argeo/app/ol/View.java new file mode 100644 index 0000000..eab7a38 --- /dev/null +++ b/org.argeo.app.geo/src/org/argeo/app/ol/View.java @@ -0,0 +1,28 @@ +package org.argeo.app.ol; + +public class View extends AbstractOlObject { + public View(Object... args) { + super(args); + } + + public void setCenter(int[] coord) { + if (isNew()) + getNewOptions().put("center", coord); + else + executeMethod(getMethodName(), new Object[] { coord }); + } + + public void setZoom(int zoom) { + if (isNew()) + getNewOptions().put("zoom", zoom); + else + executeMethod(getMethodName(), zoom); + } + +// public void fit(double[] extent) { +// executeMethod(getMethodName(), extent); +// } +// public void setProjection(String projection) { +// doSetValue(getMethodName(), "projection", projection); +// } +} diff --git a/org.argeo.app.jcr/src/org/argeo/app/jcr/JcrEntityDefinition.java b/org.argeo.app.jcr/src/org/argeo/app/jcr/JcrEntityDefinition.java index e76315c..8795d02 100644 --- a/org.argeo.app.jcr/src/org/argeo/app/jcr/JcrEntityDefinition.java +++ b/org.argeo.app.jcr/src/org/argeo/app/jcr/JcrEntityDefinition.java @@ -2,7 +2,6 @@ package org.argeo.app.jcr; import java.util.Map; -import javax.jcr.Node; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; @@ -14,11 +13,12 @@ import org.argeo.jcr.Jcr; import org.osgi.framework.BundleContext; /** An entity definition based on a JCR data structure. */ +@Deprecated public class JcrEntityDefinition implements EntityDefinition { private Repository repository; private String type; - private String defaultEditorId; +// private String defaultEditorId; public void init(BundleContext bundleContext, Map properties) throws RepositoryException { Session adminSession = CmsJcrUtils.openDataAdminSession(repository, null); @@ -26,7 +26,7 @@ public class JcrEntityDefinition implements EntityDefinition { type = properties.get(EntityConstants.TYPE); if (type == null) throw new IllegalArgumentException("Entity type property " + EntityConstants.TYPE + " must be set."); - defaultEditorId = properties.get(EntityConstants.DEFAULT_EDITOR_ID); +// defaultEditorId = properties.get(EntityConstants.DEFAULT_EDITOR_ID); // String definitionPath = EntityNames.ENTITY_DEFINITIONS_PATH + '/' + type; // if (!adminSession.itemExists(definitionPath)) { // Node entityDefinition = JcrUtils.mkdirs(adminSession, definitionPath, EntityTypes.ENTITY_DEFINITION); @@ -48,10 +48,10 @@ public class JcrEntityDefinition implements EntityDefinition { } - @Override - public String getEditorId(Node entity) { - return defaultEditorId; - } +// @Override +// public String getEditorId(Node entity) { +// return defaultEditorId; +// } @Override public String getType() { diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java index 6e145c2..de88a23 100644 --- a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java +++ b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkManifestServlet.java @@ -30,6 +30,9 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.output.NullOutputStream; import org.argeo.app.api.EntityMimeType; +import org.argeo.app.api.EntityType; +import org.argeo.app.api.WGS84PosName; +import org.argeo.app.geo.GeoShapeUtils; import org.argeo.app.odk.OrxManifestName; import org.argeo.cms.auth.RemoteAuthUtils; import org.argeo.cms.servlet.ServletHttpRequest; @@ -142,6 +145,7 @@ public class OdkManifestServlet extends HttpServlet { } // TODO make it more configurable columnNames.add("display"); + columnNames.add("geometry"); if (EntityMimeType.XML.equals(mimeType)) { } else if (EntityMimeType.CSV.equals(mimeType)) { @@ -158,6 +162,16 @@ public class OdkManifestServlet extends HttpServlet { } // display lst.add(row.getValue("name").getString() + " (" + row.getValue("label").getString() + ")"); + Node field = row.getNode("geopoint"); + if (field != null && field.isNodeType(EntityType.geopoint.get())) { + double lat = field.getProperty(WGS84PosName.lat.get()).getDouble(); + double lon = field.getProperty(WGS84PosName.lon.get()).getDouble(); + double alt = field.hasProperty(WGS84PosName.alt.get()) + ? field.getProperty(WGS84PosName.alt.get()).getDouble() + : Double.NaN; + String geoshape = GeoShapeUtils.geoPointToGeoShape(lon, lat, alt); + lst.add(geoshape); + } csvWriter.writeLine(lst); } } else { diff --git a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java index 3ef414b..da79b5e 100644 --- a/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java +++ b/org.argeo.app.servlet.odk/src/org/argeo/app/servlet/odk/OdkSubmissionServlet.java @@ -39,13 +39,11 @@ public class OdkSubmissionServlet extends HttpServlet { private final static CmsLog log = CmsLog.getLog(OdkSubmissionServlet.class); private final static String XML_SUBMISSION_FILE = "xml_submission_file"; + private final static String IS_INCOMPLETE = "*isIncomplete*"; private DateTimeFormatter submissionNameFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HHmmssSSS") .withZone(ZoneId.from(ZoneOffset.UTC)); -// private Repository repository; -// private ContentRepository contentRepository; - private Set submissionListeners = new HashSet<>(); private AppUserState appUserState; @@ -56,30 +54,18 @@ public class OdkSubmissionServlet extends HttpServlet { resp.setHeader("X-OpenRosa-Version", "1.0"); resp.setDateHeader("Date", System.currentTimeMillis()); - // should be set in HEAD? Let's rather use defaults. - // resp.setIntHeader("X-OpenRosa-Accept-Content-Length", 1024 * 1024); - RemoteAuthRequest request = new ServletHttpRequest(req); -// Session session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), request); -// CmsSession cmsSession = RemoteAuthUtils.getCmsSession(request); -// Session adminSession = null; -// try { -// // TODO centralise at a deeper level -// adminSession = CmsJcrUtils.openDataAdminSession(repository, null); -// SuiteJcrUtils.getOrCreateCmsSessionNode(adminSession, cmsSession); -// } finally { -// Jcr.logout(adminSession); -// } - + boolean isIncomplete = false; try { Content sessionDir = appUserState.getOrCreateSessionDir(cmsSession); Node cmsSessionNode = sessionDir.adapt(Node.class); - // Node cmsSessionNode = SuiteJcrUtils.getCmsSessionNode(session, cmsSession); - Node submission = cmsSessionNode.addNode(submissionNameFormatter.format(Instant.now()), - OrxType.submission.get()); + String submissionName = submissionNameFormatter.format(Instant.now()); + Node submission = cmsSessionNode.addNode(submissionName, OrxType.submission.get()); + String submissionPath = submission.getPath(); for (Part part : req.getParts()) { + String partNameSane = JcrUtils.replaceInvalidChars(part.getName()); if (log.isTraceEnabled()) log.trace("Part: " + part.getName() + ", " + part.getContentType()); @@ -88,6 +74,9 @@ public class OdkSubmissionServlet extends HttpServlet { cmsSessionNode.getSession().importXML(xml.getPath(), part.getInputStream(), ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING); + } else if (part.getName().equals(IS_INCOMPLETE)) { + isIncomplete = true; + log.debug("Form submission " + submissionPath + " is incomplete, expecting more to be uploaded..."); } else { Node fileNode; if (part.getName().endsWith(".jpg")) { @@ -97,19 +86,17 @@ public class OdkSubmissionServlet extends HttpServlet { ImageProcessor imageProcessor = new ImageProcessor(() -> part.getInputStream(), () -> Files.newOutputStream(temp)); imageProcessor.process(); - fileNode = JcrUtils.copyStreamAsFile(submission, part.getName(), - Files.newInputStream(temp)); + fileNode = JcrUtils.copyStreamAsFile(submission, partNameSane, Files.newInputStream(temp)); } finally { Files.deleteIfExists(temp); } } else { - fileNode = JcrUtils.copyStreamAsFile(submission, part.getName(), part.getInputStream()); + fileNode = JcrUtils.copyStreamAsFile(submission, partNameSane, part.getInputStream()); } String contentType = part.getContentType(); if (contentType != null) { fileNode.addMixin(NodeType.MIX_MIMETYPE); fileNode.setProperty(Property.JCR_MIMETYPE, contentType); - } if (part.getName().endsWith(".jpg") || part.getName().endsWith(".png")) { // TODO meta data and thumbnails @@ -120,22 +107,23 @@ public class OdkSubmissionServlet extends HttpServlet { cmsSessionNode.getSession().save(); try { for (FormSubmissionListener submissionListener : submissionListeners) { - submissionListener.formSubmissionReceived(JcrContent.nodeToContent(submission)); + submissionListener.formSubmissionReceived(JcrContent.nodeToContent(submission), isIncomplete); } } catch (Exception e) { - log.error("Cannot save submision, cancelling...", e); - submission.remove(); + log.error("Cannot save submission, cancelling...", e); + if (cmsSessionNode.getSession().hasPendingChanges()) + cmsSessionNode.getSession().refresh(false);// discard + if (cmsSessionNode.getSession().itemExists(submissionPath)) + submission.remove(); cmsSessionNode.getSession().save(); resp.setStatus(503); return; } } catch (Exception e) { - log.error("Cannot save submision", e); + log.error("Cannot save submission", e); resp.setStatus(503); return; -// } finally { -// Jcr.logout(session); } resp.setStatus(201); @@ -144,10 +132,6 @@ public class OdkSubmissionServlet extends HttpServlet { } -// public void setRepository(Repository repository) { -// this.repository = repository; -// } - public synchronized void addSubmissionListener(FormSubmissionListener listener) { submissionListeners.add(listener); } @@ -156,10 +140,6 @@ public class OdkSubmissionServlet extends HttpServlet { submissionListeners.remove(listener); } -// public void setContentRepository(ContentRepository contentRepository) { -// this.contentRepository = contentRepository; -// } - public void setAppUserState(AppUserState appUserState) { this.appUserState = appUserState; } diff --git a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FopServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FopServlet.java index b389883..a4e07ba 100644 --- a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FopServlet.java +++ b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/FopServlet.java @@ -40,15 +40,16 @@ import org.apache.xmlgraphics.io.ResourceResolver; import org.argeo.api.acr.Content; import org.argeo.api.acr.ContentRepository; import org.argeo.api.acr.ContentSession; +import org.argeo.api.acr.NamespaceUtils; import org.argeo.app.geo.GeoUtils; import org.argeo.app.geo.GpxUtils; +import org.argeo.app.geo.acr.GeoEntityUtils; import org.argeo.cms.acr.xml.XmlNormalizer; import org.argeo.cms.auth.RemoteAuthUtils; import org.argeo.cms.servlet.ServletHttpRequest; import org.argeo.cms.util.LangUtils; -import org.geotools.data.collection.ListFeatureCollection; -import org.geotools.data.simple.SimpleFeatureCollection; -import org.opengis.feature.simple.SimpleFeature; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.Polygon; import net.sf.saxon.BasicTransformerFactory; @@ -109,21 +110,35 @@ public class FopServlet extends HttpServlet { return new StreamSource(in); } if (url.getScheme().equals("geo2svg")) { - String includePath = path + url.getPath(); - String geoExt = includePath.substring(includePath.lastIndexOf('.')); - Content geoContent = session.get(includePath); - if (".gpx".equals(geoExt)) { - try (InputStream in = geoContent.open(InputStream.class)) { - SimpleFeature field = GpxUtils.parseGpxToPolygon(in); - SimpleFeatureCollection features = new ListFeatureCollection(field.getType(), field); - try (StringWriter writer = new StringWriter()) { - GeoUtils.exportToSvg(features, writer, 100, 100); - StreamSource res = new StreamSource(new StringReader(writer.toString())); - return res; + int lastDot = url.getPath().lastIndexOf('.'); + Polygon polygon; + if (lastDot > 0) { + String includePath = path + url.getPath(); + Content geoContent = session.get(includePath); + String geoExt = includePath.substring(lastDot); + if (".gpx".equals(geoExt)) { + try (InputStream in = geoContent.open(InputStream.class)) { + polygon = GpxUtils.parseGpxTrackTo(in, Polygon.class); } + } else { + throw new UnsupportedOperationException(geoExt + " is not supported"); } } else { - throw new UnsupportedOperationException(geoExt + " is not supported"); + Content geoContent; + String attrName; + if (url.getPath().startsWith("/@")) { + geoContent = content; + attrName = url.getPath().substring(2);// remove /@ + } else { + throw new IllegalArgumentException("Only direct attributes are currently supported"); + } + polygon = GeoEntityUtils.getGeometry(geoContent, NamespaceUtils.parsePrefixedName(attrName), + Polygon.class); + } + try (StringWriter writer = new StringWriter()) { + GeoUtils.exportToSvg(new Geometry[] { polygon }, writer, 100, 100); + StreamSource res = new StreamSource(new StringReader(writer.toString())); + return res; } } } diff --git a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/GeoToSvgServlet.java b/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/GeoToSvgServlet.java deleted file mode 100644 index c22b834..0000000 --- a/org.argeo.app.servlet.publish/src/org/argeo/app/servlet/publish/GeoToSvgServlet.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.argeo.app.servlet.publish; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.argeo.api.acr.Content; -import org.argeo.api.acr.ContentRepository; -import org.argeo.api.acr.ContentSession; -import org.argeo.app.geo.GeoUtils; -import org.argeo.app.geo.GpxUtils; -import org.argeo.cms.auth.RemoteAuthUtils; -import org.argeo.cms.servlet.ServletHttpRequest; -import org.geotools.data.collection.ListFeatureCollection; -import org.geotools.data.simple.SimpleFeatureCollection; -import org.opengis.feature.simple.SimpleFeature; - -/** - * A servlet transforming an geographical data to SVG. - */ -public class GeoToSvgServlet extends HttpServlet { - private static final long serialVersionUID = -6346379324580671894L; - private ContentRepository contentRepository; - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String servletPath = req.getServletPath(); - - servletPath = servletPath.substring(1, servletPath.lastIndexOf('.')); - servletPath = servletPath.substring(servletPath.indexOf('/'), servletPath.length()); - String path = URLDecoder.decode(servletPath, StandardCharsets.UTF_8); - String ext = servletPath.substring(path.lastIndexOf('.')); - - resp.setContentType("image/svg+xml"); - - ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(), new ServletHttpRequest(req)); - Content content = session.get(path); - if (".gpx".equals(ext)) { - try (InputStream in = content.open(InputStream.class)) { - SimpleFeature field = GpxUtils.parseGpxToPolygon(in); - - SimpleFeatureCollection features = new ListFeatureCollection(field.getType(), field); - GeoUtils.exportToSvg(features, resp.getWriter(), 100, 100); -// log.debug("SVG:\n" + writer.toString() + "\n"); - } - } - } - - public void start(Map properties) { - } - - public void stop(Map properties) { - - } - - public void setContentRepository(ContentRepository contentRepository) { - this.contentRepository = contentRepository; - } - -} diff --git a/sdk/argeo-build b/sdk/argeo-build index d9cae87..d5943f5 160000 --- a/sdk/argeo-build +++ b/sdk/argeo-build @@ -1 +1 @@ -Subproject commit d9cae87d811258d5a13e43eea8492f3792377ce4 +Subproject commit d5943f556d6fba9db0dd63d4c4cfceef89e4888e diff --git a/sdk/argeo-suite-desktop.properties b/sdk/argeo-suite-desktop.properties index e541ba4..8ada854 100644 --- a/sdk/argeo-suite-desktop.properties +++ b/sdk/argeo-suite-desktop.properties @@ -7,6 +7,8 @@ org.argeo.cms,\ org.argeo.cms.swt.rcp,\ org.argeo.cms.ee,\ org.argeo.cms.lib.dbus,\ +org.argeo.cms.lib.equinox,\ +org.argeo.cms.lib.jetty,\ argeo.osgi.start.4=\ org.argeo.cms.jcr @@ -14,8 +16,10 @@ org.argeo.cms.jcr argeo.osgi.start.5=\ org.argeo.app.profile.acr.fs,\ org.argeo.app.core,\ +org.argeo.app.jcr,\ org.argeo.app.ui,\ org.argeo.app.theme.default,\ +org.argeo.app.geo,\ # Local diff --git a/sdk/argeo-suite-server.properties b/sdk/argeo-suite-server.properties index a600396..a9b3271 100644 --- a/sdk/argeo-suite-server.properties +++ b/sdk/argeo-suite-server.properties @@ -39,6 +39,8 @@ log.org.argeo=DEBUG # DON'T CHANGE BELOW org.eclipse.equinox.http.jetty.autostart=false org.osgi.framework.system.packages.extra=\ +sun.security.internal.spec,\ +sun.security.provider,\ com.sun.net.httpserver,\ com.sun.jndi.ldap,\ com.sun.jndi.ldap.sasl,\ diff --git a/sdk/branches/unstable.bnd b/sdk/branches/unstable.bnd index f9e0372..172581f 100644 --- a/sdk/branches/unstable.bnd +++ b/sdk/branches/unstable.bnd @@ -1,6 +1,6 @@ major=2 minor=3 -micro=15 +micro=19 qualifier= Bundle-Copyright= \ @@ -9,4 +9,4 @@ Copyright 2017-2023 Mathieu Baudier SPDX-License-Identifier= \ GPL-2.0-or-later \ -OR LicenseRef-argeo2-GPL-2.0-or-later-with-EPL-and-JCR-permissions +OR LicenseRef-argeo2-GPL-2.0-or-later-with-EPL-and-Apache-and-JCR-permissions diff --git a/swt/org.argeo.app.geo.swt/.classpath b/swt/org.argeo.app.geo.swt/.classpath new file mode 100644 index 0000000..81fe078 --- /dev/null +++ b/swt/org.argeo.app.geo.swt/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/swt/org.argeo.app.geo.swt/.project b/swt/org.argeo.app.geo.swt/.project new file mode 100644 index 0000000..cf7ca92 --- /dev/null +++ b/swt/org.argeo.app.geo.swt/.project @@ -0,0 +1,28 @@ + + + org.argeo.app.geo.swt + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/swt/org.argeo.app.geo.swt/.settings/org.eclipse.core.resources.prefs b/swt/org.argeo.app.geo.swt/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/swt/org.argeo.app.geo.swt/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/swt/org.argeo.app.geo.swt/.settings/org.eclipse.jdt.core.prefs b/swt/org.argeo.app.geo.swt/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..62ef348 --- /dev/null +++ b/swt/org.argeo.app.geo.swt/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/swt/org.argeo.app.geo.swt/.settings/org.eclipse.pde.core.prefs b/swt/org.argeo.app.geo.swt/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000..f29e940 --- /dev/null +++ b/swt/org.argeo.app.geo.swt/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/swt/org.argeo.app.geo.swt/bnd.bnd b/swt/org.argeo.app.geo.swt/bnd.bnd new file mode 100644 index 0000000..f8e867c --- /dev/null +++ b/swt/org.argeo.app.geo.swt/bnd.bnd @@ -0,0 +1,7 @@ +Import-Package:\ +org.eclipse.swt,\ +org.argeo.cms.acr,\ +* + +Provide-Capability:\ +cms.publish;pkg=org.argeo.app.geo.swt.openlayers;file="*.png,*.js,*.css" diff --git a/swt/org.argeo.app.geo.swt/build.properties b/swt/org.argeo.app.geo.swt/build.properties new file mode 100644 index 0000000..34d2e4d --- /dev/null +++ b/swt/org.argeo.app.geo.swt/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/MapUiProvider.java b/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/MapUiProvider.java new file mode 100644 index 0000000..283cbce --- /dev/null +++ b/swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/MapUiProvider.java @@ -0,0 +1,52 @@ +package org.argeo.app.geo.swt; + +import org.argeo.api.acr.Content; +import org.argeo.app.geo.ux.AbstractGeoJsObject; +import org.argeo.app.geo.ux.OpenLayersMapPart; +import org.argeo.app.geo.ux.SentinelCloudless; +import org.argeo.app.ol.GeoJSON; +import org.argeo.app.ol.Layer; +import org.argeo.app.ol.OSM; +import org.argeo.app.ol.TileLayer; +import org.argeo.app.ol.VectorLayer; +import org.argeo.app.ol.VectorSource; +import org.argeo.app.swt.js.SwtBrowserJsPart; +import org.argeo.app.ux.js.JsClient; +import org.argeo.cms.swt.acr.SwtUiProvider; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +/** Create map parts. */ +public class MapUiProvider implements SwtUiProvider { + + @Override + public Control createUiPart(Composite parent, Content context) { + JsClient jsClient = new SwtBrowserJsPart(parent, 0, AbstractGeoJsObject.ARGEO_APP_GEO_JS_URL); + OpenLayersMapPart mapPart = new OpenLayersMapPart(jsClient, "defaultOverviewMap"); + mapPart.getMap().getView().setCenter(new int[] { 0, 0 }); + mapPart.getMap().getView().setZoom(6); + + Layer satelliteLayer = new TileLayer(new SentinelCloudless()); + satelliteLayer.setMaxResolution(200); + mapPart.getMap().addLayer(satelliteLayer); + + TileLayer baseLayer = new TileLayer(); + baseLayer.setSource(new OSM()); + baseLayer.setOpacity(0.5); + mapPart.getMap().addLayer(baseLayer); + + Layer dataLayer = new VectorLayer(new VectorSource( + "https://openlayers.org/en/v4.6.5/examples/data/geojson/countries.geojson", new GeoJSON())); + mapPart.getMap().addLayer(dataLayer); + +// SwtJsMapPart map = new SwtJsMapPart("defaultOverviewMap", parent, 0); +// map.setCenter(13.404954, 52.520008); // Berlin +//// map.setCenter(-74.00597, 40.71427); // NYC +//// map.addPoint(-74.00597, 40.71427, null); +// map.setZoom(6); +// // map.addUrlLayer("https://openlayers.org/en/v4.6.5/examples/data/geojson/countries.geojson", +// // Format.GEOJSON); + return parent; + } + +} diff --git a/swt/org.argeo.app.swt/src/org/argeo/app/swt/chart/AbstractJsChart.java b/swt/org.argeo.app.swt/src/org/argeo/app/swt/chart/AbstractJsChart.java new file mode 100644 index 0000000..8cae325 --- /dev/null +++ b/swt/org.argeo.app.swt/src/org/argeo/app/swt/chart/AbstractJsChart.java @@ -0,0 +1,31 @@ +package org.argeo.app.swt.chart; + +import org.argeo.app.swt.js.SwtBrowserJsPart; +import org.eclipse.swt.widgets.Composite; + +/** Base class for charts. */ +public abstract class AbstractJsChart extends SwtBrowserJsPart { + private String chartName; + + protected abstract String getJsImplementation(); + + public AbstractJsChart(String chartName, Composite parent, int style) { + super(parent, style, "/pkg/org.argeo.app.js/chart.html"); + this.chartName = chartName; + } + + @Override + protected void init() { + // create chart + doExecute(getJsChartVar() + " = new " + getJsImplementation() + "('" + chartName + "');"); + } + + protected String getJsChartVar() { + return getJsVarName(chartName); + } + + protected void executeChartMethod(String methodCall, Object... args) { + executeMethod(getJsChartVar(), methodCall, args); + } + +} diff --git a/swt/org.argeo.app.swt/src/org/argeo/app/swt/chart/SwtJsBarChart.java b/swt/org.argeo.app.swt/src/org/argeo/app/swt/chart/SwtJsBarChart.java new file mode 100644 index 0000000..bcfb15f --- /dev/null +++ b/swt/org.argeo.app.swt/src/org/argeo/app/swt/chart/SwtJsBarChart.java @@ -0,0 +1,62 @@ +package org.argeo.app.swt.chart; + +import java.io.StringWriter; + +import org.argeo.app.ux.js.JsClient; +import org.eclipse.swt.widgets.Composite; + +import jakarta.json.Json; +import jakarta.json.stream.JsonGenerator; + +public class SwtJsBarChart extends AbstractJsChart { + + public SwtJsBarChart(String chartName, Composite parent, int style) { + super(chartName, parent, style); + } + + @Override + protected String getJsImplementation() { + return "globalThis.argeo.app.chart.BarChart"; + } + + public void setLabels(String[] labels) { + executeChartMethod("setLabels(%s)", JsClient.toJsArray(labels)); + } + + public void addDataset(String label, int[] values) { + executeChartMethod("addDataset('%s', %s)", label, JsClient.toJsArray(values)); + } + + public void setData(String[] labels, String label, int[] values) { + executeChartMethod("setData(%s, '%s', %s)", JsClient.toJsArray(labels), label, JsClient.toJsArray(values)); + } + + public void setDatasets(String[] labels, String[] label, int[][] values) { + executeChartMethod("setDatasets(%s, %s)", JsClient.toJsArray(labels), toDatasets(label, values)); + } + + protected String toDatasets(String[] label, int[][] values) { + if (label.length != values.length) + throw new IllegalArgumentException("Arrays must have the same length"); + StringWriter writer = new StringWriter(); + JsonGenerator g = Json.createGenerator(writer); + g.writeStartArray(); + for (int i = 0; i < label.length; i++) { + g.writeStartObject(); + g.write("label", label[i]); + g.writeStartArray("data"); + for (int j = 0; j < values[i].length; j++) { + g.write(values[i][j]); + } + g.writeEnd();// data array + g.writeEnd();// dataset + } + g.writeEnd(); + g.close(); + return writer.toString(); + } + + public void clearDatasets() { + executeChartMethod("clearDatasets()"); + } +} diff --git a/swt/org.argeo.app.swt/src/org/argeo/app/swt/js/SwtBrowserJsPart.java b/swt/org.argeo.app.swt/src/org/argeo/app/swt/js/SwtBrowserJsPart.java new file mode 100644 index 0000000..6782f5d --- /dev/null +++ b/swt/org.argeo.app.swt/src/org/argeo/app/swt/js/SwtBrowserJsPart.java @@ -0,0 +1,194 @@ +package org.argeo.app.swt.js; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + +import org.argeo.api.cms.CmsLog; +import org.argeo.api.cms.ux.CmsView; +import org.argeo.app.ux.js.JsClient; +import org.argeo.cms.swt.CmsSwtUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.browser.Browser; +import org.eclipse.swt.browser.BrowserFunction; +import org.eclipse.swt.browser.ProgressEvent; +import org.eclipse.swt.browser.ProgressListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; + +/** + * A part using a {@link Browser} and remote JavaScript components on the client + * side. + */ +public class SwtBrowserJsPart implements JsClient { + private final static CmsLog log = CmsLog.getLog(SwtBrowserJsPart.class); + + private final static String GLOBAL_THIS_ = "globalThis."; + + private final Browser browser; + private final CompletableFuture readyStage = new CompletableFuture<>(); + + /** + * Tasks that were requested before the context was ready. Typically + * configuration methods on the part while the user interfaces is being build. + */ + private List preReadyToDos = new ArrayList<>(); + + public SwtBrowserJsPart(Composite parent, int style, String url) { + CmsView cmsView = CmsSwtUtils.getCmsView(parent); + this.browser = new Browser(parent, 0); + if (parent.getLayout() instanceof GridLayout) + browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + // TODO other layouts + + URI u = cmsView.toBackendUri(url); + browser.setUrl(u.toString()); + browser.addProgressListener(new ProgressListener() { + static final long serialVersionUID = 1L; + + @Override + public void completed(ProgressEvent event) { + try { + init(); + loadExtensions(); + // execute todos in order + for (PreReadyToDo toDo : preReadyToDos) { + toDo.run(); + } + preReadyToDos.clear(); + readyStage.complete(true); + } catch (Exception e) { + log.error("Cannot initialise " + url + " in browser", e); + readyStage.complete(false); + } + } + + @Override + public void changed(ProgressEvent event) { + } + }); + } + + /* + * LIFECYCLE + */ + + /** + * Called when the page has been loaded, typically in order to initialise + * JavaScript objects. One MUST use {@link #doExecute(String, Object...)} in + * order to do so, since the context is not yet considered ready and calls to + * {@link #evaluate(String, Object...)} will block. + */ + protected void init() { + } + + /** + * To be overridden with calls to {@link #loadExtension(String)}. + */ + protected void loadExtensions() { + + } + + protected void loadExtension(String url) { + URI u = CmsSwtUtils.getCmsView(getControl()).toBackendUri(url); + browser.evaluate(String.format(Locale.ROOT, "import('%s')", u.toString())); + } + + public CompletionStage getReadyStage() { + return readyStage.minimalCompletionStage(); + } + + /* + * JAVASCRIPT ACCESS + */ + + @Override + public Object evaluate(String js, Object... args) { + assert browser.getDisplay().equals(Display.findDisplay(Thread.currentThread())) : "Not the proper UI thread."; + if (!readyStage.isDone()) + throw new IllegalStateException("Methods returning a result can only be called after UI initialisation."); + if (browser.isDisposed()) + return null; + Object result = browser.evaluate(String.format(Locale.ROOT, js, args)); + return result; + } + + @Override + public void execute(String js, Object... args) { + String jsToExecute = String.format(Locale.ROOT, js, args); + if (readyStage.isDone()) { + if (browser.isDisposed()) + return; + boolean success = browser.execute(jsToExecute); + if (!success) + throw new RuntimeException("JavaScript execution failed."); + } else { + PreReadyToDo toDo = new PreReadyToDo(jsToExecute); + preReadyToDos.add(toDo); + } + } + + @Override + public String createJsFunction(String name, Function toDo) { + // browser functions must be directly on window (RAP specific) + new BrowserFunction(browser, name) { + + @Override + public Object function(Object[] arguments) { + Object result = toDo.apply(arguments); + return result; + } + + }; + return "window." + name; + } + + /** + * Directly executes, even if {@link #getReadyStage()} is not completed. Except + * in initialisation, {@link #evaluate(String, Object...)} should be used + * instead. + */ + protected void doExecute(String js, Object... args) { + if (browser.isDisposed()) + return; + browser.execute(String.format(Locale.ROOT, js, args)); + } + + @Override + public String getJsVarName(String name) { + return GLOBAL_THIS_ + name; + } + + class PreReadyToDo implements Runnable { + private String js; + + public PreReadyToDo(String js) { + this.js = js; + } + + @Override + public void run() { + if (browser.isDisposed()) + return; + boolean success = browser.execute(js); + if (!success && log.isTraceEnabled()) + log.error("Pre-ready JavaScript failed: " + js); + } + } + + /* + * ACCESSORS + */ + + public Control getControl() { + return browser; + } + +} diff --git a/swt/org.argeo.app.swt/src/org/argeo/app/swt/ux/DefaultEditionLayer.java b/swt/org.argeo.app.swt/src/org/argeo/app/swt/ux/DefaultEditionLayer.java index 109dd22..549062f 100644 --- a/swt/org.argeo.app.swt/src/org/argeo/app/swt/ux/DefaultEditionLayer.java +++ b/swt/org.argeo.app.swt/src/org/argeo/app/swt/ux/DefaultEditionLayer.java @@ -16,6 +16,7 @@ import org.argeo.cms.swt.acr.SwtUiProvider; import org.argeo.cms.util.LangUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; @@ -59,6 +60,8 @@ public class DefaultEditionLayer implements SwtAppLayer { } else { if (this.workArea != null) { Composite area = new Composite(parent, SWT.NONE); + // we set fill layout by default but it can be overridden + area.setLayout(new FillLayout()); this.workArea.createUiPart(area, context); return area; } diff --git a/swt/org.argeo.app.swt/src/org/argeo/app/swt/ux/SuiteSwtUtils.java b/swt/org.argeo.app.swt/src/org/argeo/app/swt/ux/SuiteSwtUtils.java index 39cde1b..66e8463 100644 --- a/swt/org.argeo.app.swt/src/org/argeo/app/swt/ux/SuiteSwtUtils.java +++ b/swt/org.argeo.app.swt/src/org/argeo/app/swt/ux/SuiteSwtUtils.java @@ -11,6 +11,7 @@ import org.argeo.api.cms.ux.CmsEditable; import org.argeo.api.cms.ux.CmsStyle; import org.argeo.app.ux.SuiteStyle; import org.argeo.cms.Localized; +import org.argeo.cms.acr.ContentUtils; import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.swt.acr.Img; import org.argeo.cms.swt.dialogs.CmsFeedback; @@ -182,7 +183,7 @@ public class SuiteSwtUtils { * CONTENT */ public static String toLink(Content content) { - return content != null ? "#" + CmsSwtUtils.cleanPathForUrl(content.getPath()) : null; + return content != null ? "#" + ContentUtils.cleanPathForUrl(content.getPath()) : null; } public static Text addFormLine(Composite parent, Localized label, Content content, QNamed property, @@ -297,7 +298,7 @@ public class SuiteSwtUtils { Text txt = SuiteSwtUtils.addFormTextField(parent, text, null, 0); if (cmsEditable != null && cmsEditable.isEditing()) { txt.addModifyListener((e) -> { - content.put(property, txt.getText()); + content.put(property, txt.getText().trim()); }); } else { txt.setEditable(false); diff --git a/swt/org.argeo.app.ui/OSGI-INF/defaultMap.xml b/swt/org.argeo.app.ui/OSGI-INF/defaultMap.xml new file mode 100644 index 0000000..8d53c27 --- /dev/null +++ b/swt/org.argeo.app.ui/OSGI-INF/defaultMap.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/swt/org.argeo.app.ui/OSGI-INF/mapLayer.xml b/swt/org.argeo.app.ui/OSGI-INF/mapLayer.xml index 44f7a0e..372ca82 100644 --- a/swt/org.argeo.app.ui/OSGI-INF/mapLayer.xml +++ b/swt/org.argeo.app.ui/OSGI-INF/mapLayer.xml @@ -6,5 +6,5 @@ - + diff --git a/swt/org.argeo.app.ui/bnd.bnd b/swt/org.argeo.app.ui/bnd.bnd index 5bc2eea..dcf439d 100644 --- a/swt/org.argeo.app.ui/bnd.bnd +++ b/swt/org.argeo.app.ui/bnd.bnd @@ -20,6 +20,7 @@ OSGI-INF/documentsFolder.xml,\ OSGI-INF/fsEntryArea.xml,\ OSGI-INF/mapLayer.xml,\ OSGI-INF/overviewMap.xml,\ +OSGI-INF/defaultMap.xml,\ OSGI-INF/wwwLayer.xml,\ OSGI-INF/documentUiProvider.xml,\ OSGI-INF/publishEntryArea.xml,\ @@ -36,6 +37,7 @@ org.eclipse.core.commands.common,\ org.eclipse.jface.window,\ org.eclipse.jface.dialogs,\ org.eclipse.rap.rwt,\ +org.argeo.app.geo.swt,\ javax.servlet.*;version="[3,5)",\ javax.jcr.nodetype,\ * diff --git a/swt/org.argeo.app.ui/config/defaultMap.properties b/swt/org.argeo.app.ui/config/defaultMap.properties new file mode 100644 index 0000000..fb14459 --- /dev/null +++ b/swt/org.argeo.app.ui/config/defaultMap.properties @@ -0,0 +1 @@ +service.pid=argeo.geo.ui.defaultMap diff --git a/swt/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java b/swt/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java index e649bfc..62463c7 100644 --- a/swt/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java +++ b/swt/org.argeo.app.ui/src/org/argeo/app/ui/SuiteUiUtils.java @@ -19,6 +19,7 @@ import org.argeo.app.api.EntityNames; import org.argeo.app.api.EntityType; import org.argeo.app.swt.ux.SuiteSwtUtils; import org.argeo.app.ux.SuiteUxEvent; +import org.argeo.cms.acr.ContentUtils; import org.argeo.cms.jcr.acr.JcrContent; import org.argeo.cms.swt.CmsSwtUtils; import org.argeo.cms.swt.dialogs.LightweightDialog; @@ -220,7 +221,7 @@ public class SuiteUiUtils { } public static String toLink(Node node) { - return node != null ? "#" + CmsSwtUtils.cleanPathForUrl(JcrContent.nodeToContent(node).getPath()) : null; + return node != null ? "#" + ContentUtils.cleanPathForUrl(JcrContent.nodeToContent(node).getPath()) : null; } public static Control addLink(Composite parent, String label, Node node, CmsStyle style) diff --git a/swt/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OLMap.java b/swt/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OLMap.java deleted file mode 100644 index 1301325..0000000 --- a/swt/org.argeo.app.ui/src/org/argeo/app/ui/openlayers/OLMap.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.argeo.app.ui.openlayers; - -import org.argeo.cms.swt.CmsSwtUtils; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; - -public class OLMap extends Composite { - private Label div; - - public OLMap(Composite parent, int style) { - super(parent, style); - setLayout(CmsSwtUtils.noSpaceGridLayout()); - div = new Label(this, SWT.NONE); - CmsSwtUtils.markup(div); - CmsSwtUtils.disableMarkupValidation(div); - div.setText("
"); - div.setLayoutData(CmsSwtUtils.fillAll()); - } - -} diff --git a/swt/org.argeo.app.ui/src/org/argeo/app/ui/publish/PdfViewer.java b/swt/org.argeo.app.ui/src/org/argeo/app/ui/publish/PdfViewer.java index 38d995f..57f77f3 100644 --- a/swt/org.argeo.app.ui/src/org/argeo/app/ui/publish/PdfViewer.java +++ b/swt/org.argeo.app.ui/src/org/argeo/app/ui/publish/PdfViewer.java @@ -3,8 +3,8 @@ package org.argeo.app.ui.publish; import java.awt.image.BufferedImage; import java.nio.file.Paths; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.rendering.PDFRenderer; +//import org.apache.pdfbox.pdmodel.PDDocument; +//import org.apache.pdfbox.rendering.PDFRenderer; import org.argeo.eclipse.ui.specific.BufferedImageDisplay; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; @@ -13,25 +13,25 @@ import org.eclipse.swt.widgets.Shell; public class PdfViewer { public static void main(String[] args) throws Exception { - PDDocument doc = PDDocument.load(Paths.get(args[0]).toFile()); - PDFRenderer renderer = new PDFRenderer(doc); - - BufferedImage image = renderer.renderImageWithDPI(0, 300); - - Display display = new Display(); - Shell shell = new Shell(display); - shell.setLayout(new FillLayout()); - - shell.setSize(200, 200); - - BufferedImageDisplay imageDisplay = new BufferedImageDisplay(shell, SWT.NONE); - imageDisplay.setImage(image); - - shell.open(); - while (!shell.isDisposed()) { - if (!display.readAndDispatch()) - display.sleep(); - } - display.dispose(); +// PDDocument doc = PDDocument.load(Paths.get(args[0]).toFile()); +// PDFRenderer renderer = new PDFRenderer(doc); +// +// BufferedImage image = renderer.renderImageWithDPI(0, 300); +// +// Display display = new Display(); +// Shell shell = new Shell(display); +// shell.setLayout(new FillLayout()); +// +// shell.setSize(200, 200); +// +// BufferedImageDisplay imageDisplay = new BufferedImageDisplay(shell, SWT.NONE); +// imageDisplay.setImage(image); +// +// shell.open(); +// while (!shell.isDisposed()) { +// if (!display.readAndDispatch()) +// display.sleep(); +// } +// display.dispose(); } }