From c82008c70621d226f917dd30420b6354eb6e757a Mon Sep 17 00:00:00 2001 From: da730 Date: Wed, 31 Jan 2024 19:58:18 +0800 Subject: [PATCH 01/18] feat: add doc page --- .github/workflows/sync-main-to-develop.yml | 2 +- common/config/rush/pnpm-lock.yaml | 345 +++- docs/assets/changelog/en/changelog.md | 542 ++++++ docs/assets/changelog/zh/changelog.md | 542 ++++++ .../guide/en/Basic/How_to_Get_VRender.md | 38 + .../guide/en/Basic/How_to_Import_VRender.md | 11 + .../assets/guide/en/Basic_Tutorial/Animate.md | 276 +++ .../Cross_platform_Interface.md | 15 + .../en/Basic_Tutorial/Events_and_Animation.md | 78 + .../Basic_Tutorial/Extensions_and_Plugins.md | 263 +++ docs/assets/guide/en/Getting_Started.md | 107 ++ docs/assets/guide/en/VMind_Website_Guide.md | 57 + docs/assets/guide/menu.json | 79 + .../guide/zh/Basic/How_to_Get_VRender.md | 38 + .../guide/zh/Basic/How_to_Import_VRender.md | 11 + .../assets/guide/zh/Basic_Tutorial/Animate.md | 276 +++ .../Cross_platform_Interface.md | 15 + .../zh/Basic_Tutorial/Events_and_Animation.md | 78 + .../Basic_Tutorial/Extensions_and_Plugins.md | 307 +++ docs/assets/guide/zh/Getting_Started.md | 107 ++ docs/assets/guide/zh/VMind_Website_Guide.md | 56 + docs/index.html | 15 + docs/index.js | 155 ++ docs/libs/template-parse/build.js | 188 ++ docs/libs/template-parse/etpl.js | 1679 +++++++++++++++++ docs/libs/template-parse/md2json.js | 449 +++++ docs/libs/template-parse/schemaHelper.js | 226 +++ docs/menu.json | 14 + docs/package.json | 38 + docs/src/app.tsx | 55 + docs/src/header.tsx | 61 + docs/src/i18n.tsx | 20 + docs/src/main.tsx | 11 + docs/src/markdown.tsx | 228 +++ docs/src/option.tsx | 66 + docs/src/option/description.tsx | 291 +++ docs/src/option/index.css | 50 + docs/src/option/index.tsx | 86 + docs/src/option/outline.tsx | 215 +++ docs/style.css | 118 ++ docs/tsconfig.json | 25 + docs/tsconfig.node.json | 8 + docs/vite.config.js | 22 + pnpm-lock.yaml | 28 - rush.json | 10 +- 45 files changed, 7203 insertions(+), 98 deletions(-) create mode 100644 docs/assets/changelog/en/changelog.md create mode 100644 docs/assets/changelog/zh/changelog.md create mode 100644 docs/assets/guide/en/Basic/How_to_Get_VRender.md create mode 100644 docs/assets/guide/en/Basic/How_to_Import_VRender.md create mode 100644 docs/assets/guide/en/Basic_Tutorial/Animate.md create mode 100644 docs/assets/guide/en/Basic_Tutorial/Cross_platform_Interface.md create mode 100644 docs/assets/guide/en/Basic_Tutorial/Events_and_Animation.md create mode 100644 docs/assets/guide/en/Basic_Tutorial/Extensions_and_Plugins.md create mode 100644 docs/assets/guide/en/Getting_Started.md create mode 100644 docs/assets/guide/en/VMind_Website_Guide.md create mode 100644 docs/assets/guide/menu.json create mode 100644 docs/assets/guide/zh/Basic/How_to_Get_VRender.md create mode 100644 docs/assets/guide/zh/Basic/How_to_Import_VRender.md create mode 100644 docs/assets/guide/zh/Basic_Tutorial/Animate.md create mode 100644 docs/assets/guide/zh/Basic_Tutorial/Cross_platform_Interface.md create mode 100644 docs/assets/guide/zh/Basic_Tutorial/Events_and_Animation.md create mode 100644 docs/assets/guide/zh/Basic_Tutorial/Extensions_and_Plugins.md create mode 100644 docs/assets/guide/zh/Getting_Started.md create mode 100644 docs/assets/guide/zh/VMind_Website_Guide.md create mode 100644 docs/index.html create mode 100644 docs/index.js create mode 100644 docs/libs/template-parse/build.js create mode 100644 docs/libs/template-parse/etpl.js create mode 100644 docs/libs/template-parse/md2json.js create mode 100644 docs/libs/template-parse/schemaHelper.js create mode 100644 docs/menu.json create mode 100644 docs/package.json create mode 100644 docs/src/app.tsx create mode 100644 docs/src/header.tsx create mode 100644 docs/src/i18n.tsx create mode 100644 docs/src/main.tsx create mode 100644 docs/src/markdown.tsx create mode 100644 docs/src/option.tsx create mode 100644 docs/src/option/description.tsx create mode 100644 docs/src/option/index.css create mode 100644 docs/src/option/index.tsx create mode 100644 docs/src/option/outline.tsx create mode 100644 docs/style.css create mode 100644 docs/tsconfig.json create mode 100644 docs/tsconfig.node.json create mode 100644 docs/vite.config.js delete mode 100644 pnpm-lock.yaml diff --git a/.github/workflows/sync-main-to-develop.yml b/.github/workflows/sync-main-to-develop.yml index ca1f370d..afb747c5 100644 --- a/.github/workflows/sync-main-to-develop.yml +++ b/.github/workflows/sync-main-to-develop.yml @@ -57,5 +57,5 @@ jobs: title: '[Auto Sync] Sync the code from branch main to branch develop after release ${{ steps.package-version.outputs.current_version }}' base: develop head: sync/main-${{ steps.package-version.outputs.current_version }} - reviewers: xile611 + reviewers: da730 body: 'Sync the code from branch main to branch develop after release ${{ steps.package-version.outputs.current_version }}' diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index bebae744..25db1326 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -5,6 +5,63 @@ importers: .: specifiers: {} + ../../docs: + specifiers: + '@arco-design/web-react': 2.46.1 + '@types/highlightjs': ^9.12.0 + '@types/markdown-it': ^13.0.0 + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 + '@visactor/vchart': ^1.9.0 + '@visactor/vgrammar': ~0.5.7 + '@visactor/vrender': ~0.17.19 + '@visactor/vutils': ~0.17.4 + '@vitejs/plugin-react': 3.1.0 + axios: ^1.4.0 + chalk: ^3.0.0 + chokidar: ^3.5.0 + fs-extra: 10.1.0 + globby: 11.1.0 + highlight.js: ^11.8.0 + htmlparser2: ^4.1.0 + lodash: 4.17.21 + markdown-it: ^13.0.0 + marked: ^0.3.19 + react: ^18.0.0 + react-dom: ^18.0.0 + react-router-dom: 6.9.0 + typescript: 4.9.5 + vite: 3.2.6 + yargs: ^17.1.1 + dependencies: + '@arco-design/web-react': 2.46.1_p2jlmv6k7k3po6tueteg46f2ku + '@visactor/vchart': 1.9.0 + '@visactor/vgrammar': 0.5.7 + '@visactor/vrender': 0.17.19 + '@visactor/vutils': 0.17.4 + axios: 1.6.7 + highlight.js: 11.9.0 + lodash: 4.17.21 + markdown-it: 13.0.2 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + react-router-dom: 6.9.0_biqbaboplfbrettd7655fr4n2y + devDependencies: + '@types/highlightjs': 9.12.6 + '@types/markdown-it': 13.0.7 + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 + '@vitejs/plugin-react': 3.1.0_vite@3.2.6 + chalk: 3.0.0 + chokidar: 3.5.3 + fs-extra: 10.1.0 + globby: 11.1.0 + htmlparser2: 4.1.0 + marked: 0.3.19 + typescript: 4.9.5 + vite: 3.2.6 + yargs: 17.7.2 + ../../packages/calculator: specifiers: '@internal/bundler': workspace:* @@ -358,7 +415,6 @@ packages: resolution: {integrity: sha512-s7p9MSwJgHeL8DwcATaXvWT3m2SigKpxx4JA1BGPHL4gfvaQsmQfrLBDpjOJFJuJ2jG2dMt3R3P8Pm9E65q18g==} dependencies: color: 3.2.1 - dev: true /@arco-design/web-react/2.46.1_p2jlmv6k7k3po6tueteg46f2ku: resolution: {integrity: sha512-XjG44rODJklDu++OApvxjt/TbRrgkNqVq6grt/H+9skysm46jFn2SwhuSljBHmjo11LtIeB1m/OMPMaFtafeYg==} @@ -383,7 +439,6 @@ packages: shallowequal: 1.1.0 transitivePeerDependencies: - '@types/react' - dev: true /@babel/code-frame/7.23.5: resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} @@ -2212,7 +2267,6 @@ packages: /@remix-run/router/1.4.0: resolution: {integrity: sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==} engines: {node: '>=14'} - dev: true /@resvg/resvg-js-android-arm-eabi/2.4.1: resolution: {integrity: sha512-AA6f7hS0FAPpvQMhBCf6f1oD1LdlqNXKCxAAPpKh6tR11kqV0YIB9zOlIYgITM14mq2YooLFl6XIbbvmY+jwUw==} @@ -2220,7 +2274,6 @@ packages: cpu: [arm] os: [android] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-android-arm64/2.4.1: @@ -2229,7 +2282,6 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-darwin-arm64/2.4.1: @@ -2238,7 +2290,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-darwin-x64/2.4.1: @@ -2247,7 +2298,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-linux-arm-gnueabihf/2.4.1: @@ -2256,7 +2306,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-linux-arm64-gnu/2.4.1: @@ -2265,7 +2314,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-linux-arm64-musl/2.4.1: @@ -2274,7 +2322,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-linux-x64-gnu/2.4.1: @@ -2283,7 +2330,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-linux-x64-musl/2.4.1: @@ -2292,7 +2338,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-win32-arm64-msvc/2.4.1: @@ -2301,7 +2346,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-win32-ia32-msvc/2.4.1: @@ -2310,7 +2354,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: true optional: true /@resvg/resvg-js-win32-x64-msvc/2.4.1: @@ -2319,7 +2362,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: true optional: true /@resvg/resvg-js/2.4.1: @@ -2338,7 +2380,6 @@ packages: '@resvg/resvg-js-win32-arm64-msvc': 2.4.1 '@resvg/resvg-js-win32-ia32-msvc': 2.4.1 '@resvg/resvg-js-win32-x64-msvc': 2.4.1 - dev: true /@rollup/plugin-alias/5.0.0_rollup@3.20.5: resolution: {integrity: sha512-l9hY5chSCjuFRPsnRm16twWBiSApl2uYFLsepQYwtBuAxNMQ/1dJqADld40P0Jkqm65GRTLy/AC6hnpVebtLsA==} @@ -2741,6 +2782,10 @@ packages: chokidar: 3.5.3 dev: true + /@types/highlightjs/9.12.6: + resolution: {integrity: sha512-Qfd1DUrwE851Hc3tExADJY4qY8yeZMt06Xw9AJm/UtpneepJS3MZY29c33BY0wP899veaaHD4gZzYiSuQm84Fg==} + dev: true + /@types/istanbul-lib-coverage/2.0.6: resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} dev: true @@ -2786,10 +2831,25 @@ packages: resolution: {integrity: sha512-1YXyYH83h6We1djyoUEqTlVyQtCfJAFXELSKW2ZRtjHD4hQ82CC4lvrv5D0l0FLcKBaiPbXyi3MpMsI9ZRgKsw==} dev: true + /@types/linkify-it/3.0.5: + resolution: {integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==} + dev: true + /@types/lodash/4.14.182: resolution: {integrity: sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==} dev: true + /@types/markdown-it/13.0.7: + resolution: {integrity: sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==} + dependencies: + '@types/linkify-it': 3.0.5 + '@types/mdurl': 1.0.5 + dev: true + + /@types/mdurl/1.0.5: + resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} + dev: true + /@types/merge2/1.4.0: resolution: {integrity: sha512-MRHDvln2ldZELrUC8n1PGaQzZ33aNh8uDcsGehREW0zR1Fr818a4/JTZjO9eloHPPxnpUp8fz/YFTRc5CWm7Xw==} dependencies: @@ -2839,7 +2899,6 @@ packages: /@types/prop-types/15.7.11: resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} - dev: true /@types/react-dom/18.2.18: resolution: {integrity: sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==} @@ -2853,7 +2912,6 @@ packages: '@types/prop-types': 15.7.11 '@types/scheduler': 0.16.8 csstype: 3.1.3 - dev: true /@types/resolve/1.20.2: resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -2861,7 +2919,6 @@ packages: /@types/scheduler/0.16.8: resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} - dev: true /@types/semver/7.3.12: resolution: {integrity: sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==} @@ -3081,7 +3138,6 @@ packages: '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 '@visactor/vutils-extension': 1.9.0 - dev: true /@visactor/vdataset/0.17.4: resolution: {integrity: sha512-o43a4/z9J3Wr/u+5BI8G+XwtWAJSHl+Pg0+UZDYoS+lXQLJV64THokAfhWUEWrMqxnrUbdBqaPgZAozYzaZJdg==} @@ -3109,7 +3165,13 @@ packages: dependencies: '@visactor/vgrammar-util': 0.11.5 '@visactor/vutils': 0.17.4 - dev: true + + /@visactor/vgrammar-coordinate/0.5.7: + resolution: {integrity: sha512-7eDnI8Bd9IQzF7Tm1DFiJqTcpIdk79RfXHVieiG/szbCNOvxxqxWzzAbEI28GKFYUBPehRR7e33n5JsIRFp5vA==} + dependencies: + '@visactor/vgrammar-util': 0.5.7 + '@visactor/vutils': 0.13.3 + dev: false /@visactor/vgrammar-core/0.11.5: resolution: {integrity: sha512-mjhps1xC9sYvWmgVp1lV3UVl8dUT+waHhPC3hL2XDRZ+YV0e694U2HPiWlh0JsVHXerYFdjm63t1UVfy48LqRg==} @@ -3122,7 +3184,6 @@ packages: '@visactor/vrender-kits': 0.17.19 '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 - dev: true /@visactor/vgrammar-hierarchy/0.11.5: resolution: {integrity: sha512-HVsKusLuL1VwcuNXXqQA0uZ9XIQc25uLa0D3xBBwzkTxyMAvRWSmfh/sLFxnd+HiCZsV8iTXXzvyPUY9V/uOpQ==} @@ -3132,7 +3193,6 @@ packages: '@visactor/vrender-core': 0.17.19 '@visactor/vrender-kits': 0.17.19 '@visactor/vutils': 0.17.4 - dev: true /@visactor/vgrammar-projection/0.11.5: resolution: {integrity: sha512-ZzzP0UMn4iD8wIFGG/R59kJbTsN0hruyx6vxju7tYQTNCwO/n7T+JDAbjVFpVSfMmu8/xYO0NKRdJX0PqQ8iZA==} @@ -3141,7 +3201,6 @@ packages: '@visactor/vgrammar-util': 0.11.5 '@visactor/vutils': 0.17.4 d3-geo: 1.12.1 - dev: true /@visactor/vgrammar-sankey/0.11.5: resolution: {integrity: sha512-SOsMj0tj9Zu13NBErdQkKoQcyUNu3Er3BnZP85fyv0lGzdQW6m3o/T2ziVP7sZJwWm8vXwiUOI2dYEaN9zJNwQ==} @@ -3151,13 +3210,17 @@ packages: '@visactor/vrender-core': 0.17.19 '@visactor/vrender-kits': 0.17.19 '@visactor/vutils': 0.17.4 - dev: true /@visactor/vgrammar-util/0.11.5: resolution: {integrity: sha512-trbgNsbj+TBa+202Iw+ews79w0iiZSeLgoWcq80pS+2U+xiuCjjdyDe6U1sbJV/6HKtRR1mSk4dwdR0NRVs0hQ==} dependencies: '@visactor/vutils': 0.17.4 - dev: true + + /@visactor/vgrammar-util/0.5.7: + resolution: {integrity: sha512-k1UeYvUyhtzUW+s/GIt/B8uRakJzbtWUMR7PpgDJQOlXL+zdyumK2I01U1gRLaY6t6VWbpLjk32iifJfO7oQHg==} + dependencies: + '@visactor/vutils': 0.13.3 + dev: false /@visactor/vgrammar-wordcloud-shape/0.11.5: resolution: {integrity: sha512-+6hKAXZ3OaNiw3PfNcPc5K0BLz8Z6tC5F3eYdzrlLBVvzQGyea+o7LjHPMfcPH6jHhatOXsPOrXb6QAVoL9A0A==} @@ -3168,7 +3231,6 @@ packages: '@visactor/vrender-kits': 0.17.19 '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 - dev: true /@visactor/vgrammar-wordcloud/0.11.5: resolution: {integrity: sha512-zWzfs1nQyQJv/pgJHilC/DnDhe+M3u/d51bBPlaAmSNijPVY85sNSIwbGVJVuGi2zSJLmB5YbbFuZCWp23TuwA==} @@ -3178,7 +3240,26 @@ packages: '@visactor/vrender-core': 0.17.19 '@visactor/vrender-kits': 0.17.19 '@visactor/vutils': 0.17.4 - dev: true + + /@visactor/vgrammar/0.5.7: + resolution: {integrity: sha512-bm9pxj/hIs8dh2i+liKyk/wx4N+yINph9kLig+BLYXXlctjwRl4ge7Zh9PRZGOiLVLRM0WKEQt/eAdMrUCfQfg==} + dependencies: + '@visactor/vgrammar-coordinate': 0.5.7 + '@visactor/vgrammar-util': 0.5.7 + '@visactor/vrender': 0.13.14 + '@visactor/vrender-components': 0.13.17 + '@visactor/vscale': 0.13.4 + '@visactor/vutils': 0.13.3 + dev: false + + /@visactor/vrender-components/0.13.17: + resolution: {integrity: sha512-9UjNk/4g/JEm/89Cd/uUuq9As78YeUVdEP+A6uRm8v5Bryg5c4+gBZ500Hxweo8Kx2UDIAbGIDo+ioaNysDRzw==} + dependencies: + '@visactor/vrender': 0.13.14 + '@visactor/vscale': 0.13.4 + '@visactor/vutils': 0.13.3 + inversify: 6.0.1 + dev: false /@visactor/vrender-components/0.17.19: resolution: {integrity: sha512-B5Hj9n71OuWBMPo16G0HUUgHJFFiQDklwojtJvUgWmdp0gjGkbGJN4//+C1tEN1ONSAJc+uJvo2fZZMxcnpi7w==} @@ -3187,7 +3268,6 @@ packages: '@visactor/vrender-kits': 0.17.19 '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 - dev: true /@visactor/vrender-core/0.17.19: resolution: {integrity: sha512-ylqm0QDZb2vk7HbFjJrp7JES6A0LneaeFK/EYcV/A32x7U60wi8WOIwuVhHWv0rxBeQ6YzgiDbGCPnjwHux5jA==} @@ -3202,13 +3282,33 @@ packages: '@visactor/vrender-core': 0.17.19 '@visactor/vutils': 0.17.4 roughjs: 4.5.2 - dev: true + + /@visactor/vrender/0.13.14: + resolution: {integrity: sha512-Pu0l+Pg2KpwroX+pSRcZ4zzW/A6pEDo3KD4V61G/iYkaQ/ajJkwHfkSKSzo/dMKo6lipKY/r1R6svmYqBdFOEA==} + dependencies: + '@visactor/vutils': 0.13.3 + color-convert: 2.0.1 + core-js: 3.31.1 + inversify: 6.0.1 + dev: false + + /@visactor/vrender/0.17.19: + resolution: {integrity: sha512-ZQqYXPe49zQ74Rxk6k8P7e/keg29KUQG5J3hcBI+FrmR6GSegODFATnif7o7z4tfeaqGJiDcrwczdcParQSLiw==} + dependencies: + '@visactor/vrender-core': 0.17.19 + '@visactor/vrender-kits': 0.17.19 + dev: false + + /@visactor/vscale/0.13.4: + resolution: {integrity: sha512-UeyPYN+vAmvI+CURCfRN1s+peKeFDGxdblTJCgvZj/bho1oJF6WeI/mqAOquLeCT4+Y3f3SYoqIqDL5nSHJkZw==} + dependencies: + '@visactor/vutils': 0.13.3 + dev: false /@visactor/vscale/0.17.4: resolution: {integrity: sha512-gF9SWmduQxat8ct8BkDwT3C/E7aWxsqKctJ6zI+XZzL/wLD4NELnA7zUSiuRmyAunjaH87B9jNtiPcBRMviVEw==} dependencies: '@visactor/vutils': 0.17.4 - dev: true /@visactor/vutils-extension/1.9.0: resolution: {integrity: sha512-yZpk+E8tyil/Iz/0riIXQRB40H2ExfKfv0fm6UFrzGit3kigIk5vKKGe2rO2OO30FGC+V1DpG4H2U/5QKmNOIA==} @@ -3217,7 +3317,14 @@ packages: '@visactor/vrender-kits': 0.17.19 '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 - dev: true + + /@visactor/vutils/0.13.3: + resolution: {integrity: sha512-lCFiuUHwqz/0RCvIYa79ycduCLAILWaXddPOjxEd3VRX9CCoWMUmRtM3gF5JxtK2pK6Mu7hW7LaMSuWFw+0Kkw==} + dependencies: + '@turf/helpers': 6.5.0 + '@turf/invariant': 6.5.0 + eventemitter3: 4.0.7 + dev: false /@visactor/vutils/0.17.4: resolution: {integrity: sha512-tii2RpNEhXsvU+DRgadFcfo0UM/xOIZz7bxhycA624TUQdPnH/tOpdjAtSdvnjusrMmqsx8yAJa8j1imXkZLsg==} @@ -3237,7 +3344,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.23.3_@babel+core@7.20.12 magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 3.2.6_2spomixywugicrp5ojnu5wf6qy + vite: 3.2.6 transitivePeerDependencies: - supports-color dev: true @@ -3834,11 +3941,9 @@ packages: /b-tween/0.3.3: resolution: {integrity: sha512-oEHegcRpA7fAuc9KC4nktucuZn2aS8htymCPcP3qkEGPqiBH+GfqtqoG2l7LxHngg6O0HFM7hOeOYExl1Oz4ZA==} - dev: true /b-validate/1.5.3: resolution: {integrity: sha512-iCvCkGFskbaYtfQ0a3GmcQCHl/Sv1GufXFGuUQ+FE+WJa7A/espLOuFIn09B944V8/ImPj71T4+rTASxO2PAuA==} - dev: true /babel-jest/24.9.0_@babel+core@7.20.12: resolution: {integrity: sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==} @@ -4298,6 +4403,14 @@ packages: escape-string-regexp: 1.0.5 supports-color: 5.5.0 + /chalk/3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + /chalk/4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -4420,7 +4533,6 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: false /clone-buffer/1.0.0: resolution: {integrity: sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==} @@ -4502,7 +4614,6 @@ packages: dependencies: color-name: 1.1.4 simple-swizzle: 0.2.2 - dev: true /color-support/1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} @@ -4514,7 +4625,6 @@ packages: dependencies: color-convert: 1.9.3 color-string: 1.9.1 - dev: true /combined-stream/1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} @@ -4544,11 +4654,9 @@ packages: /compute-scroll-into-view/1.0.11: resolution: {integrity: sha512-uUnglJowSe0IPmWOdDtrlHXof5CTIJitfJEyITHBW6zDVOGu9Pjk5puaLM73SLcwak0L4hEjO7Td88/a6P5i7A==} - dev: true /compute-scroll-into-view/1.0.20: resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} - dev: true /concat-map/0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -4626,6 +4734,11 @@ packages: browserslist: 4.22.2 dev: false + /core-js/3.31.1: + resolution: {integrity: sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ==} + requiresBuild: true + dev: false + /core-util-is/1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} dev: true @@ -4700,7 +4813,6 @@ packages: /csstype/3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - dev: true /d/1.0.1: resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} @@ -4926,7 +5038,6 @@ packages: /detect-node-es/1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - dev: true /detect-node/2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} @@ -4975,6 +5086,17 @@ packages: dependencies: '@babel/runtime': 7.17.0 csstype: 3.1.3 + + /dom-serializer/1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + dev: true + + /domelementtype/2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} dev: true /domexception/1.0.1: @@ -4992,6 +5114,28 @@ packages: webidl-conversions: 5.0.0 dev: true + /domhandler/3.3.0: + resolution: {integrity: sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: true + + /domhandler/4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: true + + /domutils/2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + dev: true + /dotenv/16.3.2: resolution: {integrity: sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==} engines: {node: '>=12'} @@ -5082,6 +5226,15 @@ packages: dependencies: once: 1.4.0 + /entities/2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + dev: true + + /entities/3.0.1: + resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} + engines: {node: '>=0.12'} + dev: false + /env-paths/2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -6079,7 +6232,6 @@ packages: engines: {node: '>=10'} dependencies: tslib: 2.3.1 - dev: true /follow-redirects/1.15.5: resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} @@ -6163,7 +6315,6 @@ packages: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.1 - dev: false /fs-extra/8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} @@ -6710,6 +6861,11 @@ packages: hasBin: true dev: true + /highlight.js/11.9.0: + resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==} + engines: {node: '>=12.0.0'} + dev: false + /homedir-polyfill/1.0.3: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} @@ -6737,6 +6893,15 @@ packages: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true + /htmlparser2/4.1.0: + resolution: {integrity: sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==} + dependencies: + domelementtype: 2.3.0 + domhandler: 3.3.0 + domutils: 2.8.0 + entities: 2.2.0 + dev: true + /http-cache-semantics/4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} dev: true @@ -6858,6 +7023,10 @@ packages: loose-envify: 1.4.0 dev: true + /inversify/6.0.1: + resolution: {integrity: sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==} + dev: false + /invert-kv/1.0.0: resolution: {integrity: sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==} engines: {node: '>=0.10.0'} @@ -6889,7 +7058,6 @@ packages: /is-arrayish/0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - dev: true /is-async-function/2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} @@ -8458,7 +8626,6 @@ packages: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - dev: false /jsprim/1.4.2: resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} @@ -8640,6 +8807,12 @@ packages: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true + /linkify-it/4.0.1: + resolution: {integrity: sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==} + dependencies: + uc.micro: 1.0.6 + dev: false + /listenercount/1.0.1: resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} dev: false @@ -8867,6 +9040,23 @@ packages: dependencies: object-visit: 1.0.1 + /markdown-it/13.0.2: + resolution: {integrity: sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==} + hasBin: true + dependencies: + argparse: 2.0.1 + entities: 3.0.1 + linkify-it: 4.0.1 + mdurl: 1.0.1 + uc.micro: 1.0.6 + dev: false + + /marked/0.3.19: + resolution: {integrity: sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==} + engines: {node: '>=0.10.0'} + hasBin: true + dev: true + /matchdep/2.0.0: resolution: {integrity: sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==} engines: {node: '>= 0.10.0'} @@ -8892,6 +9082,10 @@ packages: blueimp-md5: 2.19.0 dev: true + /mdurl/1.0.1: + resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} + dev: false + /memoizee/0.4.15: resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==} dependencies: @@ -9254,7 +9448,6 @@ packages: /number-precision/1.6.0: resolution: {integrity: sha512-05OLPgbgmnixJw+VvEh18yNPUo3iyp4BEWJcrLu4X9W05KmMifN7Mu5exYvQXqxxeNWhvIF+j3Rij+HmddM/hQ==} - dev: true /nwsapi/2.2.7: resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} @@ -9562,7 +9755,6 @@ packages: /path-data-parser/0.1.0: resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} - dev: true /path-dirname/1.0.2: resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} @@ -9764,14 +9956,12 @@ packages: /points-on-curve/0.2.0: resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} - dev: true /points-on-path/0.2.1: resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} dependencies: path-data-parser: 0.1.0 points-on-curve: 0.2.0 - dev: true /posix-character-classes/0.1.1: resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} @@ -9945,7 +10135,6 @@ packages: dependencies: '@babel/runtime': 7.17.0 react: 18.2.0 - dev: true /react-dom/18.2.0_react@18.2.0: resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} @@ -9955,7 +10144,6 @@ packages: loose-envify: 1.4.0 react: 18.2.0 scheduler: 0.23.0 - dev: true /react-focus-lock/2.9.7_7kh72gklg5qjlh5zc6s6v3p6v4: resolution: {integrity: sha512-EfhX040SELLqnQ9JftqsmQCG49iByg8F5X5m19Er+n371OaETZ35dlNPZrLOOTlnnwD4c2Zv0KDgabDTc7dPHw==} @@ -9974,7 +10162,6 @@ packages: react-clientside-effect: 1.2.6_react@18.2.0 use-callback-ref: 1.3.1_7kh72gklg5qjlh5zc6s6v3p6v4 use-sidecar: 1.1.2_7kh72gklg5qjlh5zc6s6v3p6v4 - dev: true /react-is/16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -9999,7 +10186,6 @@ packages: react: 18.2.0 react-dom: 18.2.0_react@18.2.0 react-router: 6.9.0_react@18.2.0 - dev: true /react-router/6.9.0_react@18.2.0: resolution: {integrity: sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==} @@ -10009,7 +10195,6 @@ packages: dependencies: '@remix-run/router': 1.4.0 react: 18.2.0 - dev: true /react-transition-group/4.4.5_biqbaboplfbrettd7655fr4n2y: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} @@ -10023,14 +10208,12 @@ packages: prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - dev: true /react/18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - dev: true /read-pkg-up/1.0.1: resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} @@ -10345,7 +10528,6 @@ packages: /resize-observer-polyfill/1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} - dev: true /resolve-cwd/3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} @@ -10477,7 +10659,6 @@ packages: path-data-parser: 0.1.0 points-on-curve: 0.2.0 points-on-path: 0.2.1 - dev: true /rsvp/4.8.5: resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==} @@ -10558,13 +10739,11 @@ packages: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: loose-envify: 1.4.0 - dev: true /scroll-into-view-if-needed/2.2.20: resolution: {integrity: sha512-P9kYMrhi9f6dvWwTGpO5I3HgjSU/8Mts7xL3lkoH5xlewK7O9Obdc5WmMCzppln7bCVGNmf3qfoZXrpCeyNJXw==} dependencies: compute-scroll-into-view: 1.0.11 - dev: true /semver-compare/1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} @@ -10656,7 +10835,6 @@ packages: /shallowequal/1.1.0: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} - dev: true /shapefile/0.6.6: resolution: {integrity: sha512-rLGSWeK2ufzCVx05wYd+xrWnOOdSV7xNUW5/XFgx3Bc02hBkpMlrd2F1dDII7/jhWzv0MSyBFh5uJIy9hLdfuw==} @@ -10721,7 +10899,6 @@ packages: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} dependencies: is-arrayish: 0.3.2 - dev: true /simplify-geojson/1.0.5: resolution: {integrity: sha512-02l1W4UipP5ivNVq6kX15mAzCRIV1oI3tz0FUEyOsNiv1ltuFDjbNhO+nbv/xhbDEtKqWLYuzpWhUsJrjR/ypA==} @@ -11590,6 +11767,10 @@ packages: engines: {node: '>=4.2.0'} hasBin: true + /uc.micro/1.0.6: + resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} + dev: false + /ufo/1.3.2: resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} dev: true @@ -11683,7 +11864,6 @@ packages: /universalify/2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - dev: false /unset-value/1.0.0: resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} @@ -11758,7 +11938,6 @@ packages: '@types/react': 18.2.48 react: 18.2.0 tslib: 2.3.1 - dev: true /use-sidecar/1.1.2_7kh72gklg5qjlh5zc6s6v3p6v4: resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} @@ -11774,7 +11953,6 @@ packages: detect-node-es: 1.1.0 react: 18.2.0 tslib: 2.3.1 - dev: true /use/3.1.1: resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} @@ -11929,6 +12107,39 @@ packages: vite: 3.2.6_2spomixywugicrp5ojnu5wf6qy dev: true + /vite/3.2.6: + resolution: {integrity: sha512-nTXTxYVvaQNLoW5BQ8PNNQ3lPia57gzsQU/Khv+JvzKPku8kNZL6NMUR/qwXhMG6E+g1idqEPanomJ+VZgixEg==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.15.18 + postcss: 8.4.21 + resolve: 1.22.8 + rollup: 2.79.1 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /vite/3.2.6_2spomixywugicrp5ojnu5wf6qy: resolution: {integrity: sha512-nTXTxYVvaQNLoW5BQ8PNNQ3lPia57gzsQU/Khv+JvzKPku8kNZL6NMUR/qwXhMG6E+g1idqEPanomJ+VZgixEg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -12367,7 +12578,6 @@ packages: /yargs-parser/21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - dev: false /yargs-parser/5.0.1: resolution: {integrity: sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==} @@ -12442,7 +12652,6 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: false /yargs/7.1.2: resolution: {integrity: sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==} diff --git a/docs/assets/changelog/en/changelog.md b/docs/assets/changelog/en/changelog.md new file mode 100644 index 00000000..e6e922f6 --- /dev/null +++ b/docs/assets/changelog/en/changelog.md @@ -0,0 +1,542 @@ +# v0.17.18 + +2024-01-24 + + +**🆕 New feature** + +- **@visactor/vrender-components**: adjust the timing for label customLayoutFunc invocation +- **@visactor/vrender-components**: label component will sync maxLineWidth to maxWidth in richText +- **@visactor/vrender-kits**: compatible canvas in lynx env +- **@visactor/vrender-core**: support backgroundCornerRadius + +**🐛 Bug fix** + +- **@visactor/vrender-components**: event pos error when interactive in site +- **@visactor/vrender-kits**: fix issue with interface +- **@visactor/vrender-core**: fix issue with multiline text textBaseline, closed [#886](https://github.com/VisActor/VRender/issues/886) +- **@visactor/vrender-core**: fix issue with union empty bounds +- **@visactor/vrender-core**: richtext.textConfig supports number type text + + + +[more detail about v0.17.18](https://github.com/VisActor/VRender/releases/tag/v0.17.18) + +# v0.17.17 + +2024-01-22 + + +**🆕 New feature** + +- **@visactor/vrender-core**: html only append dom inside body +- **@visactor/vrender-core**: color support str gradient color +- **@visactor/vrender**: color support str gradient color + +**🐛 Bug fix** + +- **@visactor/vrender-components**: title support multiline +- **@visactor/vrender-kits**: fix issue with loaded tree-shaking +- **@visactor/vrender-core**: fix issue with rerun getTextBounds +- **@visactor/vrender-core**: fix issue with set image +- **@visactor/vrender-core**: fix issue with loaded tree-shaking + + + +[more detail about v0.17.17](https://github.com/VisActor/VRender/releases/tag/v0.17.17) + +# v0.17.16 + +2024-01-18 + + +**🆕 New feature** + +- **@visactor/vrender-core**: enable pass supportsPointerEvents and supportsTouchEvents + +**🐛 Bug fix** + +- **@visactor/vrender-components**: when no brush is active, brush should not call stopPropagation() + +[more detail about v0.17.16](https://github.com/VisActor/VRender/releases/tag/v0.17.16) + +# v0.17.15 + +2024-01-17 + + +**🆕 New feature** + +- **@visactor/vrender-components**: support boolean config in label +- **@visactor/vrender-core**: add supportsTouchEvents and supportsPointerEvents params + +**🐛 Bug fix** + +- **@visactor/vrender-components**: fix the flush of axis when axis label has rotate angle +- **@visactor/vrender-components**: arc label line not shown +- **@visactor/vrender-components**: error happens in line-label when line has no points +- **@visactor/vrender-core**: fix issue with html attribute +- **@visactor/vrender-core**: fix issue with env-check +- **@visactor/vrender-core**: fix issue with text background opacity + + + +[more detail about v0.17.15](https://github.com/VisActor/VRender/releases/tag/v0.17.15) + +# v0.17.14 + +2024-01-12 + +**🐛 Bug fix** +- **@visactor/vrender-core**: fix `splitRect` when rect has `x1` or `y1` +- **@visactor/vrender**: fix `splitRect` when rect has `x1` or `y1` + + +[more detail about v0.17.14](https://github.com/VisActor/VRender/releases/tag/v0.17.14) + +# v0.17.13 + +2024-01-10 + +**🆕 New feature** +- **@visactor/vrender-core**: background support opacity +**🐛 Bug fix** +- **@visactor/vrender-components**: filter out invisible indicator spec +- **@visactor/vrender-components**: `measureTextSize` needs to take into account the fonts configured on the stage theme +- **@visactor/vrender-core**: fix issue with incremental draw +- **@visactor/vrender-core**: supply the `getTheme()` api for `IStage` + + + +[more detail about v0.17.13](https://github.com/VisActor/VRender/releases/tag/v0.17.13) + +# v0.17.12 + +2024-01-10 + +**🆕 New feature** +- **@visactor/vrender-components**: support fit strategy for indicator +- **marker**: mark point support confine. fix @Visactor/VChart[#1573](https://github.com/VisActor/VRender/issues/1573) +**🐛 Bug fix** +- **marker**: fix problem of no render when set visible attr and add valid judgment logic. fix@Visactor/Vchart[#1901](https://github.com/VisActor/VRender/issues/1901) +- **datazoom**: adaptive handler text layout. fix@Visactor/VChart[#1809](https://github.com/VisActor/VRender/issues/1809) +- **datazoom**: set pickable false when zoomLock. fix @Visactor/VChart[#1565](https://github.com/VisActor/VRender/issues/1565) +- **datazoom**: handler not follow mouse after resize. fix@Visactor/Vchart[#1490](https://github.com/VisActor/VRender/issues/1490) +- **@visactor/vrender-components**: arc outside label invisible with visible label line + + + +[more detail about v0.17.12](https://github.com/VisActor/VRender/releases/tag/v0.17.12) + +# v0.17.11 + +2024-01-05 + +**🆕 New feature** +- **@visactor/vrender-core**: add backgroundFit attribute +**🐛 Bug fix** +- **@visactor/vrender-core**: fix issue with position in html attribute +- fix: label invisible when baseMark visible is false + +**Full Changelog**: https://github.com/VisActor/VRender/compare/v0.17.10...v0.17.11 + +[more detail about v0.17.11](https://github.com/VisActor/VRender/releases/tag/v0.17.11) + +# v0.17.10 + +2024-01-03 + +**🆕 New feature** +- **@visactor/vrender-components**: support `lastVisible` of LineAxis label +- **@visactor/vrender-kits**: support fillPickable and strokePickable for area, closed [#792](https://github.com/VisActor/VRender/issues/792) +- **@visactor/vrender-core**: support fillPickable and strokePickable for area, closed [#792](https://github.com/VisActor/VRender/issues/792) +- **@visactor/vrender-core**: support `lastVisible` of LineAxis label +- **@visactor/vrender**: support `lastVisible` of LineAxis label +**🐛 Bug fix** +- **@visactor/vrender-components**: fix the auto limit width of label when the label has vertical `direction` in orient top or bottom +- **@visactor/vrender-components**: fix issue with legend symbol size +- **@visactor/vrender-components**: fixed height calculation issue after multi-layer axis text rotation +- **@visactor/vrender-core**: fix issue with area-line highperformance draw +- **@visactor/vrender-core**: fix the auto limit width of label when the label has vertical `direction` in orient top or bottom +- **@visactor/vrender-core**: disable layer picker in interactive layer +- **@visactor/vrender**: fix the auto limit width of label when the label has vertical `direction` in orient top or bottom +**🔖 other** +- **@visactor/vrender-components**: 'feat: support label line in label component' + + + +[more detail about v0.17.10](https://github.com/VisActor/VRender/releases/tag/v0.17.10) + +# v0.17.9 + +2024-01-03 + +**🐛 Bug fix** +- **@visactor/vrender-components**: fix label position when offset is 0 +- **@visactor/vrender-core**: fix issue with conical cache not work as expect + + + +[more detail about v0.17.9](https://github.com/VisActor/VRender/releases/tag/v0.17.9) + +# v0.17.8 + +2023-12-29 + +**🆕 New feature** +- **@visactor/vrender-components**: optimize outer label layout in tangential direction +- **@visactor/vrender-core**: support drawGraphicToCanvas +- **@visactor/vrender**: support drawGraphicToCanvas +**🐛 Bug fix** +- **@visactor/vrender-components**: when axis label space is 0, and axis tick' inside is true, the axis label's position is not correct +- **@visactor/vrender-components**: fix morphing of rect +- **@visactor/vrender-kits**: fix issue with mapToCanvasPoint in miniapp, closed [#828](https://github.com/VisActor/VRender/issues/828) +- **@visactor/vrender-core**: fix issue with rect.toCustomPath +- **@visactor/vrender-core**: fix issue with area segment with single point, closed [#801](https://github.com/VisActor/VRender/issues/801) +- **@visactor/vrender-core**: fix issue with new Function in miniapp +- **@visactor/vrender-core**: fix morphing of rect +- **@visactor/vrender-core**: fix issue with side-effect in some env +- **@visactor/vrender-core**: fix issue with check tt env +- **@visactor/vrender-core**: fix issue with cliped attribute in vertical text, closed [#827](https://github.com/VisActor/VRender/issues/827) +- **@visactor/vrender**: fix issue with area segment with single point, closed [#801](https://github.com/VisActor/VRender/issues/801) +- **@visactor/vrender**: fix morphing of rect +- **@visactor/vrender**: fix issue with side-effect in some env + + + +[more detail about v0.17.8](https://github.com/VisActor/VRender/releases/tag/v0.17.8) + +# v0.17.7 + +2023-12-21 + +**🐛 Bug fix** +- **@visactor/vrender-kits**: fix issue with create layer in miniapp env +- **@visactor/vrender-core**: fix issue with create layer in miniapp env + + + +[more detail about v0.17.7](https://github.com/VisActor/VRender/releases/tag/v0.17.7) + +# v0.17.6 + +2023-12-20 + +**What's Changed** +* Main by @neuqzxy in https://github.com/VisActor/VRender/pull/813 +* fix: fix issue with rect stroke contribution by @neuqzxy in https://github.com/VisActor/VRender/pull/814 +* [Auto release] release 0.17.6 by @github-actions in https://github.com/VisActor/VRender/pull/815 + + +**Full Changelog**: https://github.com/VisActor/VRender/compare/v0.17.5...v0.17.6 + +[more detail about v0.17.6](https://github.com/VisActor/VRender/releases/tag/v0.17.6) + +# v0.17.5 + +2023-12-19 + +**🆕 New feature** +- **scrollbar**: dispatch scrollDown event +- **@visactor/vrender-components**: labelLine support animate +- **@visactor/vrender-components**: label don't create enter animate animationEnter while duration less than 0 +- **@visactor/vrender**: add disableAutoClipedPoptip attribute in text graphic +**🐛 Bug fix** +- **@visactor/vrender-components**: fix issue with arc animate with delayafter +- **@visactor/vrender-components**: fix issue with poptip circular dependencies +- **@visactor/vrender-core**: fix issue with plugin unregister +- **@visactor/vrender-core**: fix issue with text while whitespace is normal +- **@visactor/vrender**: fix cursor update error in multi-stage + + + +[more detail about v0.17.5](https://github.com/VisActor/VRender/releases/tag/v0.17.5) + +# v0.17.4 + +2023-12-15 + +**🐛 Bug fix** +- **datazoom**: symbol size problem +- **@visactor/vrender-core**: fix issue with arc imprecise bounds, closed [#728](https://github.com/VisActor/VRender/issues/728) + + + +[more detail about v0.17.4](https://github.com/VisActor/VRender/releases/tag/v0.17.4) + +# v0.17.3 + +2023-12-14 + +**🐛 Bug fix** +- **datazoom**: handler zindex to interaction error + + + +[more detail about v0.17.3](https://github.com/VisActor/VRender/releases/tag/v0.17.3) + +# v0.17.2 + +2023-12-14 + +**🆕 New feature** +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **@visactor/vrender-core**: rect3d support x1y1, fix -radius issue with rect +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +**🐛 Bug fix** +- **@visactor/vrender-components**: scrollbar slider width/height should not be negative +- **@visactor/vrender-components**: datazoom event block window event. fix @visactor/vchart[#1686](https://github.com/VisActor/VRender/issues/1686) +- **@visactor/vrender-components**: fix the issue of brushEnd trigger multiple times, related https://github.com/VisActor/VChart/issues/1694 +- **@visactor/vrender-core**: fix shadow pick issue +**⚡ Performance optimization** +- **@visactor/vrender-components**: optimize the `_handleStyle()` in legend + + + +[more detail about v0.17.2](https://github.com/VisActor/VRender/releases/tag/v0.17.2) + +# v0.17.1 + +2023-12-06 + +**🆕 New feature** +- **@visactor/vrender-kits**: support pickStrokeBuffer, closed [#758](https://github.com/VisActor/VRender/issues/758) +- **@visactor/vrender-core**: support pickStrokeBuffer, closed [#758](https://github.com/VisActor/VRender/issues/758) +**🐛 Bug fix** +- **@visactor/vrender-kits**: fix issue with rebind pick-contribution +- **@visactor/vrender-core**: fix issue in area chart with special points +- **@visactor/vrender-core**: fix issue with rebind pick-contribution +- **@visactor/vrender-core**: fix error with wrap text and normal whiteSpace text + + + +[more detail about v0.17.1](https://github.com/VisActor/VRender/releases/tag/v0.17.1) + +# v0.17.0 + +2023-11-30 + +**🆕 New feature** +- **@visactor/vrender-components**: optmize bounds performance +- **@visactor/vrender-kits**: rect support x1 and y1 +- **@visactor/vrender-kits**: optmize bounds performance +- **@visactor/vrender-core**: support disableCheckGraphicWidthOutRange to skip check if graphic out of range +- **@visactor/vrender-core**: rect support x1 and y1 +- **@visactor/vrender-core**: don't rewrite global reflect +- **@visactor/vrender-core**: text support background, closed [#711](https://github.com/VisActor/VRender/issues/711) +- **@visactor/vrender-core**: optmize bounds performance +- **@visactor/vrender**: don't rewrite global reflect +- **@visactor/vrender**: skip update bounds while render small node-tree, closed [#660](https://github.com/VisActor/VRender/issues/660) +- **@visactor/vrender**: optmize bounds performance +**🔨 Refactor** +- **@visactor/vrender-kits**: refact inversify completely, closed [#657](https://github.com/VisActor/VRender/issues/657) +- **@visactor/vrender-core**: refact inversify completely, closed [#657](https://github.com/VisActor/VRender/issues/657) +- **@visactor/vrender**: refact inversify completely, closed [#657](https://github.com/VisActor/VRender/issues/657) +**⚡ Performance optimization** +- **@visactor/vrender-components**: add option `skipDefault` to vrender-components +- **@visactor/vrender-core**: area support drawLinearAreaHighPerformance, closed [#672](https://github.com/VisActor/VRender/issues/672) + + + +[more detail about v0.17.0](https://github.com/VisActor/VRender/releases/tag/v0.17.0) + +# v0.16.18 + +2023-11-30 + +**🆕 New feature** +- **@visactor/vrender-components**: discrete legend's pager support position property +- **@visactor/vrender-core**: support suffixPosition, closed [#625](https://github.com/VisActor/VRender/issues/625) +- **@visactor/vrender**: support suffixPosition, closed [#625](https://github.com/VisActor/VRender/issues/625) +**🐛 Bug fix** +- **@visactor/vrender-kits**: doubletap should not be triggered when the target is different twice before and after +- **@visactor/vrender-core**: fix issue with attribute interpolate, closed [#741](https://github.com/VisActor/VRender/issues/741) +- **@visactor/vrender-core**: fix issue about calcuate bounds with shadow, closed [#474](https://github.com/VisActor/VRender/issues/474) +- **@visactor/vrender-core**: fix issue with white line in some dpr device, closed [#666](https://github.com/VisActor/VRender/issues/666) +**🔨 Refactor** +- **@visactor/vrender-components**: move getSizeHandlerPath out of sizlegend +- **@visactor/vrender-core**: event-related coordinate points do not require complex Point classes + + + +[more detail about v0.16.18](https://github.com/VisActor/VRender/releases/tag/v0.16.18) + +# v0.16.17 + +2023-11-23 + +**🆕 New feature** +- **@visactor/vrender-components**: support rich text for label, axis, marker,tooltip, indicator and title +- **@visactor/vrender-components**: add mode type of smartInvert +- **@visactor/vrender-components**: place more label for overlapPadding case +- **@visactor/vrender-kits**: support 'tap' gesture for Gesture plugin +- **@visactor/vrender-core**: add `event` config for Stage params, which can configure `clickInterval` and some other options in eventSystem +- **@visactor/vrender-core**: support fill and stroke while svg don't support, closed [#710](https://github.com/VisActor/VRender/issues/710) +**🐛 Bug fix** +- **@visactor/vrender-kits**: \`pickMode: 'imprecise'\` not work in polygon +- **@visactor/vrender-core**: richtext may throw error when textConfig is null +- **@visactor/vrender-core**: fix issue with image repeat, closed [#712](https://github.com/VisActor/VRender/issues/712) +- **@visactor/vrender-core**: fix issue with restore and save count not equal +**⚡ Performance optimization** +- **@visactor/vrender-core**: not setAttribute while background is not url, closed [#696](https://github.com/VisActor/VRender/issues/696) + + + +[more detail about v0.16.17](https://github.com/VisActor/VRender/releases/tag/v0.16.17) + +# v0.16.16 + +2023-11-17 + +**🐛 Bug fix** +- **@visactor/vrender-components**: fix the issue of legend item.shape can not set visible, related https://github.com/VisActor/VChart/issues/1508 +- **@visactor/vrender-core**: assign symbol rect function to old + + + +[more detail about v0.16.16](https://github.com/VisActor/VRender/releases/tag/v0.16.16) + +# v0.16.15 + +2023-11-16 + +**🐛 Bug fix** +- **@visactor/vrender-compoments**: legendItemHover and legendItemUnHover should trigger once + + + +[more detail about v0.16.15](https://github.com/VisActor/VRender/releases/tag/v0.16.15) + +# v0.16.14 + +2023-11-15 + +**🆕 New feature** +- **@visactor/vrender-components**: datazoom update callback supports new trigger tag param +- **@visactor/vrender-components**: support line/area label +- **@visactor/vrender-components**: lineHeight support string, which means percent +- **@visactor/vrender-core**: add round line symbol, closed [#1458](https://github.com/VisActor/VRender/issues/1458) +- **@visactor/vrender-core**: lineHeight support string, which means percent +**🐛 Bug fix** +- **@visactor/vrender-core**: fix issue with render while in scale transform + + + +[more detail about v0.16.14](https://github.com/VisActor/VRender/releases/tag/v0.16.14) + +# v0.16.13 + +2023-11-15 + +**🆕 New feature** +- **@visactor/vrender-core**: add preventRender function +- **@visactor/vrender-core**: merge wrap text function to text +**🐛 Bug fix** +- **@visactor/vrender-kits**: temp fix issue with lynx measuretext + + + +[more detail about v0.16.13](https://github.com/VisActor/VRender/releases/tag/v0.16.13) + +# v0.16.12 + +2023-11-07 + +**🆕 New feature** +- **@visactor/vrender-core**: optimize text increase animation +**🐛 Bug fix** +- **@visactor/vrender-components**: padding of title component +- **@visactor/vrender-components**: padding offset of AABBbounds +- **@visactor/vrender-kits**: fix node-canvas max count issue +- **@visactor/vrender-core**: fix node-canvas max count issue + + + +[more detail about v0.16.12](https://github.com/VisActor/VRender/releases/tag/v0.16.12) + +# v0.16.11 + +2023-11-07 + +**🐛 Bug fix** +- **@visactor/vrender-components**: optimize the auto-overlap of axis label, which use rotateBounds when text rotated, relate https://github.com/VisActor/VChart/issues/133 +- **@visactor/vrender-components**: flush should not sue width height +- **@visactor/vrender-components**: fix the lastvisible logic of axis's auto-hide +- **@visactor/vrender-kits**: fix issue with xul and html attribute, closed [#634](https://github.com/VisActor/VRender/issues/634) +- **@visactor/vrender-core**: fix issue with xul and html attribute, closed [#634](https://github.com/VisActor/VRender/issues/634) + + + +[more detail about v0.16.11](https://github.com/VisActor/VRender/releases/tag/v0.16.11) + +# v0.16.10 + +2023-11-02 + +**What's Changed** +* Sync main by @neuqzxy in https://github.com/VisActor/VRender/pull/640 +* fix: fix issue with xul and html attribute, closed [#634](https://github.com/VisActor/VRender/issues/634) by @neuqzxy in https://github.com/VisActor/VRender/pull/635 +* Echance/axis auto rotate by @kkxxkk2019 in https://github.com/VisActor/VRender/pull/633 +* [Auto release] release 0.16.9 by @github-actions in https://github.com/VisActor/VRender/pull/641 + + +**Full Changelog**: https://github.com/VisActor/VRender/compare/v0.16.9...v0.16.10 + +[more detail about v0.16.10](https://github.com/VisActor/VRender/releases/tag/v0.16.10) + +# v0.16.9 + +2023-10-27 + +**🆕 New feature** +- **@visactor/vrender-components**: add checkbox indeterminate state +- **label**: rect label support position `top-right`|`top-left`|`bottom-righ`|`bottom-left` +- **@visactor/vrender-core**: stage background support image +**🐛 Bug fix** +- **@visactor/vrender-components**: all the group container of marker do not trigger event +- **datazoom**: text bounds when visible is false. fix VisActor/VChart[#1281](https://github.com/VisActor/VRender/issues/1281) + + + +[more detail about v0.16.9](https://github.com/VisActor/VRender/releases/tag/v0.16.9) + +# v0.16.8 + +2023-10-23 + +**🐛 Bug fix** +- **@visactor/vrender-components**: fix the issue of error position of focus when legend item just has label + + + +[more detail about v0.16.8](https://github.com/VisActor/VRender/releases/tag/v0.16.8) + +# v0.16.7 + +2023-10-23 + +**🐛 Bug fix** +- **label**: fix the issue that `clampForce` does not work when`overlapPadding` is configured +- **@visactor/vrender-core**: fix issue with creating multi chart in miniapp + + + +[more detail about v0.16.7](https://github.com/VisActor/VRender/releases/tag/v0.16.7) + +# v0.16.6 + +2023-10-23 + +**🆕 New feature** +- **@visactor/vrender-components**: optimize the layout method of circle axis label +**🐛 Bug fix** +- **@visactor/vrender-components**: fix the layout issue of legend item because of the error logic of `focusStartX` + + + +[more detail about v0.16.6](https://github.com/VisActor/VRender/releases/tag/v0.16.6) + diff --git a/docs/assets/changelog/zh/changelog.md b/docs/assets/changelog/zh/changelog.md new file mode 100644 index 00000000..bdf0cc2e --- /dev/null +++ b/docs/assets/changelog/zh/changelog.md @@ -0,0 +1,542 @@ +# v0.17.18 + +2024-01-24 + + +**🆕 新增功能** + +- **@visactor/vrender-components**: adjust the timing for label customLayoutFunc invocation +- **@visactor/vrender-components**: label component will sync maxLineWidth to maxWidth in richText +- **@visactor/vrender-kits**: compatible canvas in lynx env +- **@visactor/vrender-core**: support backgroundCornerRadius + +**🐛 功能修复** + +- **@visactor/vrender-components**: event pos error when interactive in site +- **@visactor/vrender-kits**: fix issue with interface +- **@visactor/vrender-core**: fix issue with multiline text textBaseline, closed [#886](https://github.com/VisActor/VRender/issues/886) +- **@visactor/vrender-core**: fix issue with union empty bounds +- **@visactor/vrender-core**: richtext.textConfig supports number type text + + + +[更多详情请查看 v0.17.18](https://github.com/VisActor/VRender/releases/tag/v0.17.18) + +# v0.17.17 + +2024-01-22 + + +**🆕 新增功能** + +- **@visactor/vrender-core**: html only append dom inside body +- **@visactor/vrender-core**: color support str gradient color +- **@visactor/vrender**: color support str gradient color + +**🐛 功能修复** + +- **@visactor/vrender-components**: title support multiline +- **@visactor/vrender-kits**: fix issue with loaded tree-shaking +- **@visactor/vrender-core**: fix issue with rerun getTextBounds +- **@visactor/vrender-core**: fix issue with set image +- **@visactor/vrender-core**: fix issue with loaded tree-shaking + + + +[更多详情请查看 v0.17.17](https://github.com/VisActor/VRender/releases/tag/v0.17.17) + +# v0.17.16 + +2024-01-18 + + +**🆕 新增功能** + +- **@visactor/vrender-core**: enable pass supportsPointerEvents and supportsTouchEvents + +**🐛 功能修复** + +- **@visactor/vrender-components**: when no brush is active, brush should not call stopPropagation() + +[更多详情请查看 v0.17.16](https://github.com/VisActor/VRender/releases/tag/v0.17.16) + +# v0.17.15 + +2024-01-17 + + +**🆕 新增功能** + +- **@visactor/vrender-components**: support boolean config in label +- **@visactor/vrender-core**: add supportsTouchEvents and supportsPointerEvents params + +**🐛 功能修复** + +- **@visactor/vrender-components**: fix the flush of axis when axis label has rotate angle +- **@visactor/vrender-components**: arc label line not shown +- **@visactor/vrender-components**: error happens in line-label when line has no points +- **@visactor/vrender-core**: fix issue with html attribute +- **@visactor/vrender-core**: fix issue with env-check +- **@visactor/vrender-core**: fix issue with text background opacity + + + +[更多详情请查看 v0.17.15](https://github.com/VisActor/VRender/releases/tag/v0.17.15) + +# v0.17.14 + +2024-01-12 + +**🐛 功能修复** +- **@visactor/vrender-core**: fix `splitRect` when rect has `x1` or `y1` +- **@visactor/vrender**: fix `splitRect` when rect has `x1` or `y1` + + +[更多详情请查看 v0.17.14](https://github.com/VisActor/VRender/releases/tag/v0.17.14) + +# v0.17.13 + +2024-01-10 + +**🆕 新增功能** +- **@visactor/vrender-core**: background support opacity +**🐛 功能修复** +- **@visactor/vrender-components**: filter out invisible indicator spec +- **@visactor/vrender-components**: `measureTextSize` needs to take into account the fonts configured on the stage theme +- **@visactor/vrender-core**: fix issue with incremental draw +- **@visactor/vrender-core**: supply the `getTheme()` api for `IStage` + + + +[更多详情请查看 v0.17.13](https://github.com/VisActor/VRender/releases/tag/v0.17.13) + +# v0.17.12 + +2024-01-10 + +**🆕 新增功能** +- **@visactor/vrender-components**: support fit strategy for indicator +- **marker**: mark point support confine. fix @Visactor/VChart[#1573](https://github.com/VisActor/VRender/issues/1573) +**🐛 功能修复** +- **marker**: fix problem of no render when set visible attr and add valid judgment logic. fix@Visactor/Vchart[#1901](https://github.com/VisActor/VRender/issues/1901) +- **datazoom**: adaptive handler text layout. fix@Visactor/VChart[#1809](https://github.com/VisActor/VRender/issues/1809) +- **datazoom**: set pickable false when zoomLock. fix @Visactor/VChart[#1565](https://github.com/VisActor/VRender/issues/1565) +- **datazoom**: handler not follow mouse after resize. fix@Visactor/Vchart[#1490](https://github.com/VisActor/VRender/issues/1490) +- **@visactor/vrender-components**: arc outside label invisible with visible label line + + + +[更多详情请查看 v0.17.12](https://github.com/VisActor/VRender/releases/tag/v0.17.12) + +# v0.17.11 + +2024-01-05 + +**🆕 新增功能** +- **@visactor/vrender-core**: add backgroundFit attribute +**🐛 功能修复** +- **@visactor/vrender-core**: fix issue with position in html attribute +- fix: label invisible when baseMark visible is false + +**Full Changelog**: https://github.com/VisActor/VRender/compare/v0.17.10...v0.17.11 + +[更多详情请查看 v0.17.11](https://github.com/VisActor/VRender/releases/tag/v0.17.11) + +# v0.17.10 + +2024-01-03 + +**🆕 新增功能** +- **@visactor/vrender-components**: support `lastVisible` of LineAxis label +- **@visactor/vrender-kits**: support fillPickable and strokePickable for area, closed [#792](https://github.com/VisActor/VRender/issues/792) +- **@visactor/vrender-core**: support fillPickable and strokePickable for area, closed [#792](https://github.com/VisActor/VRender/issues/792) +- **@visactor/vrender-core**: support `lastVisible` of LineAxis label +- **@visactor/vrender**: support `lastVisible` of LineAxis label +**🐛 功能修复** +- **@visactor/vrender-components**: fix the auto limit width of label when the label has vertical `direction` in orient top or bottom +- **@visactor/vrender-components**: fix issue with legend symbol size +- **@visactor/vrender-components**: fixed height calculation issue after multi-layer axis text rotation +- **@visactor/vrender-core**: fix issue with area-line highperformance draw +- **@visactor/vrender-core**: fix the auto limit width of label when the label has vertical `direction` in orient top or bottom +- **@visactor/vrender-core**: disable layer picker in interactive layer +- **@visactor/vrender**: fix the auto limit width of label when the label has vertical `direction` in orient top or bottom +**🔖 其他** +- **@visactor/vrender-components**: 'feat: support label line in label component' + + + +[更多详情请查看 v0.17.10](https://github.com/VisActor/VRender/releases/tag/v0.17.10) + +# v0.17.9 + +2024-01-03 + +**🐛 功能修复** +- **@visactor/vrender-components**: fix label position when offset is 0 +- **@visactor/vrender-core**: fix issue with conical cache not work as expect + + + +[更多详情请查看 v0.17.9](https://github.com/VisActor/VRender/releases/tag/v0.17.9) + +# v0.17.8 + +2023-12-29 + +**🆕 新增功能** +- **@visactor/vrender-components**: optimize outer label layout in tangential direction +- **@visactor/vrender-core**: support drawGraphicToCanvas +- **@visactor/vrender**: support drawGraphicToCanvas +**🐛 功能修复** +- **@visactor/vrender-components**: when axis label space is 0, and axis tick' inside is true, the axis label's position is not correct +- **@visactor/vrender-components**: fix morphing of rect +- **@visactor/vrender-kits**: fix issue with mapToCanvasPoint in miniapp, closed [#828](https://github.com/VisActor/VRender/issues/828) +- **@visactor/vrender-core**: fix issue with rect.toCustomPath +- **@visactor/vrender-core**: fix issue with area segment with single point, closed [#801](https://github.com/VisActor/VRender/issues/801) +- **@visactor/vrender-core**: fix issue with new Function in miniapp +- **@visactor/vrender-core**: fix morphing of rect +- **@visactor/vrender-core**: fix issue with side-effect in some env +- **@visactor/vrender-core**: fix issue with check tt env +- **@visactor/vrender-core**: fix issue with cliped attribute in vertical text, closed [#827](https://github.com/VisActor/VRender/issues/827) +- **@visactor/vrender**: fix issue with area segment with single point, closed [#801](https://github.com/VisActor/VRender/issues/801) +- **@visactor/vrender**: fix morphing of rect +- **@visactor/vrender**: fix issue with side-effect in some env + + + +[更多详情请查看 v0.17.8](https://github.com/VisActor/VRender/releases/tag/v0.17.8) + +# v0.17.7 + +2023-12-21 + +**🐛 功能修复** +- **@visactor/vrender-kits**: fix issue with create layer in miniapp env +- **@visactor/vrender-core**: fix issue with create layer in miniapp env + + + +[更多详情请查看 v0.17.7](https://github.com/VisActor/VRender/releases/tag/v0.17.7) + +# v0.17.6 + +2023-12-20 + +**What's Changed** +* Main by @neuqzxy in https://github.com/VisActor/VRender/pull/813 +* fix: fix issue with rect stroke contribution by @neuqzxy in https://github.com/VisActor/VRender/pull/814 +* [Auto release] release 0.17.6 by @github-actions in https://github.com/VisActor/VRender/pull/815 + + +**Full Changelog**: https://github.com/VisActor/VRender/compare/v0.17.5...v0.17.6 + +[更多详情请查看 v0.17.6](https://github.com/VisActor/VRender/releases/tag/v0.17.6) + +# v0.17.5 + +2023-12-19 + +**🆕 新增功能** +- **scrollbar**: dispatch scrollDown event +- **@visactor/vrender-components**: labelLine support animate +- **@visactor/vrender-components**: label don't create enter animate animationEnter while duration less than 0 +- **@visactor/vrender**: add disableAutoClipedPoptip attribute in text graphic +**🐛 功能修复** +- **@visactor/vrender-components**: fix issue with arc animate with delayafter +- **@visactor/vrender-components**: fix issue with poptip circular dependencies +- **@visactor/vrender-core**: fix issue with plugin unregister +- **@visactor/vrender-core**: fix issue with text while whitespace is normal +- **@visactor/vrender**: fix cursor update error in multi-stage + + + +[更多详情请查看 v0.17.5](https://github.com/VisActor/VRender/releases/tag/v0.17.5) + +# v0.17.4 + +2023-12-15 + +**🐛 功能修复** +- **datazoom**: symbol size problem +- **@visactor/vrender-core**: fix issue with arc imprecise bounds, closed [#728](https://github.com/VisActor/VRender/issues/728) + + + +[更多详情请查看 v0.17.4](https://github.com/VisActor/VRender/releases/tag/v0.17.4) + +# v0.17.3 + +2023-12-14 + +**🐛 功能修复** +- **datazoom**: handler zindex to interaction error + + + +[更多详情请查看 v0.17.3](https://github.com/VisActor/VRender/releases/tag/v0.17.3) + +# v0.17.2 + +2023-12-14 + +**🆕 新增功能** +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +- **@visactor/vrender-core**: rect3d support x1y1, fix -radius issue with rect +- **dataZoom**: add mask to modify hot zone. feat @visactor/vchart[#1415](https://github.com/VisActor/VRender/issues/1415)' +**🐛 功能修复** +- **@visactor/vrender-components**: scrollbar slider width/height should not be negative +- **@visactor/vrender-components**: datazoom event block window event. fix @visactor/vchart[#1686](https://github.com/VisActor/VRender/issues/1686) +- **@visactor/vrender-components**: fix the issue of brushEnd trigger multiple times, related https://github.com/VisActor/VChart/issues/1694 +- **@visactor/vrender-core**: fix shadow pick issue +**⚡ 性能优化** +- **@visactor/vrender-components**: optimize the `_handleStyle()` in legend + + + +[更多详情请查看 v0.17.2](https://github.com/VisActor/VRender/releases/tag/v0.17.2) + +# v0.17.1 + +2023-12-06 + +**🆕 新增功能** +- **@visactor/vrender-kits**: support pickStrokeBuffer, closed [#758](https://github.com/VisActor/VRender/issues/758) +- **@visactor/vrender-core**: support pickStrokeBuffer, closed [#758](https://github.com/VisActor/VRender/issues/758) +**🐛 功能修复** +- **@visactor/vrender-kits**: fix issue with rebind pick-contribution +- **@visactor/vrender-core**: fix issue in area chart with special points +- **@visactor/vrender-core**: fix issue with rebind pick-contribution +- **@visactor/vrender-core**: fix error with wrap text and normal whiteSpace text + + + +[更多详情请查看 v0.17.1](https://github.com/VisActor/VRender/releases/tag/v0.17.1) + +# v0.17.0 + +2023-11-30 + +**🆕 新增功能** +- **@visactor/vrender-components**: optmize bounds performance +- **@visactor/vrender-kits**: rect support x1 and y1 +- **@visactor/vrender-kits**: optmize bounds performance +- **@visactor/vrender-core**: support disableCheckGraphicWidthOutRange to skip check if graphic out of range +- **@visactor/vrender-core**: rect support x1 and y1 +- **@visactor/vrender-core**: don't rewrite global reflect +- **@visactor/vrender-core**: text support background, closed [#711](https://github.com/VisActor/VRender/issues/711) +- **@visactor/vrender-core**: optmize bounds performance +- **@visactor/vrender**: don't rewrite global reflect +- **@visactor/vrender**: skip update bounds while render small node-tree, closed [#660](https://github.com/VisActor/VRender/issues/660) +- **@visactor/vrender**: optmize bounds performance +**🔨 功能重构** +- **@visactor/vrender-kits**: refact inversify completely, closed [#657](https://github.com/VisActor/VRender/issues/657) +- **@visactor/vrender-core**: refact inversify completely, closed [#657](https://github.com/VisActor/VRender/issues/657) +- **@visactor/vrender**: refact inversify completely, closed [#657](https://github.com/VisActor/VRender/issues/657) +**⚡ 性能优化** +- **@visactor/vrender-components**: add option `skipDefault` to vrender-components +- **@visactor/vrender-core**: area support drawLinearAreaHighPerformance, closed [#672](https://github.com/VisActor/VRender/issues/672) + + + +[更多详情请查看 v0.17.0](https://github.com/VisActor/VRender/releases/tag/v0.17.0) + +# v0.16.18 + +2023-11-30 + +**🆕 新增功能** +- **@visactor/vrender-components**: discrete legend's pager support position property +- **@visactor/vrender-core**: support suffixPosition, closed [#625](https://github.com/VisActor/VRender/issues/625) +- **@visactor/vrender**: support suffixPosition, closed [#625](https://github.com/VisActor/VRender/issues/625) +**🐛 功能修复** +- **@visactor/vrender-kits**: doubletap should not be triggered when the target is different twice before and after +- **@visactor/vrender-core**: fix issue with attribute interpolate, closed [#741](https://github.com/VisActor/VRender/issues/741) +- **@visactor/vrender-core**: fix issue about calcuate bounds with shadow, closed [#474](https://github.com/VisActor/VRender/issues/474) +- **@visactor/vrender-core**: fix issue with white line in some dpr device, closed [#666](https://github.com/VisActor/VRender/issues/666) +**🔨 功能重构** +- **@visactor/vrender-components**: move getSizeHandlerPath out of sizlegend +- **@visactor/vrender-core**: event-related coordinate points do not require complex Point classes + + + +[更多详情请查看 v0.16.18](https://github.com/VisActor/VRender/releases/tag/v0.16.18) + +# v0.16.17 + +2023-11-23 + +**🆕 新增功能** +- **@visactor/vrender-components**: support rich text for label, axis, marker,tooltip, indicator and title +- **@visactor/vrender-components**: add mode type of smartInvert +- **@visactor/vrender-components**: place more label for overlapPadding case +- **@visactor/vrender-kits**: support 'tap' gesture for Gesture plugin +- **@visactor/vrender-core**: add `event` config for Stage params, which can configure `clickInterval` and some other options in eventSystem +- **@visactor/vrender-core**: support fill and stroke while svg don't support, closed [#710](https://github.com/VisActor/VRender/issues/710) +**🐛 功能修复** +- **@visactor/vrender-kits**: \`pickMode: 'imprecise'\` not work in polygon +- **@visactor/vrender-core**: richtext may throw error when textConfig is null +- **@visactor/vrender-core**: fix issue with image repeat, closed [#712](https://github.com/VisActor/VRender/issues/712) +- **@visactor/vrender-core**: fix issue with restore and save count not equal +**⚡ 性能优化** +- **@visactor/vrender-core**: not setAttribute while background is not url, closed [#696](https://github.com/VisActor/VRender/issues/696) + + + +[更多详情请查看 v0.16.17](https://github.com/VisActor/VRender/releases/tag/v0.16.17) + +# v0.16.16 + +2023-11-17 + +**🐛 功能修复** +- **@visactor/vrender-components**: fix the issue of legend item.shape can not set visible, related https://github.com/VisActor/VChart/issues/1508 +- **@visactor/vrender-core**: assign symbol rect function to old + + + +[更多详情请查看 v0.16.16](https://github.com/VisActor/VRender/releases/tag/v0.16.16) + +# v0.16.15 + +2023-11-16 + +**🐛 功能修复** +- **@visactor/vrender-compoments**: legendItemHover and legendItemUnHover should trigger once + + + +[更多详情请查看 v0.16.15](https://github.com/VisActor/VRender/releases/tag/v0.16.15) + +# v0.16.14 + +2023-11-15 + +**🆕 新增功能** +- **@visactor/vrender-components**: datazoom update callback supports new trigger tag param +- **@visactor/vrender-components**: support line/area label +- **@visactor/vrender-components**: lineHeight support string, which means percent +- **@visactor/vrender-core**: add round line symbol, closed [#1458](https://github.com/VisActor/VRender/issues/1458) +- **@visactor/vrender-core**: lineHeight support string, which means percent +**🐛 功能修复** +- **@visactor/vrender-core**: fix issue with render while in scale transform + + + +[更多详情请查看 v0.16.14](https://github.com/VisActor/VRender/releases/tag/v0.16.14) + +# v0.16.13 + +2023-11-15 + +**🆕 新增功能** +- **@visactor/vrender-core**: add preventRender function +- **@visactor/vrender-core**: merge wrap text function to text +**🐛 功能修复** +- **@visactor/vrender-kits**: temp fix issue with lynx measuretext + + + +[更多详情请查看 v0.16.13](https://github.com/VisActor/VRender/releases/tag/v0.16.13) + +# v0.16.12 + +2023-11-07 + +**🆕 新增功能** +- **@visactor/vrender-core**: optimize text increase animation +**🐛 功能修复** +- **@visactor/vrender-components**: padding of title component +- **@visactor/vrender-components**: padding offset of AABBbounds +- **@visactor/vrender-kits**: fix node-canvas max count issue +- **@visactor/vrender-core**: fix node-canvas max count issue + + + +[更多详情请查看 v0.16.12](https://github.com/VisActor/VRender/releases/tag/v0.16.12) + +# v0.16.11 + +2023-11-07 + +**🐛 功能修复** +- **@visactor/vrender-components**: optimize the auto-overlap of axis label, which use rotateBounds when text rotated, relate https://github.com/VisActor/VChart/issues/133 +- **@visactor/vrender-components**: flush should not sue width height +- **@visactor/vrender-components**: fix the lastvisible logic of axis's auto-hide +- **@visactor/vrender-kits**: fix issue with xul and html attribute, closed [#634](https://github.com/VisActor/VRender/issues/634) +- **@visactor/vrender-core**: fix issue with xul and html attribute, closed [#634](https://github.com/VisActor/VRender/issues/634) + + + +[更多详情请查看 v0.16.11](https://github.com/VisActor/VRender/releases/tag/v0.16.11) + +# v0.16.10 + +2023-11-02 + +**What's Changed** +* Sync main by @neuqzxy in https://github.com/VisActor/VRender/pull/640 +* fix: fix issue with xul and html attribute, closed [#634](https://github.com/VisActor/VRender/issues/634) by @neuqzxy in https://github.com/VisActor/VRender/pull/635 +* Echance/axis auto rotate by @kkxxkk2019 in https://github.com/VisActor/VRender/pull/633 +* [Auto release] release 0.16.9 by @github-actions in https://github.com/VisActor/VRender/pull/641 + + +**Full Changelog**: https://github.com/VisActor/VRender/compare/v0.16.9...v0.16.10 + +[更多详情请查看 v0.16.10](https://github.com/VisActor/VRender/releases/tag/v0.16.10) + +# v0.16.9 + +2023-10-27 + +**🆕 新增功能** +- **@visactor/vrender-components**: add checkbox indeterminate state +- **label**: rect label support position `top-right`|`top-left`|`bottom-righ`|`bottom-left` +- **@visactor/vrender-core**: stage background support image +**🐛 功能修复** +- **@visactor/vrender-components**: all the group container of marker do not trigger event +- **datazoom**: text bounds when visible is false. fix VisActor/VChart[#1281](https://github.com/VisActor/VRender/issues/1281) + + + +[更多详情请查看 v0.16.9](https://github.com/VisActor/VRender/releases/tag/v0.16.9) + +# v0.16.8 + +2023-10-23 + +**🐛 功能修复** +- **@visactor/vrender-components**: fix the issue of error position of focus when legend item just has label + + + +[更多详情请查看 v0.16.8](https://github.com/VisActor/VRender/releases/tag/v0.16.8) + +# v0.16.7 + +2023-10-23 + +**🐛 功能修复** +- **label**: fix the issue that `clampForce` does not work when`overlapPadding` is configured +- **@visactor/vrender-core**: fix issue with creating multi chart in miniapp + + + +[更多详情请查看 v0.16.7](https://github.com/VisActor/VRender/releases/tag/v0.16.7) + +# v0.16.6 + +2023-10-23 + +**🆕 新增功能** +- **@visactor/vrender-components**: optimize the layout method of circle axis label +**🐛 功能修复** +- **@visactor/vrender-components**: fix the layout issue of legend item because of the error logic of `focusStartX` + + + +[更多详情请查看 v0.16.6](https://github.com/VisActor/VRender/releases/tag/v0.16.6) + diff --git a/docs/assets/guide/en/Basic/How_to_Get_VRender.md b/docs/assets/guide/en/Basic/How_to_Get_VRender.md new file mode 100644 index 00000000..861a84cb --- /dev/null +++ b/docs/assets/guide/en/Basic/How_to_Get_VRender.md @@ -0,0 +1,38 @@ +# How to Get VRender + +There are several ways to get VRender: + +- Get it from npm +- Get it from cdn +- Get it from GitHub repository + +## npm Get + +```bash +# npm +$ npm install @visactor/vrender + +# yarn +$ yarn add @visactor/vrender +``` + +For how to use it when getting, see [How to Import VRender in a Project](./How_to_Import_VRender). + +## cdn Get + +You can get VRender from the following free CDNs: + +```html + + + + + +``` + +## GitHub Get + +You can get the VRender source code directly from GitHub: + +- You can directly clone the source code from GitHub. +- You can also select the corresponding version from the VRender [release](https://github.com/VisActor/VChart/releases) page, click on the Source code in the Assets section at the bottom of the page, download it to your local machine, extract it and use it. diff --git a/docs/assets/guide/en/Basic/How_to_Import_VRender.md b/docs/assets/guide/en/Basic/How_to_Import_VRender.md new file mode 100644 index 00000000..516730c4 --- /dev/null +++ b/docs/assets/guide/en/Basic/How_to_Import_VRender.md @@ -0,0 +1,11 @@ +# How to Reference VChart in the Project + +In the [How to Get VRender](./How_to_Get_VRender) chapter, we introduced the ways to obtain VRender. This chapter will introduce how to reference VRender under these acquisition methods. + +## Use of CDN + +After obtaining the VChart file from [cdn](./How_to_Get_VRender#cdn-%E8%8E%B7%E5%8F%96), it can be added to the ` +``` + +## Introducing VRender + +### Import VRender via NPM Package + +Use `import` to introduce VRender at the top of the JavaScript file: + +```js +import VRender from '@visactor/vrender'; +``` + +### Import VRender using the script tag + +Introduce the built vchart file directly by adding a ` + + +``` + +## Drawing a Circle + +Before we draw, we can prepare a DOM container with width and height for VRender. + +```html + + +
+ +``` + +Next, let's create a `Stage` instance based on this Canvas, create a circle and add it to the `Stage`: + +```ts +// Create a stage +const stage = createStage({ + canvas: 'main', + autoRender: true // Enable automatic rendering +}); +// Create a circle element +const circle = createCircle({ + radius: 60, + x: 200, + y: 200, + fill: 'red', +}); +// Add it to the stage +stage.defaultLayer.add(circle); +``` + +At this point, you have successfully drawn a red circle! + +```javascript +// Create a stage +const stage = createStage({ + canvas: 'main', + autoRender: true // Enable automatic rendering +}); +// Create a circle element +const circle = createCircle({ + radius: 60, + x: 200, + y: 200, + fill: 'red', +}); +// Listen to click events, then change fill color to green +circle.addEventListener('click', () => { + circle.setAttribute('fill', 'green'); +}); +// Add it to the stage +stage.defaultLayer.add(circle); +``` + +We hope this tutorial helps you learn how to use VChart. Now you can try drawing different types of charts and customize more diverse chart effects by understanding in depth the various configuration options of VChart. Embark on your VChart journey bravely! \ No newline at end of file diff --git a/docs/assets/guide/en/VMind_Website_Guide.md b/docs/assets/guide/en/VMind_Website_Guide.md new file mode 100644 index 00000000..c1d2b05c --- /dev/null +++ b/docs/assets/guide/en/VMind_Website_Guide.md @@ -0,0 +1,57 @@ +# Site Guide + +This document is mainly to help you make better use of the VRender site and help you get the content you want on the site as quickly as possible. + +## Quick Start + +### Getting Started + +First, you need to complete the VRender [Getting Started](./Getting_Started) chapter which will teach you how to configure and use the environment needed for VRender, as well as how to use VRender to build your first graphic application. + +### Understanding VRender + +After completing [Getting Started](./Getting_Started), you can delve deeper into the various primitives and interactions supported by studying the [Primitives and Interactions](./Your_First_Chart) chapter, then learn the [Animation] chapter to understand how to create an animation, and then learn the [Extensions and Plugins]() chapter to understand how to enhance the functionality of the application through extensions and plugins. + +## Documentation + +VRender's documentation provides detailed information about features and configurations. Depending on your needs, you can view the following sections: + +- [Tutorials](./todo): Introduces the basic concepts of VRender and various usage methods. + +- [Configuration Items](./todo): Provides all configuration items for VRender and their detailed explanations. + +- [API](./todo): Provides detailed descriptions of all available interfaces for VRender. + +## Examples + +The examples page offers many practical application cases of VRender, from simple primitives to complex animations and custom extensions. Each example provides a detailed description, key configuration information, and source code. You can also modify the example and view the effect through the online editor. + +![Chart Example](./images/examples.png) + +## How to use the search function + +The site offers a powerful search feature that allows you to quickly find related usage information. Click the search box at the top of the site, enter a keyword, and you will see matching results in the dropdown list. Select the appropriate result to view the relevant content. + +![How to use the search feature](./images/search-function.png) + +## How to Ask Questions & Suggestions + +We are happy to help! If you encounter any problems while learning VRender, you can ask questions in the following ways: + +1. Submit an issue in the GitHub repository: Visit [VRender GitHub](https://github.com/VisActor/VChart/issues/new/choose), describe in detail the problem you encountered, and our team will respond and resolve as soon as possible. + +2. Submit a discussion in the GitHub repository: Visit [VRender Discussion](https://github.com/VisActor/VChart/discussions), we are very welcome to propose your ideas and suggestions here, and our team will respond and resolve as soon as possible. + +## How to Report Errors + +If you find any problems in the documentation or examples, or think some parts can be improved, please let us know. You can provide us with error correction information in the following ways: + +1. Submit a pull request in the GitHub repository: Correct the content and submit, and a team member will review and merge. + +2. Submit an issue: Point out the problem in the documentation, and team members will verify and correct it as soon as possible. + +Thank you for your help! We will continue to improve the documentation and provide a better learning experience for all VRender users. + +# Subpage Directory + +Currently unable to display this content outside the Feishu document. \ No newline at end of file diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json new file mode 100644 index 00000000..88ce5c44 --- /dev/null +++ b/docs/assets/guide/menu.json @@ -0,0 +1,79 @@ +{ + "menu": "scripts", + "children": [ + { + "path": "VMind_Website_Guide", + "title": { + "zh": "VMind站点指引", + "en": "VMind Website Guide" + } + }, + { + "path": "Getting_Started", + "title": { + "zh": "快速上手", + "en": "Getting Started" + } + }, + { + "path": "Basic", + "title": { + "zh": "入门", + "en": "Basic" + }, + "children": [ + { + "path": "How_to_Get_VRender", + "title": { + "zh": "如何获取VRender", + "en": "How to Get VRender" + } + }, + { + "path": "How_to_Import_VRender", + "title": { + "zh": "如何在项目中引用 VRender", + "en": "How to Import VRender" + } + } + ] + }, + { + "path": "Basic_Tutorial", + "title": { + "zh": "基础教程", + "en": "Basic Tutorial" + }, + "children": [ + { + "path": "Events_and_Animation", + "title": { + "zh": "了解事件和动画", + "en": "Events and Animation" + } + }, + { + "path": "Animate", + "title": { + "zh": "动画", + "en": "Animate" + } + }, + { + "path": "Cross_platform_Interface", + "title": { + "zh": "跨端接口", + "en": "Cross platform Interface" + } + }, + { + "path": "Extensions_and_Plugins", + "title": { + "zh": "扩展和插件", + "en": "Extensions and Plugins" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/docs/assets/guide/zh/Basic/How_to_Get_VRender.md b/docs/assets/guide/zh/Basic/How_to_Get_VRender.md new file mode 100644 index 00000000..eb322f81 --- /dev/null +++ b/docs/assets/guide/zh/Basic/How_to_Get_VRender.md @@ -0,0 +1,38 @@ +# 如何获取 VRender + +获取 VRender 的方式有以下几种: + +- 从 npm 获取 +- 从 cdn 获取 +- 从 GitHub 仓库获取 + +## npm 获取 + +```bash +# npm +$ npm install @visactor/vrender + +# yarn +$ yarn add @visactor/vrender +``` + +获取时候如何使用,详见[如何在项目中引用 VRender](./How_to_Import_VRender)。 + +## cdn 获取 + +可以从以下免费的 CDN 中获取 VRender: + +```html + + + + + +``` + +## GitHub 获取 + +从 GitHub 上你可以直接获取 VRender 的源码: + +- 你可以直接从 GitHub clone 源码。 +- 你也可以从 VRender 的  [release](https://github.com/VisActor/VChart/releases)  页面选择对应的版本,点击页面下方 Assets 中的 Source code,将其下载至本地解压后使用。 diff --git a/docs/assets/guide/zh/Basic/How_to_Import_VRender.md b/docs/assets/guide/zh/Basic/How_to_Import_VRender.md new file mode 100644 index 00000000..c1240930 --- /dev/null +++ b/docs/assets/guide/zh/Basic/How_to_Import_VRender.md @@ -0,0 +1,11 @@ +# 如何在项目中引用 VChart + +在[如何获取 VRender](./How_to_Get_VRender)章节中我们介绍了获取 VRender 的方式,本章节会一一介绍这些获取方式下如何引用 VRender。 + +## cdn 使用 + +我们从  [cdn](./How_to_Get_VRender#cdn-%E8%8E%B7%E5%8F%96)  获取到 VChart 文件后,就可以将其添加到 HTML 文件的  ` +``` + +## 引入 VRender + +### 通过 NPM 包引入 + +在 JavaScript 文件顶部使用 `import` 引入 VRender: + +```js +import VRender from '@visactor/vrender'; +``` + +### 使用 script 标签引入 + +通过直接在 HTML 文件中添加 ` + + +``` + +## 绘制一个圆形 + +在绘图前我们可以为 VRender 准备一个具备高宽的 DOM 容器。 + +```html + + +
+ +``` + +接下来,我们基于这个Canvas创建一个 `Stage` 实例,创建一个圆形并添加到`Stage`中: + +```ts +// 创建一个stage +const stage = createStage({ + canvas: 'main', + autoRender: true // 开启自动渲染 +}); +// 创建一个circle图元 +const circle = createCircle({ + radius: 60, + x: 200, + y: 200, + fill: 'red', +}); +// 添加到stage中 +stage.defaultLayer.add(circle); +``` + +至此,你已经成功绘制出了一个红色的圆形! + +```javascript +// 创建一个stage +const stage = createStage({ + canvas: 'main', + autoRender: true // 开启自动渲染 +}); +// 创建一个circle图元 +const circle = createCircle({ + radius: 60, + x: 200, + y: 200, + fill: 'red', +}); +// 监听点击事件,然后填充色变成绿色 +circle.addEventListener('click', () => { + circle.setAttribute('fill', 'green'); +}); +// 添加到stage中 +stage.defaultLayer.add(circle); +``` + +希望这篇教程对你学习如何使用 VChart 有所帮助。现在,你可以尝试绘制不同类型的图表,并通过深入了解 VChart 的各种配置选项,定制出更加丰富多样的图表效果。勇敢开始你的 VChart 之旅吧! \ No newline at end of file diff --git a/docs/assets/guide/zh/VMind_Website_Guide.md b/docs/assets/guide/zh/VMind_Website_Guide.md new file mode 100644 index 00000000..4bee803a --- /dev/null +++ b/docs/assets/guide/zh/VMind_Website_Guide.md @@ -0,0 +1,56 @@ +# 站点指引 + +本文档主要是为了帮助你更好地使用 VMind 站点,帮助你更快得在站点上获取你想要的内容。 + +## 快速开始 + +### 快速上手 + +首先,你需要完成 VMind [快速上手](./Getting_Started) 这个章节它将教你如何配置和使用 VMind 需要的环境,以及如何使用VMind构建你的第一个智能可视化应用。 + +### 了解VMind + +在你完成[快速上手](./Getting_Started)后,你可以通过学习[图元与交互](./Your_First_Chart)章节来深入了解支持的各种图元与交互,然后学习[动画]章节来了解如何创建一个动画,然后学习[扩展和插件]()章节来了解如何通过扩展和插件增强应用程序的功能 + +## 文档 + +VRender 的文档提供了有关功能和配置的详细信息。根据你的需求,你可以查看以下几个部分: + +- [教程](./todo):介绍了 VRender 的基本概念和各种使用方法。 + +- [配置项](./todo):提供了 VRender 的所有配置项及其详细说明。 + +- [API](./todo):提供了 VRender 的所有可用接口的详细说明。 + + +## 示例 + +示例页面提供了许多关于 VRender 的实际应用案例从简单的图元到复杂的动画和自定义扩展。每个示例都提供了详细的描述、关键配置信息以及源代码,你也可以通过在线编辑器修改示例并查看效果。 + +## 如何使用搜索功能 + +本站点提供了一个强大的搜索功能,让你可以快速找到相关的使用信息。点击站点顶部的搜索框,输入关键词后,你将在下拉列表中看到匹配的结果。选择合适的结果即可查看相关内容。 + +## 如何提问&建议 + +我们很高兴为你提供帮助! 如果你在学习 VRender 过程中遇到问题,可以通过以下方式提问: + +1. 在 GitHub 仓库中提交一个 issue:访问 [VRender GitHub](https://github.com/VisActor/VChart/issues/new/choose),详细描述你遇到的问题,我们的团队将尽快回应并解决。 + +2. 在 GitHub 仓库提交一个 discussion:访问 [VRender Discussion](https://github.com/VisActor/VChart/discussions),非常欢迎你在这里提出你的想法和建议,我们的团队将尽快回应并解决。 + + +## 如何纠错 + +如果你在文档示例中发现问题,或者认为某些部分可以改进务必告诉我们。你可以通过以下方式为我们提纠错信息: + +1. 在 GitHub 仓库中提交一个 pull request:纠正的内容并提交,会有团队成员审核并合并。 + +2. 提交一个 issue:指出文档中存在的问题团队成员会尽快核实并修正。 + + +感谢你的帮助!我们将不断完善文档,为所有 VRender 用户提供更好的学习体验。 + +# 子页面目录 + +暂时无法在飞书文档外展示此内容 diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..a46c95e1 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,15 @@ + + + + Documents Site + + + + + + + +
+ + + diff --git a/docs/index.js b/docs/index.js new file mode 100644 index 00000000..afe19eaa --- /dev/null +++ b/docs/index.js @@ -0,0 +1,155 @@ +/** + * Usage: + * example command: node ./download-documents.js path=./examples token=1e7a4c5b-893e-580f-96f2-29e62d5de99c routeId=186 + * arguments: + * path: target directory to store documents + * token: cms site token + * routeId: top route id for cms site + * + * target directory structure: + * entry: + * zh: xx.md / dir + * en: xx.md / dir + */ + +const fs = require('fs'); +const path = require('path'); +const fetch = require('node-fetch-commonjs'); + +// configs +const languages = ['zh', 'en']; +const ignores = ['README.md', 'readme.md']; + +// CMS Domain + +const CMSDomain = 'https://cms-cn.zijieapi.com'; +// arguments +const arguments = process.argv.slice(2); + +let targetDirectory = path.resolve(__dirname); +let token = ''; +let routeId = -1; +for (const argument of arguments) { + if (argument.startsWith('path=')) { + targetDirectory = argument.split('path=')[1]; + } else if (argument.startsWith('token=')) { + token = argument.split('token=')[1]; + } else if (argument.startsWith('routeId=')) { + routeId = argument.split('routeId=')[1]; + } +} +if (token === '') { + console.error('Invalid parameters! Please refer to the cms config in the scripts.'); +} +targetDirectory = path.resolve(targetDirectory); +const targetEntry = targetDirectory.split('/')[targetDirectory.split('/').length - 1]; + +async function fetchCMSData(token, url, plain) { + const response = await fetch(`${CMSDomain}${url}`, { + method: 'GET', + mode: 'cors', + cache: 'default', + headers: { + // 'Access-Control-Allow-Origin': '*', + 'Content-Type': 'application/json', + Authorization: token + } + }); + const json = await response.json(); + const data = plain ? json : json?.data; + return data; +} + +async function fetchRoutes(routeId, token) { + if (routeId === -1) { + const routeData = await fetchCMSData(token, `/api/open/site`, false); + return routeData.routes; + } + const routeData = await fetchCMSData(token, `/api/open/site/top/${routeId}`, false); + return routeData[0].children; +} + +async function generateRouteData(route, parentMenuItem, rootDirectory, directory, token) { + // not downloading any readme file + if (route.path.indexOf('README') >= 0) { + return; + } + if (route.children) { + for (const language of languages) { + const targetPath = path.join(rootDirectory, language, directory, route.path); + // create directory + if (!fs.existsSync(targetPath)) { + fs.mkdirSync(targetPath); + } + } + const menuItem = { + path: route.path, + title: { + zh: route.name['1'], + en: route.name['2'] + }, + children: [] + }; + parentMenuItem.children.push(menuItem); + for (const subRoute of route.children) { + await generateRouteData(subRoute, menuItem, rootDirectory, path.join(directory, route.path), token); + } + } else { + const menuItem = { + path: route.path, + title: {} + }; + parentMenuItem.children.push(menuItem); + for (const language of languages) { + const languageIndex = languages.indexOf(language) + 1; + const document = await fetchCMSData( + token, + `/api/open/document?fullPath=${route.fullPath}&language=${languageIndex}`, + false + ); + const content = document[0].content; + if (!content || content === '') { + console.log(`Empty document: ${route.fullPath}`); + return; + } + const meta = JSON.parse(document[0].meta); + menuItem.title[language] = meta.title; + const targetPath = path.resolve(rootDirectory, language, directory, `${route.path}.md`); + fs.writeFileSync(targetPath, content, { encoding: 'utf8' }); + } + console.log(`Generate document: ${route.fullPath}`); + } +} + +// token = tokenEnum.vtableGuide; +// // routeId = vchartExampleRouteId; +// targetDirectory = './tutorials'; + +async function run() { + const routes = await fetchRoutes(routeId, token); + + const menu = { + menu: targetEntry, + children: [] + }; + const targetFullPath = path.resolve(targetDirectory); + if (!fs.existsSync(targetFullPath)) { + fs.mkdirSync(targetFullPath); + } + for (const language of languages) { + const languageFullPath = path.join(targetDirectory, language); + if (!fs.existsSync(languageFullPath)) { + fs.mkdirSync(languageFullPath); + } + } + for (const route of routes) { + await generateRouteData(route, menu, targetFullPath, '', token); + } + const menuResult = JSON.stringify(menu, null, 2); + const menuPath = path.join(targetDirectory, 'menu.json'); + fs.writeFileSync(menuPath, menuResult, { encoding: 'utf8' }); + + console.log('Successfully download all documents!'); +} + +run(); diff --git a/docs/libs/template-parse/build.js b/docs/libs/template-parse/build.js new file mode 100644 index 00000000..cac280f9 --- /dev/null +++ b/docs/libs/template-parse/build.js @@ -0,0 +1,188 @@ +/* Adapted from echarts-doc by Apache ECharts + * https://github.com/apache/echarts-doc + * Licensed under the Apache-2.0 license + + * url: https://github.com/apache/echarts-doc/blob/master/build.js + * License: https://github.com/apache/echarts-doc/blob/master/LICENSE + * @license + */ + +const md2json = require('./md2json'); +const { extractDesc } = require('./schemaHelper'); +const fs = require('fs'); +const fse = require('fs-extra'); +const chalk = require('chalk'); +const argv = require('yargs').argv; +const path = require('path'); +const assert = require('assert'); +const chokidar = require('chokidar'); +const { debounce } = require('lodash'); +const menu = require('../../menu.json'); + +function initEnv() { + let envType = argv.env; + let isDev = argv.dev != null || argv.debug != null || argv.env === 'dev'; + + if (isDev) { + console.warn('============================='); + console.warn('!!! THIS IS IN DEV MODE !!!'); + console.warn('============================='); + envType = 'dev'; + } + + if (!envType) { + throw new Error('--env MUST be specified'); + } + + let config = { + releaseDestDir: path.resolve(__dirname, '../../public/documents') + }; + + config.envType = envType; + + return config; +} + +const config = initEnv(); + +const languages = ['zh', 'en']; + +config.gl = config.gl || {}; +for (let key in config) { + if (key !== 'gl' && !config.gl.hasOwnProperty(key)) { + config.gl[key] = config[key]; + } +} + +async function md2jsonAsync(opt) { + var newOpt = Object.assign( + { + path: path.resolve(__dirname, opt.assetPath, opt.language, '**/*.md'), + tplEnv: Object.assign({}, config), + imageRoot: config.imagePath + }, + opt + ); + + function run(cb) { + md2json(newOpt) + .then(schema => { + writeSingleSchemaPartioned(schema, opt.language, opt.entry, false, opt.arrayKeys); + console.log(chalk.green('generated: ' + opt.language + '/' + opt.entry)); + cb && cb(); + }) + .catch(e => { + console.log(e); + }); + } + + var runDebounced = debounce(run, 500, { + leading: false, + trailing: true + }); + return await new Promise((resolve, reject) => { + run(resolve); + + if (argv.watch) { + chokidar + .watch(path.resolve(__dirname, opt.assetPath, opt.language), { + ignoreInitial: true + }) + .on('all', (event, path) => { + console.log(path, event); + runDebounced(); + }); + } + }); +} + +async function run() { + for (const menuItem of menu) { + if (menuItem.type !== 'markdown-template') { + continue; + } + for (const language of languages) { + await md2jsonAsync({ + sectionsAnyOf: menuItem.sections ?? [], + arrayKeys: menuItem.arrayKeys ?? [], + entry: menuItem.entry, + assetPath: `../../assets/${menuItem.menu}/`, + language + }); + } + } + + console.log('Build doc done.'); + + console.log('All done.'); +} + +function writeSingleSchemaPartioned(schema, language, docName, format, arrayItemKeys) { + const { outline, descriptions } = extractDesc(schema, docName, arrayItemKeys); + + const outlineBasename = `outline.json`; + const outlineDestPath = path.resolve(config.releaseDestDir, `${docName}/${language}/${outlineBasename}`); + fse.ensureDirSync(path.dirname(outlineDestPath)); + fse.outputFileSync(outlineDestPath, format ? JSON.stringify(outline, null, 2) : JSON.stringify(outline), 'utf-8'); + + function copyUIControlConfigs(source, target) { + for (let key in source) { + if (target[key]) { + if (source[key].uiControl && !target[key].uiControl) { + target[key].uiControl = source[key].uiControl; + } + if (source[key].exampleBaseOptions && !target[key].exampleBaseOptions) { + target[key].exampleBaseOptions = source[key].exampleBaseOptions; + } + } else { + // console.error(`Unmatched option path ${key}`); + } + } + } + + function readOptionDesc(language, partKey) { + const descBasename = `${partKey}.json`; + const descDestPath = path.resolve(config.releaseDestDir, `${docName}/${language}/${descBasename}`); + try { + const text = fs.readFileSync(descDestPath, 'utf-8'); + return JSON.parse(text); + } catch (e) { + return; + } + } + + function writeOptionDesc(language, partKey, json) { + const descBasename = `${partKey}.json`; + const descDestPath = path.resolve(config.releaseDestDir, `${docName}/${language}/${descBasename}`); + fse.ensureDirSync(path.dirname(descDestPath)); + fse.outputFileSync(descDestPath, format ? JSON.stringify(json, null, 2) : JSON.stringify(json), 'utf-8'); + } + + for (let partKey in descriptions) { + let partDescriptions = descriptions[partKey]; + + // Copy ui control config from zh to english. + if (language === 'zh') { + languages.forEach(function (otherLang) { + if (otherLang === 'zh') { + return; + } + const json = readOptionDesc(otherLang, partKey); + if (json) { + copyUIControlConfigs(partDescriptions, json); + writeOptionDesc(otherLang, partKey, json); + } + }); + } else { + const json = readOptionDesc('zh', partKey); + if (json) { + copyUIControlConfigs(json, partDescriptions); + } + } + + writeOptionDesc(language, partKey, partDescriptions); + // console.log(chalk.green('generated: ' + descDestPath)); + } +} + +run(); diff --git a/docs/libs/template-parse/etpl.js b/docs/libs/template-parse/etpl.js new file mode 100644 index 00000000..62baa8c9 --- /dev/null +++ b/docs/libs/template-parse/etpl.js @@ -0,0 +1,1679 @@ +/* Adapted from echarts-doc by Apache ECharts + * https://github.com/apache/echarts-doc + * Licensed under the Apache-2.0 license + + * url: https://github.com/apache/echarts-doc/blob/master/dep/etpl.js + * License: https://github.com/apache/echarts-doc/blob/master/LICENSE + * @license + */ + +/** + * ETPL (Enterprise Template) + * Copyright 2013 Baidu Inc. All rights reserved. + * + * @file 模板引擎 + * @author errorrik(errorrik@gmail.com) + * otakustay(otakustay@gmail.com) + */ + +// HACK: 可见的重复代码未抽取成function和var是为了gzip size,吐槽的一边去 +/* eslint-env node */ + +(function (root) { + /** + * 对象属性拷贝 + * + * @inner + * @param {Object} target 目标对象 + * @param {Object} source 源对象 + * @return {Object} 返回目标对象 + */ + function extend(target, source) { + for (var key in source) { + if (source.hasOwnProperty(key)) { + target[key] = source[key]; + } + } + + return target; + } + + /** + * 随手写了个栈 + * + * @inner + * @constructor + */ + function Stack() { + this.raw = []; + this.length = 0; + } + + Stack.prototype = { + /** + * 添加元素进栈 + * + * @param {*} elem 添加项 + */ + push: function (elem) { + this.raw[this.length++] = elem; + }, + + /** + * 弹出顶部元素 + * + * @return {*} 顶部元素 + */ + pop: function () { + if (this.length > 0) { + var elem = this.raw[--this.length]; + this.raw.length = this.length; + return elem; + } + }, + + /** + * 获取顶部元素 + * + * @return {*} 顶部元素 + */ + top: function () { + return this.raw[this.length - 1]; + }, + + /** + * 获取底部元素 + * + * @return {*} 底部元素 + */ + bottom: function () { + return this.raw[0]; + }, + + /** + * 根据查询条件获取元素 + * + * @param {Function} condition 查询函数 + * @return {*} 符合条件的元素 + */ + find: function (condition) { + var index = this.length; + while (index--) { + var item = this.raw[index]; + if (condition(item)) { + return item; + } + } + } + }; + + /** + * 唯一id的起始值 + * + * @inner + * @type {number} + */ + var guidIndex = 0x2b845; + + /** + * 获取唯一id,用于匿名target或编译代码的变量名生成 + * + * @inner + * @return {string} 唯一id + */ + function generateGUID() { + return '___' + guidIndex++; + } + + /** + * 构建类之间的继承关系 + * + * @inner + * @param {Function} subClass 子类函数 + * @param {Function} superClass 父类函数 + */ + function inherits(subClass, superClass) { + /* jshint -W054 */ + var subClassProto = subClass.prototype; + var F = new Function(); + F.prototype = superClass.prototype; + subClass.prototype = new F(); + subClass.prototype.constructor = subClass; + extend(subClass.prototype, subClassProto); + /* jshint +W054 */ + } + + /** + * HTML Filter替换的字符实体表 + * + * @const + * @inner + * @type {Object} + */ + var HTML_ENTITY = { + /* jshint ignore:start */ + '&': '&', + '<': '<', + '>': '>', + '"': '"', + /* eslint-disable quotes */ + "'": ''' + /* eslint-enable quotes */ + /* jshint ignore:end */ + }; + + /** + * HTML Filter的替换函数 + * + * @inner + * @param {string} c 替换字符 + * @return {string} 替换后的HTML字符实体 + */ + function htmlFilterReplacer(c) { + return HTML_ENTITY[c]; + } + + /** + * 默认filter + * + * @inner + * @const + * @type {Object} + */ + var DEFAULT_FILTERS = { + /** + * HTML转义filter + * + * @param {string} source 源串 + * @return {string} 替换结果串 + */ + html: function (source) { + return source.replace(/[&<>"']/g, htmlFilterReplacer); + }, + + /** + * URL编码filter + * + * @param {string} source 源串 + * @return {string} 替换结果串 + */ + url: encodeURIComponent, + + /** + * 源串filter,用于在默认开启HTML转义时获取源串,不进行转义 + * + * @param {string} source 源串 + * @return {string} 替换结果串 + */ + raw: function (source) { + return source; + } + }; + + /** + * 字符串字面化 + * + * @inner + * @param {string} source 需要字面化的字符串 + * @return {string} 字符串字面化结果 + */ + function stringLiteralize(source) { + return ( + '"' + + source + .replace(/\x5C/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\x0A/g, '\\n') + .replace(/\x09/g, '\\t') + .replace(/\x0D/g, '\\r') + + // .replace( /\x08/g, '\\b' ) + // .replace( /\x0C/g, '\\f' ) + '"' + ); + } + + /** + * 对字符串进行可用于new RegExp的字面化 + * + * @inner + * @param {string} source 需要字面化的字符串 + * @return {string} 字符串字面化结果 + */ + function regexpLiteral(source) { + return source.replace(/[\^\[\]\$\(\)\{\}\?\*\.\+]/g, function (c) { + return '\\' + c; + }); + } + + /** + * 字符串格式化 + * + * @inner + * @param {string} source 目标模版字符串 + * @param {...string} replacements 字符串替换项集合 + * @return {string} 格式化结果 + */ + function stringFormat(source) { + var args = arguments; + return source.replace(/\{([0-9]+)\}/g, function (match, index) { + return args[index - 0 + 1]; + }); + } + + /** + * 用于render的字符串变量声明语句 + * + * @inner + * @const + * @type {string} + */ + var RENDER_STRING_DECLATION = 'var r="";'; + + /** + * 用于render的字符串内容添加语句(起始) + * + * @inner + * @const + * @type {string} + */ + var RENDER_STRING_ADD_START = 'r+='; + + /** + * 用于render的字符串内容添加语句(结束) + * + * @inner + * @const + * @type {string} + */ + var RENDER_STRING_ADD_END = ';'; + + /** + * 用于render的字符串内容返回语句 + * + * @inner + * @const + * @type {string} + */ + var RENDER_STRING_RETURN = 'return r;'; + + // HACK: IE8-时,编译后的renderer使用join Array的策略进行字符串拼接 + var ieVersionMatch = typeof navigator !== 'undefined' && navigator.userAgent.match(/msie\s*([0-9]+)/i); + + if (ieVersionMatch && ieVersionMatch[1] - 0 < 8) { + RENDER_STRING_DECLATION = 'var r=[],ri=0;'; + RENDER_STRING_ADD_START = 'r[ri++]='; + RENDER_STRING_RETURN = 'return r.join("");'; + } + + /** + * 将访问变量名称转换成getVariable调用的编译语句 + * 用于if、var等命令生成编译代码 + * + * @inner + * @param {string} name 访问变量名 + * @return {string} getVariable调用的编译语句 + */ + function toGetVariableLiteral(name) { + name = name.replace(/^\s*\*/, ''); + return stringFormat( + 'gv({0},["{1}"])', + stringLiteralize(name), + name + .replace(/\[['"]?([^'"]+)['"]?\]/g, function (match, name) { + return '.' + name; + }) + .split('.') + .join('","') + ); + } + + /** + * 解析文本片段中以固定字符串开头和结尾的包含块 + * 用于 命令串: 和 变量替换串:${...} 的解析 + * + * @inner + * @param {string} source 要解析的文本 + * @param {string} open 包含块开头 + * @param {string} close 包含块结束 + * @param {boolean} greedy 是否贪婪匹配 + * @param {function({string})} onInBlock 包含块内文本的处理函数 + * @param {function({string})} onOutBlock 非包含块内文本的处理函数 + */ + function parseTextBlock(source, open, close, greedy, onInBlock, onOutBlock) { + var closeLen = close.length; + var texts = (source || '').split(open); + var level = 0; + var buf = []; + + for (var i = 0, len = texts.length; i < len; i++) { + var text = texts[i]; + + if (i) { + var openBegin = 1; + level++; + /* eslint-disable no-constant-condition */ + while (1) { + var closeIndex = text.indexOf(close); + if (closeIndex < 0) { + buf.push(level > 1 && openBegin ? open : '', text); + break; + } + + level = greedy ? level - 1 : 0; + buf.push(level > 0 && openBegin ? open : '', text.slice(0, closeIndex), level > 0 ? close : ''); + text = text.slice(closeIndex + closeLen); + openBegin = 0; + + if (level === 0) { + break; + } + } + /* eslint-enable no-constant-condition */ + + if (level === 0) { + onInBlock(buf.join('')); + onOutBlock(text); + buf = []; + } + } else { + text && onOutBlock(text); + } + } + + if (level > 0 && buf.length > 0) { + onOutBlock(open); + onOutBlock(buf.join('')); + } + } + + /** + * 编译变量访问和变量替换的代码 + * 用于普通文本或if、var、filter等命令生成编译代码 + * + * @inner + * @param {string} source 源代码 + * @param {Engine} engine 引擎实例 + * @param {boolean} forText 是否为输出文本的变量替换 + * @return {string} 编译代码 + */ + function compileVariable(source, engine, forText) { + var code = []; + var options = engine.options; + + var toStringHead = ''; + var toStringFoot = ''; + var wrapHead = ''; + var wrapFoot = ''; + + // 默认的filter,当forText模式时有效 + var defaultFilter; + + if (forText) { + toStringHead = 'ts('; + toStringFoot = ')'; + wrapHead = RENDER_STRING_ADD_START; + wrapFoot = RENDER_STRING_ADD_END; + defaultFilter = options.defaultFilter; + } + + parseTextBlock( + source, + options.variableOpen, + options.variableClose, + 1, + + function (text) { + // 加入默认filter + // 只有当处理forText时,需要加入默认filter + // 处理if/var/use等command时,不需要加入默认filter + if (forText && text.indexOf('|') < 0 && defaultFilter) { + text += '|' + defaultFilter; + } + + // variableCode是一个gv调用,然后通过循环,在外面包filter的调用 + // 形成filter["b"](filter["a"](gv(...))) + // + // 当forText模式,处理的是文本中的变量替换时 + // 传递给filter的需要是字符串形式,所以gv外需要包一层ts调用 + // 形成filter["b"](filter["a"](ts(gv(...)))) + // + // 当variableName以*起始时,忽略ts调用,直接传递原值给filter + var filterCharIndex = text.indexOf('|'); + var variableName = (filterCharIndex > 0 ? text.slice(0, filterCharIndex) : text) + .replace(/^\s+/, '') + .replace(/\s+$/, ''); + var filterSource = filterCharIndex > 0 ? text.slice(filterCharIndex + 1) : ''; + + var variableRawValue = variableName.indexOf('*') === 0; + var variableCode = [ + variableRawValue ? '' : toStringHead, + toGetVariableLiteral(variableName), + variableRawValue ? '' : toStringFoot + ]; + + if (filterSource) { + filterSource = compileVariable(filterSource, engine); + var filterSegs = filterSource.split('|'); + for (var i = 0, len = filterSegs.length; i < len; i++) { + var seg = filterSegs[i]; + var segMatch = seg.match(/^\s*([a-z0-9_-]+)(\((.*)\))?\s*$/i); + if (segMatch) { + variableCode.unshift('fs["' + segMatch[1] + '"]('); + + if (segMatch[3]) { + variableCode.push(',', segMatch[3]); + } + + variableCode.push(')'); + } + } + } + + code.push(wrapHead, variableCode.join(''), wrapFoot); + }, + + function (text) { + code.push(wrapHead, forText ? stringLiteralize(text) : text, wrapFoot); + } + ); + + return code.join(''); + } + + /** + * 文本节点类 + * + * @inner + * @constructor + * @param {string} value 文本节点的内容文本 + * @param {Engine} engine 引擎实例 + */ + function TextNode(value, engine) { + this.value = value; + this.engine = engine; + } + + TextNode.prototype = { + /** + * 获取renderer body的生成代码 + * + * @return {string} 生成代码 + */ + getRendererBody: function () { + var value = this.value; + var options = this.engine.options; + + if (!value || (options.strip && /^\s*$/.test(value))) { + return ''; + } + + return compileVariable(value, this.engine, 1); + }, + + /** + * 复制节点的方法 + * + * @return {TextNode} 节点复制对象 + */ + clone: function () { + return this; + } + }; + + /** + * 命令节点类 + * + * @inner + * @constructor + * @param {string} value 命令节点的value + * @param {Engine} engine 引擎实例 + */ + function Command(value, engine) { + this.value = value; + this.engine = engine; + this.children = []; + this.cloneProps = []; + } + + Command.prototype = { + /** + * 添加子节点 + * + * @param {TextNode|Command} node 子节点 + */ + addChild: function (node) { + this.children.push(node); + }, + + /** + * 节点open,解析开始 + * + * @param {Object} context 语法分析环境对象 + */ + open: function (context) { + var parent = context.stack.top(); + parent && parent.addChild(this); + context.stack.push(this); + }, + + /** + * 节点闭合,解析结束 + * + * @param {Object} context 语法分析环境对象 + */ + close: function (context) { + if (context.stack.top() === this) { + context.stack.pop(); + } + }, + + /** + * 获取renderer body的生成代码 + * + * @return {string} 生成代码 + */ + getRendererBody: function () { + var buf = []; + var children = this.children; + for (var i = 0; i < children.length; i++) { + buf.push(children[i].getRendererBody()); + } + + return buf.join(''); + }, + + /** + * 复制节点的方法 + * + * @return {Command} 节点复制对象 + */ + clone: function () { + var Clazz = this.constructor; + var node = new Clazz(this.value, this.engine); + + /* eslint-disable no-redeclare */ + for (var i = 0, l = this.children.length; i < l; i++) { + node.addChild(this.children[i].clone()); + } + + for (var i = 0, l = this.cloneProps.length; i < l; i++) { + var prop = this.cloneProps[i]; + node[prop] = this[prop]; + } + /* eslint-enable no-redeclare */ + + return node; + } + }; + + /** + * 命令自动闭合 + * + * @inner + * @param {Object} context 语法分析环境对象 + * @param {Function=} CommandType 自闭合的节点类型 + * @return {Command} 被闭合的节点 + */ + function autoCloseCommand(context, CommandType) { + var stack = context.stack; + var closeEnd = CommandType + ? stack.find(function (item) { + return item instanceof CommandType; + }) + : stack.bottom(); + + if (closeEnd) { + var node; + + while ((node = stack.top()) !== closeEnd) { + /* jshint ignore:start */ + // 如果节点对象不包含autoClose方法 + // 则认为该节点不支持自动闭合,需要抛出错误 + // for等节点不支持自动闭合 + if (!node.autoClose) { + throw new Error(node.type + ' must be closed manually: ' + node.value); + } + /* jshint ignore:end */ + + node.autoClose(context); + } + + closeEnd.close(context); + } + + return closeEnd; + } + + /** + * renderer body起始代码段 + * + * @inner + * @const + * @type {string} + */ + var RENDERER_BODY_START = + '' + + 'data=data||{};' + + 'var v={},fs=engine.filters,hg=typeof data.get=="function",' + + 'gv=function(n,ps){' + + 'var p=ps[0],d=v[p];' + + 'if(d==null){' + + 'if(hg){return data.get(n);}' + + 'd=data[p];' + + '}' + + 'for(var i=1,l=ps.length;i= TargetState.APPLIED) { + return 1; + } + + var blocks = this.blocks; + + function replaceBlock(node) { + var children = node.children; + + if (children instanceof Array) { + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + if (child instanceof BlockCommand && blocks[child.name]) { + child = children[i] = blocks[child.name]; + } + + replaceBlock(child); + } + } + } + + var master = this.engine.targets[masterName]; + if (master) { + if (master.applyMaster(master.master)) { + this.children = master.clone().children; + replaceBlock(this); + this.state = TargetState.APPLIED; + return 1; + } + } else if (this.engine.options.missTarget === 'error') { + throw new Error( + '[ETPL_MISS_TARGET]' + masterName + ', when extended by ' + (this.target ? this.target.name : this.name) + ); + } + }; + + /** + * 判断target是否ready + * 包括是否成功应用母版,以及import语句依赖的target是否ready + * + * @return {boolean} target是否ready + */ + TargetCommand.prototype.isReady = function () { + if (this.state >= TargetState.READY) { + return 1; + } + + var engine = this.engine; + var targetName = this.name; + var readyState = 1; + + /** + * 递归检查节点的ready状态 + * + * @inner + * @param {Command|TextNode} node 目标节点 + */ + function checkReadyState(node) { + for (var i = 0, len = node.children.length; i < len; i++) { + var child = node.children[i]; + + if (child instanceof ImportCommand) { + var target = engine.targets[child.name]; + if (!target && engine.options.missTarget === 'error') { + throw new Error('[ETPL_MISS_TARGET]' + child.name + ', when imported by ' + targetName); + } + + readyState = readyState && target && target.isReady(engine); + } else if (child instanceof Command) { + checkReadyState(child); + } + } + } + + if (this.applyMaster(this.master)) { + checkReadyState(this); + readyState && (this.state = TargetState.READY); + return readyState; + } + }; + + /** + * 获取target的renderer函数 + * + * @return {function(Object):string} renderer函数 + */ + TargetCommand.prototype.getRenderer = function () { + if (this.renderer) { + return this.renderer; + } + + if (this.isReady()) { + // console.log(this.name + ' ------------------'); + // console.log(RENDERER_BODY_START + RENDER_STRING_DECLATION + // + this.getRendererBody() + // + RENDER_STRING_RETURN); + + /* jshint -W054 */ + var realRenderer = new Function( + 'data', + 'engine', + [RENDERER_BODY_START, RENDER_STRING_DECLATION, this.getRendererBody(), RENDER_STRING_RETURN].join('\n') + ); + /* jshint +W054 */ + + var engine = this.engine; + this.renderer = function (data) { + return realRenderer(data, engine); + }; + + return this.renderer; + } + + return null; + }; + + /** + * 将target节点对象添加到语法分析环境中 + * + * @inner + * @param {TargetCommand} target target节点对象 + * @param {Object} context 语法分析环境对象 + */ + function addTargetToContext(target, context) { + context.target = target; + + var engine = context.engine; + var name = target.name; + + if (engine.targets[name]) { + switch (engine.options.namingConflict) { + /* jshint ignore:start */ + case 'override': + engine.targets[name] = target; + context.targets.push(name); + case 'ignore': + break; + /* jshint ignore:end */ + default: + throw new Error('[ETPL_TARGET_EXISTS]' + name); + } + } else { + engine.targets[name] = target; + context.targets.push(name); + } + } + + /** + * target节点open,解析开始 + * + * @param {Object} context 语法分析环境对象 + */ + TargetCommand.prototype.open = function (context) { + autoCloseCommand(context); + Command.prototype.open.call(this, context); + this.state = TargetState.READING; + addTargetToContext(this, context); + }; + + /** + * Var节点open,解析开始 + * + * @param {Object} context 语法分析环境对象 + */ + VarCommand.prototype.open = + /** + * Use节点open,解析开始 + * + * @param {Object} context 语法分析环境对象 + */ + UseCommand.prototype.open = function (context) { + context.stack.top().addChild(this); + }; + + /** + * Block节点open,解析开始 + * + * @param {Object} context 语法分析环境对象 + */ + BlockCommand.prototype.open = function (context) { + Command.prototype.open.call(this, context); + context.stack.find(function (node) { + return node.blocks; + }).blocks[this.name] = this; + }; + + /** + * elif节点open,解析开始 + * + * @param {Object} context 语法分析环境对象 + */ + ElifCommand.prototype.open = function (context) { + var elseCommand = new ElseCommand(); + elseCommand.open(context); + + var ifCommand = autoCloseCommand(context, IfCommand); + ifCommand.addChild(this); + context.stack.push(this); + }; + + /** + * else节点open,解析开始 + * + * @param {Object} context 语法分析环境对象 + */ + ElseCommand.prototype.open = function (context) { + var ifCommand = autoCloseCommand(context, IfCommand); + ifCommand.addChild(this); + context.stack.push(this); + }; + + /** + * import节点open,解析开始 + * + * @param {Object} context 语法分析环境对象 + */ + ImportCommand.prototype.open = function (context) { + this.parent = context.stack.top(); + this.target = context.target; + Command.prototype.open.call(this, context); + this.state = TargetState.READING; + }; + + /** + * 节点解析结束 + * 由于use节点无需闭合,处理时不会入栈,所以将close置为空函数 + * + * @param {Object} context 语法分析环境对象 + */ + UseCommand.prototype.close = + /** + * 节点解析结束 + * 由于var节点无需闭合,处理时不会入栈,所以将close置为空函数 + * + * @param {Object} context 语法分析环境对象 + */ + VarCommand.prototype.close = function () {}; + + /** + * 节点解析结束 + * + * @param {Object} context 语法分析环境对象 + */ + ImportCommand.prototype.close = function (context) { + Command.prototype.close.call(this, context); + this.state = TargetState.READED; + }; + + /** + * 节点闭合,解析结束 + * + * @param {Object} context 语法分析环境对象 + */ + TargetCommand.prototype.close = function (context) { + Command.prototype.close.call(this, context); + this.state = this.master ? TargetState.READED : TargetState.APPLIED; + context.target = null; + }; + + /** + * 节点自动闭合,解析结束 + * ImportCommand的自动结束逻辑为,在其开始位置后马上结束 + * 所以,其自动结束时children应赋予其所属的parent + * + * @param {Object} context 语法分析环境对象 + */ + ImportCommand.prototype.autoClose = function (context) { + // move children to parent + var parentChildren = this.parent.children; + parentChildren.push.apply(parentChildren, this.children); + this.children.length = 0; + + // move blocks to target + /* eslint-disable guard-for-in */ + for (var key in this.blocks) { + this.target.blocks[key] = this.blocks[key]; + } + /* eslint-enable guard-for-in */ + this.blocks = {}; + + // do close + this.close(context); + }; + + /** + * 节点open前的处理动作:节点不在target中时,自动创建匿名target + * + * @param {Object} context 语法分析环境对象 + */ + Command.prototype.beforeOpen = + /** + * 文本节点被添加到分析环境前的处理动作:节点不在target中时,自动创建匿名target + * + * @param {Object} context 语法分析环境对象 + */ + TextNode.prototype.beforeAdd = function (context) { + if (context.stack.bottom()) { + return; + } + + var target = new TargetCommand(generateGUID(), context.engine); + target.open(context); + }; + + /** + * 节点open前的处理动作:target 不需要自动创建target,所以清空方法 + * + * @param {Object} context 语法分析环境对象 + */ + TargetCommand.prototype.beforeOpen = function () {}; + + /** + * 获取renderer body的生成代码 + * + * @return {string} 生成代码 + */ + ImportCommand.prototype.getRendererBody = function () { + this.applyMaster(this.name); + return Command.prototype.getRendererBody.call(this); + }; + + /** + * 获取renderer body的生成代码 + * + * @return {string} 生成代码 + */ + UseCommand.prototype.getRendererBody = function () { + return stringFormat( + '{0}engine.render({2},{{3}}){1}', + RENDER_STRING_ADD_START, + RENDER_STRING_ADD_END, + stringLiteralize(this.name), + compileVariable(this.args, this.engine).replace(/(^|,)\s*([a-z0-9_]+)\s*=/gi, function (match, start, argName) { + return (start || '') + stringLiteralize(argName) + ':'; + }) + ); + }; + + /** + * 获取renderer body的生成代码 + * + * @return {string} 生成代码 + */ + VarCommand.prototype.getRendererBody = function () { + if (this.expr) { + return stringFormat('v[{0}]={1};', stringLiteralize(this.name), compileVariable(this.expr, this.engine)); + } + + return ''; + }; + + /** + * 获取renderer body的生成代码 + * + * @return {string} 生成代码 + */ + IfCommand.prototype.getRendererBody = function () { + return stringFormat( + 'if({0}){{1}}', + compileVariable(this.value, this.engine), + Command.prototype.getRendererBody.call(this) + ); + }; + + /** + * 获取renderer body的生成代码 + * + * @return {string} 生成代码 + */ + ElseCommand.prototype.getRendererBody = function () { + return stringFormat('}else{{0}', Command.prototype.getRendererBody.call(this)); + }; + + /** + * 获取renderer body的生成代码 + * + * @return {string} 生成代码 + */ + ForCommand.prototype.getRendererBody = function () { + return stringFormat( + /* jshint ignore:start */ + '' + + 'var {0}={1};' + + 'if({0} instanceof Array)' + + 'for (var {4}=0,{5}={0}.length;{4}<{5};{4}++){v[{2}]={4};v[{3}]={0}[{4}];{6}}' + + 'else if(typeof {0}==="object")' + + 'for(var {4} in {0}){v[{2}]={4};v[{3}]={0}[{4}];{6}}', + /* jshint ignore:end */ + generateGUID(), + compileVariable(this.list, this.engine), + stringLiteralize(this.index || generateGUID()), + stringLiteralize(this.item), + generateGUID(), + generateGUID(), + Command.prototype.getRendererBody.call(this) + ); + }; + + /** + * 获取renderer body的生成代码 + * + * @return {string} 生成代码 + */ + FilterCommand.prototype.getRendererBody = function () { + var args = this.args; + return stringFormat( + '{2}fs[{5}]((function(){{0}{4}{1}})(){6}){3}', + RENDER_STRING_DECLATION, + RENDER_STRING_RETURN, + RENDER_STRING_ADD_START, + RENDER_STRING_ADD_END, + Command.prototype.getRendererBody.call(this), + stringLiteralize(this.name), + args ? ',' + compileVariable(args, this.engine) : '' + ); + }; + + /** + * 添加命令类型 + * + * @inner + * @param {Engine} engine etpl引擎 + * @param {string} name 命令名称 + * @param {Function} Type 处理命令用到的类 + */ + function addCommandType(engine, name, Type) { + engine.commandTypes[name] = Type; + Type.prototype.type = name; + } + + /** + * etpl引擎类 + * + * @constructor + * @param {Object=} options 引擎参数 + * @param {string=} options.commandOpen 命令语法起始串 + * @param {string=} options.commandClose 命令语法结束串 + * @param {string=} options.variableOpen 变量语法起始串 + * @param {string=} options.variableClose 变量语法结束串 + * @param {string=} options.defaultFilter 默认变量替换的filter + * @param {boolean=} options.strip 是否清除命令标签前后的空白字符 + * @param {string=} options.namingConflict target名字冲突时的处理策略 + * @param {string=} options.missTarget target不存在时的处理策略 + */ + function Engine(options) { + this.options = { + commandOpen: '', + commandSyntax: /^\s*(\/)?([a-z]*)\s*(?::([\s\S]*))?$/, + variableOpen: '${', + variableClose: '}', + defaultFilter: 'html' + }; + + this.commandTypes = {}; + addCommandType(this, 'target', TargetCommand); + addCommandType(this, 'block', BlockCommand); + addCommandType(this, 'import', ImportCommand); + addCommandType(this, 'use', UseCommand); + addCommandType(this, 'var', VarCommand); + addCommandType(this, 'for', ForCommand); + addCommandType(this, 'if', IfCommand); + addCommandType(this, 'elif', ElifCommand); + addCommandType(this, 'else', ElseCommand); + addCommandType(this, 'filter', FilterCommand); + + this.config(options); + this.targets = {}; + this.filters = extend({}, DEFAULT_FILTERS); + } + + /** + * 配置引擎参数,设置的参数将被合并到现有参数中 + * + * @param {Object} options 参数对象 + * @param {string=} options.commandOpen 命令语法起始串 + * @param {string=} options.commandClose 命令语法结束串 + * @param {string=} options.variableOpen 变量语法起始串 + * @param {string=} options.variableClose 变量语法结束串 + * @param {string=} options.defaultFilter 默认变量替换的filter + * @param {boolean=} options.strip 是否清除命令标签前后的空白字符 + * @param {string=} options.namingConflict target名字冲突时的处理策略 + * @param {string=} options.missTarget target不存在时的处理策略 + */ + Engine.prototype.config = function (options) { + extend(this.options, options); + }; + + /** + * 解析模板并编译,返回第一个target编译后的renderer函数。 + * + * @param {string} source 模板源代码 + * @return {function(Object):string} renderer函数 + */ + Engine.prototype.compile = + /** + * 解析模板并编译,返回第一个target编译后的renderer函数。 + * 该方法的存在为了兼容老模板引擎 + * + * @param {string} source 模板源代码 + * @return {function(Object):string} renderer函数 + */ + Engine.prototype.parse = function (source) { + /* jshint -W054 */ + var renderer = new Function('return ""'); + /* jshint +W054 */ + + if (source) { + var parseInfo = parseSource(source, this); + var targetNames = parseInfo.targets; + + if (targetNames.length) { + renderer = this.targets[targetNames[0]].getRenderer(); + } + } + + return renderer; + }; + + /** + * 根据target名称获取编译后的renderer函数 + * + * @param {string} name target名称 + * @return {function(Object):string} renderer函数 + */ + Engine.prototype.getRenderer = function (name) { + var target = this.targets[name]; + if (!target) { + console.log(name); + } + if (target) { + return target.getRenderer(); + } + }; + + /** + * 执行模板渲染,返回渲染后的字符串。 + * + * @param {string} name target名称 + * @param {Object=} data 模板数据。 + * 可以是plain object, + * 也可以是带有 {string}get({string}name) 方法的对象 + * @return {string} 渲染结果 + */ + Engine.prototype.render = function (name, data) { + var renderer = this.getRenderer(name); + if (renderer) { + return renderer(data); + } + + return ''; + }; + + /** + * 增加命令 + * + * @param {string} name 命令名称 + * @param {Object|Function} command 命令对象或命令类 + */ + Engine.prototype.addCommand = function (name, command) { + var CommandType = command; + if ('function' !== typeof CommandType) { + CommandType = function (value, engine) { + Command.call(this, value, engine); + }; + + CommandType.prototype = command; + } + + inherits(CommandType, Command); + addCommandType(this, name, CommandType); + }; + + /** + * 增加过滤器 + * + * @param {string} name 过滤器名称 + * @param {Function} filter 过滤函数 + */ + Engine.prototype.addFilter = function (name, filter) { + if ('function' === typeof filter) { + this.filters[name] = filter; + } + }; + + /** + * 解析源代码 + * + * @inner + * @param {string} source 模板源代码 + * @param {Engine} engine 引擎实例 + * @return {Array} target名称列表 + */ + function parseSource(source, engine) { + var commandOpen = engine.options.commandOpen; + var commandClose = engine.options.commandClose; + var commandSyntax = engine.options.commandSyntax; + + var stack = new Stack(); + var analyseContext = { + engine: engine, + targets: [], + stack: stack, + target: null, + deps: {} + }; + + // text节点内容缓冲区,用于合并多text + var textBuf = []; + + /** + * 将缓冲区中的text节点内容写入 + * + * @inner + */ + function flushTextBuf() { + var text; + if (textBuf.length > 0 && (text = textBuf.join(''))) { + var textNode = new TextNode(text, engine); + textNode.beforeAdd(analyseContext); + + stack.top().addChild(textNode); + textBuf = []; + + if (engine.options.strip && analyseContext.current instanceof Command) { + textNode.value = text.replace(/^[\x20\t\r]*\n/, ''); + } + analyseContext.current = textNode; + } + } + + var NodeType; + + parseTextBlock( + source, + commandOpen, + commandClose, + 0, + + function (text) { + // 内文本的处理函数 + var match = commandSyntax.exec(text); + var nodeName; + + // 符合command规则,并且存在相应的Command类,说明是合法有含义的Command + // 否则,为不具有command含义的普通文本 + if ( + match && + (nodeName = match[2] || 'target') && + (NodeType = engine.commandTypes[nodeName.toLowerCase()]) && + typeof NodeType === 'function' + ) { + // 先将缓冲区中的text节点内容写入 + flushTextBuf(); + + var currentNode = analyseContext.current; + if (engine.options.strip && currentNode instanceof TextNode) { + currentNode.value = currentNode.value.replace(/\r?\n[\x20\t]*$/, '\n'); + } + + if (match[1]) { + currentNode = autoCloseCommand(analyseContext, NodeType); + } else { + currentNode = new NodeType(match[3], engine); + + if ('function' === typeof currentNode.init) { + currentNode.init(analyseContext); + } + + currentNode.beforeOpen(analyseContext); + currentNode.open(analyseContext); + } + + analyseContext.current = currentNode; + } else if (!/^\s*\/\//.test(text)) { + // 如果不是模板注释,则作为普通文本,写入缓冲区 + textBuf.push(commandOpen, text, commandClose); + } + + NodeType = null; + }, + + function (text) { + // 外,普通文本的处理函数 + // 普通文本直接写入缓冲区 + textBuf.push(text); + } + ); + + flushTextBuf(); // 将缓冲区中的text节点内容写入 + autoCloseCommand(analyseContext); + + var deps = []; + for (var key in analyseContext.deps) { + deps.push(key); + } + + return { + targets: analyseContext.targets, + deps: deps + }; + } + + // export object + var etpl = new Engine(); + etpl.Engine = Engine; + etpl.version = '3.2.0'; + etpl.Command = Command; + etpl.util = { + inherits: inherits, + stringFormat: stringFormat, + stringLiteralize: stringLiteralize, + compileVariable: compileVariable, + parseSource: parseSource + }; + etpl.TextNode = TextNode; + + if (typeof exports === 'object' && typeof module === 'object') { + // For CommonJS + exports = module.exports = etpl; + } else if (typeof define === 'function' && define.amd) { + // For AMD + define(etpl); + } else { + // For + + + +``` + +## Get from GitHub + +On GitHub, you can directly get the source code of VMind: + +- You can directly clone the source code from GitHub. +- You can also choose the corresponding version from the [release](https://github.com/VisActor/VMind/releases) page of VMind, click on Source code in Assets at the bottom of the page, download it to the local and unzip it for use. diff --git a/docs/assets/guide/en/Basic/How_to_Get_VRender.md b/docs/assets/guide/en/Basic/How_to_Get_VRender.md deleted file mode 100644 index 861a84cb..00000000 --- a/docs/assets/guide/en/Basic/How_to_Get_VRender.md +++ /dev/null @@ -1,38 +0,0 @@ -# How to Get VRender - -There are several ways to get VRender: - -- Get it from npm -- Get it from cdn -- Get it from GitHub repository - -## npm Get - -```bash -# npm -$ npm install @visactor/vrender - -# yarn -$ yarn add @visactor/vrender -``` - -For how to use it when getting, see [How to Import VRender in a Project](./How_to_Import_VRender). - -## cdn Get - -You can get VRender from the following free CDNs: - -```html - - - - - -``` - -## GitHub Get - -You can get the VRender source code directly from GitHub: - -- You can directly clone the source code from GitHub. -- You can also select the corresponding version from the VRender [release](https://github.com/VisActor/VChart/releases) page, click on the Source code in the Assets section at the bottom of the page, download it to your local machine, extract it and use it. diff --git a/docs/assets/guide/en/Basic/How_to_Import_VMind.md b/docs/assets/guide/en/Basic/How_to_Import_VMind.md new file mode 100644 index 00000000..ced86bb1 --- /dev/null +++ b/docs/assets/guide/en/Basic/How_to_Import_VMind.md @@ -0,0 +1,51 @@ +# How to Reference VMind in Your Project + +In the [How to Get VMind](./How_to_Get_VMind) section, we introduced how to get VMind. This section will introduce how to reference VMind under these acquisition methods one by one. + +## Using cdn + +After we get the VMind file from [cdn](./How_to_Get_VMind#cdn-获取), we can add it to the ` + + +``` + +## Using npm + +After we install `@visactor/vmind` into the project through [npm](./How_to_Get_VMind#npm-获取), we can use it in the following way: + +```ts +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ +url, //default is https://api.openai.com/v1/chat/completions +model: Model.GPT3_5, +headers: { +'api-key': apiKey //Your LLM API Key +} +}) +``` diff --git a/docs/assets/guide/en/Basic/How_to_Import_VRender.md b/docs/assets/guide/en/Basic/How_to_Import_VRender.md deleted file mode 100644 index 516730c4..00000000 --- a/docs/assets/guide/en/Basic/How_to_Import_VRender.md +++ /dev/null @@ -1,11 +0,0 @@ -# How to Reference VChart in the Project - -In the [How to Get VRender](./How_to_Get_VRender) chapter, we introduced the ways to obtain VRender. This chapter will introduce how to reference VRender under these acquisition methods. - -## Use of CDN - -After obtaining the VChart file from [cdn](./How_to_Get_VRender#cdn-%E8%8E%B7%E5%8F%96), it can be added to the ` -``` +### Import through NPM Package + +Use `import` at the top of the JavaScript file to introduce VMind -## Introducing VRender +```js +import VMind from '@visactor/vmind'; +``` -### Import VRender via NPM Package +## Initialize VMind Instance -Use `import` to introduce VRender at the top of the JavaScript file: +First, we need to initialize a VMind instance and use it to complete subsequent operations. VMind currently supports OpenAI GPT-3.5, GPT-4 series models and Volcano Engine [Skylark (skylark-pro)](https://www.volcengine.com/product/yunque) series models. In the future, we will support more large language models. Welcome to visit [Github page](https://github.com/VisActor/VMind/issues/new/choose) to propose your needs. +Use the following code to initialize a VMind instance: ```js -import VRender from '@visactor/vrender'; +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ +url, //Specify your large model service url. The default is https://api.openai.com/v1/chat/completions +model: Model.GPT3_5, //Specify the model you specify +headers: { //Specify the header when calling the large model service +'api-key': apiKey //Your LLM API Key +} +}) ``` -### Import VRender using the script tag +When initializing the VMind instance, you can specify the url of the large model service, the type of model, custom model request methods and other parameters. For detailed tutorials, please go to the [Create VMind Instance](./Basic_Tutorial/Create_VMind_Instance.md) chapter -Introduce the built vchart file directly by adding a ` - - +In traditional chart generation steps, in order to make a complete chart, you need to complete the following steps: + +1. First prepare a set of data you want to display +2. Specify a chart type (chart recommendation) +3. Describe how the fields in the data are mapped to the visual channels of the chart (field mapping) +4. Modify the style of each element and set the chart palette (intelligent color matching) + +And to generate a chart with VMind, you only need to: + +1. Provide a set of data you want to display (csv format) +2. Describe your requirements for the chart, such as what information you want to display in the chart, what style of color matching to use, etc. + +For example, we want to use the following product sales data to show the sales of various products in different regions: + +| Product Name | region | Sales | +| -------- | ------ | ------ | +| Cola | south | 2350 | +| Cola | east | 1027 | +| Cola | west | 1027 | +| Cola | north | 1027 | +| Sprite | south | 215 | +| Sprite | east | 654 | +| Sprite | west | 159 | +| Sprite | north | 28 | +| Fanta | south | 345 | +| Fanta | east | 654 | +| Fanta | west | 2100 | +| Fanta | north | 1679 | +| Red Bull | south | 1476 | +| Red Bull | east | 830 | +| Red Bull | west | 532 | +| Red Bull | north | 498 | + +In order to use csv data in the subsequent process, you need to call the data processing method, extract the field information in the data, and convert it into a structured dataset. VMind provides methods based on rules and large models to obtain field information: +```ts +const csvData = `Product Name,region,Sales +Cola,south,2350 +Cola,east,1027 +Cola,west,1027 +Cola,north,1027 +Sprite,south,215 +Sprite,east,654 +Sprite,west,159 +Sprite,north,28 +Fanta,south,345 +Fanta,east,654 +Fanta,west,2100 +Fanta,north,1679 +Red Bull,south,1476 +Red Bull,east,830 +Red Bull,west,532 +Red Bull,north,498`; +//Pass in the csv string to get fieldInfo and dataset for chart generation +const { fieldInfo, dataset } = vmind.parseCSVData(csvData); +//Pass in the csv string and the user's display intention, call the large model, and get fieldInfo and dataset for chart generation. NOTE: This will send the data to the large model +const { fieldInfo, dataset } = await vmind.parseCSVDataWithLLM(csvData, userInput); ``` -## Drawing a Circle +The content we want to show is "the changes in the sales rankings of various car brands". Call the generateChart method and pass the data and display content description directly to VMind: +```typescript +const describe='show me the changes in sales rankings of various car brand' +//Call the chart generation interface to get spec and chart animation duration +const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +``` -Before we draw, we can prepare a DOM container with width and height for VRender. +Next, we can use VChart to draw the generated chart. +Before drawing, we need to prepare a DOM container with height and width for VChart. ```html - -
+ +
``` -Next, let's create a `Stage` instance based on this Canvas, create a circle and add it to the `Stage`: +Next, we create a `VChart` instance, pass in the spec just generated and the ID of the DOM container: ```ts -// Create a stage -const stage = createStage({ - canvas: 'main', - autoRender: true // Enable automatic rendering -}); -// Create a circle element -const circle = createCircle({ - radius: 60, - x: 200, - y: 200, - fill: 'red', -}); -// Add it to the stage -stage.defaultLayer.add(circle); +// Create vchart instance +const vchart = new VChart(spec, { dom: 'chart' }); +// Draw +vchart.renderSync(); ``` -At this point, you have successfully drawn a red circle! - -```javascript -// Create a stage -const stage = createStage({ - canvas: 'main', - autoRender: true // Enable automatic rendering -}); -// Create a circle element -const circle = createCircle({ - radius: 60, - x: 200, - y: 200, - fill: 'red', -}); -// Listen to click events, then change fill color to green -circle.addEventListener('click', () => { - circle.setAttribute('fill', 'green'); -}); -// Add it to the stage -stage.defaultLayer.add(circle); +The generated chart is as follows: + +![Bar Chart](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/bar.gif) + +We can also make more requests for the chart, for example: + +```typescript +const describe = 'Help me show the sales of various products in different regions, use line charts, and use region as the x-axis'; +const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); ``` -We hope this tutorial helps you learn how to use VChart. Now you can try drawing different types of charts and customize more diverse chart effects by understanding in depth the various configuration options of VChart. Embark on your VChart journey bravely! \ No newline at end of file +The generated chart is as follows: + +![Line Chart](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/line.gif) + +## Export GIF and Video + +VMind supports exporting the generated chart as a GIF animation and video, which can be shared anytime and anywhere. +In order to implement the video export function, you need to additionally introduce VChart and FFMPEG into the project and pass them in as objects to VMind. The following will show how to get the ObjectURL of the chart GIF and video: + +First install VChart and FFMPEG: +```bash +# Install with npm +npm install @visactor/vchart +npm install @ffmpeg/ffmpeg +npm install @ffmpeg/util +``` + +```typescript +import VChart from '@visactor/vchart'; +import { FFmpeg } from "@ffmpeg/ffmpeg"; +import { fetchFile } from "@ffmpeg/util"; +//Export video +const videoSrc = await vmind.exportVideo(spec, time, VChart, FFmpeg, fetchFile); //Pass in chart spec and video duration, return ObjectURL +//Export GIF image +const gifSrc = await vmind.exportGIF(spec, time, VChart, FFmpeg, fetchFile); //Pass in chart spec and GIF duration, return ObjectURL +``` + +Once you get the ObjectURL of the chart, we can save it as a file. Take saving the video file as an example: + +```typescript +//Create dom element to implement file download +const a = document.createElement('a'); +a.href = videoSrc; +a.download = `${filename}.mp4`; //Set the saved file name +a.dispatchEvent(new MouseEvent('click')); //Save file +``` + +## Summary + +This chapter introduces how to install and use VMind for chart generation, and demonstrates how to save the generated chart as a GIF and video. VMind currently supports bar charts, pie charts, line charts, scatter plots, word clouds, dynamic bar charts, and more chart types are under development. VMind can recommend suitable chart types based on user data and display intentions, map fields to suitable visual channels, and automatically generate palettes that meet user needs, reducing the threshold for users to perform data visualization and helping you easily complete data narratives. diff --git a/docs/assets/guide/en/Intro_to_VMind.md b/docs/assets/guide/en/Intro_to_VMind.md index 36687eae..809653e7 100644 --- a/docs/assets/guide/en/Intro_to_VMind.md +++ b/docs/assets/guide/en/Intro_to_VMind.md @@ -66,14 +66,8 @@ When using VMind to make data videos, users only need to describe the content th With the intelligent chart assistant built with VMind, you can use the function call capability of the large language model to judge the user's intent and call the VMind interface to realize chart generation and data interpretation, thereby reducing the difficulty of data visualization. -You can experience the VMind Intelligent Chart Assistant on [Cici](https://ciciai.com/bot/fUuxvgvv). +__You can try the VMind Chart Assistant on [Cici](https://ciciai.com/bot/fUuxvgvv).__ -![VMind Intelligent Chart Assistant](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_chart_assistant_1.png) - - -![VMind Intelligent Chart Assistant](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_chart_assistant_2.png) - - -![VMind Intelligent Chart Assistant](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_chart_assistant_3.png) +![VMind Intelligent Chart Assistant](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_assistant.png) diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index dc8b850c..d8d22039 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -30,17 +30,17 @@ }, "children": [ { - "path": "How_to_Get_VRender", + "path": "How_to_Get_VMind", "title": { - "zh": "如何获取VRender", - "en": "How to Get VRender" + "zh": "如何获取VMind", + "en": "How to Get VMind" } }, { - "path": "How_to_Import_VRender", + "path": "How_to_Import_VMind", "title": { - "zh": "如何在项目中引用 VRender", - "en": "How to Import VRender" + "zh": "如何在项目中引用 VMind", + "en": "How to Import VMind" } } ] @@ -55,8 +55,8 @@ { "path": "Events_and_Animation", "title": { - "zh": "创建VMind对象", - "en": "Create VMind Object" + "zh": "创建VMind实例", + "en": "Create VMind Instance" } }, { diff --git a/docs/assets/guide/zh/Basic/How_to_Get_VMind.md b/docs/assets/guide/zh/Basic/How_to_Get_VMind.md new file mode 100644 index 00000000..bab2ce19 --- /dev/null +++ b/docs/assets/guide/zh/Basic/How_to_Get_VMind.md @@ -0,0 +1,41 @@ +# 如何获取 VMind + +获取 VMind 的方式有以下几种: + +- 从 npm 获取 +- 从 cdn 获取 +- 从 GitHub 仓库获取 + +## npm 获取 + +首先,你需要在项目根目录下使用以下命令安装 VMind + +```bash +# 使用 npm 安装 +npm install @visactor/vmind + +# 使用 yarn 安装 +yarn add @visactor/vmind +``` + +VMind 需要配合 VChart 一起使用。为了进行图表绘制,你还需要在项目中引入 VChart,具体教程详见[VChart快速上手](https://www.visactor.io/vchart/guide/tutorial_docs/Getting_Started) + + +## cdn 获取 + +可以从以下免费的 CDN 中获取 VMind: + +```html + + + + + +``` + +## GitHub 获取 + +从 GitHub 上你可以直接获取 VMind 的源码: + +- 你可以直接从 GitHub clone 源码。 +- 你也可以从 VMind 的  [release](https://github.com/VisActor/VMind/releases)  页面选择对应的版本,点击页面下方 Assets 中的 Source code,将其下载至本地解压后使用。 diff --git a/docs/assets/guide/zh/Basic/How_to_Get_VRender.md b/docs/assets/guide/zh/Basic/How_to_Get_VRender.md deleted file mode 100644 index eb322f81..00000000 --- a/docs/assets/guide/zh/Basic/How_to_Get_VRender.md +++ /dev/null @@ -1,38 +0,0 @@ -# 如何获取 VRender - -获取 VRender 的方式有以下几种: - -- 从 npm 获取 -- 从 cdn 获取 -- 从 GitHub 仓库获取 - -## npm 获取 - -```bash -# npm -$ npm install @visactor/vrender - -# yarn -$ yarn add @visactor/vrender -``` - -获取时候如何使用,详见[如何在项目中引用 VRender](./How_to_Import_VRender)。 - -## cdn 获取 - -可以从以下免费的 CDN 中获取 VRender: - -```html - - - - - -``` - -## GitHub 获取 - -从 GitHub 上你可以直接获取 VRender 的源码: - -- 你可以直接从 GitHub clone 源码。 -- 你也可以从 VRender 的  [release](https://github.com/VisActor/VChart/releases)  页面选择对应的版本,点击页面下方 Assets 中的 Source code,将其下载至本地解压后使用。 diff --git a/docs/assets/guide/zh/Basic/How_to_Import_VMind.md b/docs/assets/guide/zh/Basic/How_to_Import_VMind.md new file mode 100644 index 00000000..ce739861 --- /dev/null +++ b/docs/assets/guide/zh/Basic/How_to_Import_VMind.md @@ -0,0 +1,51 @@ +# 如何在项目中引用 VMind + +在[如何获取 VMind](./How_to_Get_VMind)章节中我们介绍了获取 VMind 的方式,本章节会一一介绍这些获取方式下如何引用 VMind + +## cdn 使用 + +我们从 [cdn](./How_to_Get_VMind#cdn-获取) 获取到 VMind 文件后,就可以将其添加到 HTML 文件的 ` + + +``` + +## npm 使用 + +我们通过 [npm](./How_to_Get_VMind#npm-获取) 的方式将 `@visactor/vmind` 安装到项目之后,就可以通过如下方式进行使用了: + +```ts +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ + url, //default is https://api.openai.com/v1/chat/completions + model: Model.GPT3_5, + headers: { + 'api-key': apiKey //Your LLM API Key + } +}) +``` diff --git a/docs/assets/guide/zh/Basic/How_to_Import_VRender.md b/docs/assets/guide/zh/Basic/How_to_Import_VRender.md deleted file mode 100644 index c1240930..00000000 --- a/docs/assets/guide/zh/Basic/How_to_Import_VRender.md +++ /dev/null @@ -1,11 +0,0 @@ -# 如何在项目中引用 VChart - -在[如何获取 VRender](./How_to_Get_VRender)章节中我们介绍了获取 VRender 的方式,本章节会一一介绍这些获取方式下如何引用 VRender。 - -## cdn 使用 - -我们从  [cdn](./How_to_Get_VRender#cdn-%E8%8E%B7%E5%8F%96)  获取到 VChart 文件后,就可以将其添加到 HTML 文件的  ` -``` +### 通过 NPM 包引入 -## 引入 VRender +在 JavaScript 文件顶部使用 `import` 引入 VMind -### 通过 NPM 包引入 +```js +import VMind from '@visactor/vmind'; +``` -在 JavaScript 文件顶部使用 `import` 引入 VRender: +## 初始化 VMind 实例 + +首先我们需要初始化一个 VMind 实例,并用它完成后续操作。VMind 目前支持 OpenAI GPT-3.5,GPT-4 系列模型和火山引擎[云雀(skylark-pro)](https://www.volcengine.com/product/yunque)系列模型,未来我们将支持更多的大语言模型,欢迎访问[Github页面](https://github.com/VisActor/VMind/issues/new/choose)提出你的需求。 +使用以下代码初始化一个 VMind 实例: ```js -import VRender from '@visactor/vrender'; +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ + url, //指定你的大模型服务url。default is https://api.openai.com/v1/chat/completions + model: Model.GPT3_5, //指定你指定的模型 + headers: { //指定调用大模型服务时的header + 'api-key': apiKey //Your LLM API Key + } +}) ``` -### 使用 script 标签引入 +在初始化VMind实例时,你可以指定大模型服务的url,模型种类,自定义模型请求方法等参数。详细教程请前往[创建VMind实例](./Basic_Tutorial/Create_VMind_Instance.md)章节 -通过直接在 HTML 文件中添加 ` - - +在传统的图表生成步骤中,为了制作一个完整的图表,你需要完成以下步骤: + +1. 首先准备一份想要进行展示的数据 +2. 指定一个图表类型(图表推荐) +3. 描述数据中的字段如何映射到图表的视觉通道上(字段映射) +4. 对各个元素进行样式修改,并设置图表色板(智能配色) + +而使用 VMind 生成一张图表,你仅需要: + +1. 提供一份想要展示的数据(csv 格式) +2. 描述你对图表的要求,例如想在图表中展示哪些信息,使用何种风格的配色等等 + +例如,我们想使用下面的商品销售额数据,展示不同区域各商品销售额: + +| 商品名称 | region | 销售额 | +| -------- | ------ | ------ | +| 可乐 | south | 2350 | +| 可乐 | east | 1027 | +| 可乐 | west | 1027 | +| 可乐 | north | 1027 | +| 雪碧 | south | 215 | +| 雪碧 | east | 654 | +| 雪碧 | west | 159 | +| 雪碧 | north | 28 | +| 芬达 | south | 345 | +| 芬达 | east | 654 | +| 芬达 | west | 2100 | +| 芬达 | north | 1679 | +| 醒目 | south | 1476 | +| 醒目 | east | 830 | +| 醒目 | west | 532 | +| 醒目 | north | 498 | + +为了在后续流程中使用csv数据,需要调用数据处理方法,提取数据中的字段信息,并转换成结构化的dataset。VMind提供了基于规则的和基于大模型的方法来获取字段信息: +```ts +const csvData = `商品名称,region,销售额 +可乐,south,2350 +可乐,east,1027 +可乐,west,1027 +可乐,north,1027 +雪碧,south,215 +雪碧,east,654 +雪碧,west,159 +雪碧,north,28 +芬达,south,345 +芬达,east,654 +芬达,west,2100 +芬达,north,1679 +醒目,south,1476 +醒目,east,830 +醒目,west,532 +醒目,north,498`; +//传入csv字符串,获得fieldInfo和dataset用于图表生成 +const { fieldInfo, dataset } = vmind.parseCSVData(csvData); +//传入csv字符串,和用户的展示意图,调用大模型,获得fieldInfo和dataset用于图表生成。NOTE:这将会把明数据传给大模型 +const { fieldInfo, dataset } = await vmind.parseCSVDataWithLLM(csvData, userInput); ``` -## 绘制一个圆形 +我们想要展示的内容为“各品牌汽车销量排行的变化”。调用generateChart方法,将数据和展示内容描述直接传递给VMind: +```typescript +const describe='show me the changes in sales rankings of various car brand' +//调用图表生成接口,获得spec和图表动画时长 + const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +``` -在绘图前我们可以为 VRender 准备一个具备高宽的 DOM 容器。 +接下来,我们就可以使用 VChart 绘制生成的图表。 +在绘图前我们需要为 VChart 准备一个具备高宽的 DOM 容器。 ```html -
+
``` -接下来,我们基于这个Canvas创建一个 `Stage` 实例,创建一个圆形并添加到`Stage`中: +接下来,我们创建一个 `VChart` 实例,传入刚刚生成的 spec 和 DOM 容器的 ID: ```ts -// 创建一个stage -const stage = createStage({ - canvas: 'main', - autoRender: true // 开启自动渲染 -}); -// 创建一个circle图元 -const circle = createCircle({ - radius: 60, - x: 200, - y: 200, - fill: 'red', -}); -// 添加到stage中 -stage.defaultLayer.add(circle); +// 创建 vchart 实例 +const vchart = new VChart(spec, { dom: 'chart' }); +// 绘制 +vchart.renderSync(); ``` -至此,你已经成功绘制出了一个红色的圆形! - -```javascript -// 创建一个stage -const stage = createStage({ - canvas: 'main', - autoRender: true // 开启自动渲染 -}); -// 创建一个circle图元 -const circle = createCircle({ - radius: 60, - x: 200, - y: 200, - fill: 'red', -}); -// 监听点击事件,然后填充色变成绿色 -circle.addEventListener('click', () => { - circle.setAttribute('fill', 'green'); -}); -// 添加到stage中 -stage.defaultLayer.add(circle); +生成的图表如下: + +![柱状图](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/bar.gif) + +我们还可对图表提更多的要求,例如: + +```typescript +const describe = '帮我展示不同区域各商品销售额,使用折线图,region做x轴'; +const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +``` + +生成的图表如下: + +![折线图](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/line.gif) + +## 导出 GIF 和视频 + +VMind 支持将生成的图表导出为 GIF 格式的动画和视频,随时随地进行分享。 +为了实现视频导出功能,你需要在项目中额外引入VChart和FFMPEG,并将其作为对象传入VMind。下面将展示如何获得图表 GIF 和视频的 ObjectURL: + +首先安装VChart和FFMPEG: +```bash +# 使用 npm 安装 +npm install @visactor/vchart +npm install @ffmpeg/ffmpeg +npm install @ffmpeg/util +``` + +```typescript +import VChart from '@visactor/vchart'; +import { FFmpeg } from "@ffmpeg/ffmpeg"; +import { fetchFile } from "@ffmpeg/util"; +//导出视频 +const videoSrc = await vmind.exportVideo(spec, time, VChart, FFmpeg, fetchFile); //传入图表spec和视频时长,返回ObjectURL +//导出GIF图片 +const gifSrc = await vmind.exportGIF(spec, time, VChart, FFmpeg, fetchFile); //传入图表spec和GIF时长,返回ObjectURL ``` -希望这篇教程对你学习如何使用 VChart 有所帮助。现在,你可以尝试绘制不同类型的图表,并通过深入了解 VChart 的各种配置选项,定制出更加丰富多样的图表效果。勇敢开始你的 VChart 之旅吧! \ No newline at end of file +一旦获得图表的 ObjectURL,我们可以将其保存为文件。以保存视频文件为例: + +```typescript +//创建dom元素,实现文件下载 +const a = document.createElement('a'); +a.href = videoSrc; +a.download = `${filename}.mp4`; //设置保存的文件名 +a.dispatchEvent(new MouseEvent('click')); //保存文件 +``` + +## 总结 + +本章介绍了如何安装并使用 VMind 进行图表生成,并演示了如何将生成的图表保存为 GIF 和视频。VMind 目前支持柱状图、饼图、折线图、散点图、词云、动态条形图,更多图表类型正在开发中。VMind 能够根据用户数据和展示意图,推荐合适的图表类型,并将字段映射到合适的视觉通道上,自动生成符合用户需求的色板,降低用户进行数据可视化的门槛,帮助您轻松完成数据叙事。 diff --git a/docs/assets/guide/zh/Intro_to_VMind.md b/docs/assets/guide/zh/Intro_to_VMind.md index d4558563..5f6eedb7 100644 --- a/docs/assets/guide/zh/Intro_to_VMind.md +++ b/docs/assets/guide/zh/Intro_to_VMind.md @@ -47,7 +47,7 @@ VMind的核心能力包括图表智能生成、图表智能编辑和智能配色 -## VMind的实际运用 +## VMind使用场景 ### 数据视频 数据视频是一种将数据内容通过图表、动画、标注、旁白等形式进行展示和解读的视频类型。这种方式能够将原本抽象的数据转化为直观的图形,以更加生动有趣的方式呈现,使观众更容易理解和接受。 @@ -68,17 +68,14 @@ VMind的核心能力包括图表智能生成、图表智能编辑和智能配色 ### 图表智能助手 借助VMind打造的图表智能助手,你可以利用大语言模型的function call能力,判断用户的意图并调用VMind接口,实现图表的生成和数据的解读,从而降低数据可视化的难度。 -你可以在[Cici](https://ciciai.com/bot/fUuxvgvv)体验VMind图表智能助手。 -![VMind图表智能助手](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_chart_assistant_1.png) +__你可以在[Cici](https://ciciai.com/bot/fUuxvgvv)体验VMind图表助手。__ -![VMind图表智能助手](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_chart_assistant_2.png) +![VMind图表智能助手](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_assistant.png) -![VMind图表智能助手](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_chart_assistant_3.png) - From 82f500c5936b61640ac25387740e20878a13bb7f Mon Sep 17 00:00:00 2001 From: da730 Date: Fri, 2 Feb 2024 19:19:44 +0800 Subject: [PATCH 05/18] fix: vmind reference error --- packages/vmind/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vmind/tsconfig.json b/packages/vmind/tsconfig.json index 4a85d40f..ffe4a50e 100644 --- a/packages/vmind/tsconfig.json +++ b/packages/vmind/tsconfig.json @@ -8,7 +8,6 @@ "outDir": "./esm", "composite": true, "paths": { - "@visactor/calculator": ["../calculator/src"], } }, "ts-node": { From 9619627cef0cdc44d07aac7c12f9a5127cd197c0 Mon Sep 17 00:00:00 2001 From: da730 Date: Sun, 4 Feb 2024 16:21:40 +0800 Subject: [PATCH 06/18] feat: add create vmidn instance and data process --- .../Basic_Tutorial/Create_VMind_instance.md | 149 +++++++++ .../Cross_platform_Interface.md | 15 - .../guide/en/Basic_Tutorial/Data_Process.md | 219 +++++++++++++ .../en/Basic_Tutorial/Events_and_Animation.md | 78 ----- .../Basic_Tutorial/Extensions_and_Plugins.md | 263 --------------- docs/assets/guide/menu.json | 4 +- .../assets/guide/zh/Basic_Tutorial/Animate.md | 276 ---------------- .../Basic_Tutorial/Create_VMind_Instance.md | 148 +++++++++ .../Cross_platform_Interface.md | 15 - .../guide/zh/Basic_Tutorial/Data_Process.md | 218 +++++++++++++ .../zh/Basic_Tutorial/Events_and_Animation.md | 78 ----- .../Basic_Tutorial/Extensions_and_Plugins.md | 307 ------------------ docs/package.json | 2 +- 13 files changed, 737 insertions(+), 1035 deletions(-) create mode 100644 docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md delete mode 100644 docs/assets/guide/en/Basic_Tutorial/Cross_platform_Interface.md create mode 100644 docs/assets/guide/en/Basic_Tutorial/Data_Process.md delete mode 100644 docs/assets/guide/en/Basic_Tutorial/Events_and_Animation.md delete mode 100644 docs/assets/guide/en/Basic_Tutorial/Extensions_and_Plugins.md delete mode 100644 docs/assets/guide/zh/Basic_Tutorial/Animate.md create mode 100644 docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md delete mode 100644 docs/assets/guide/zh/Basic_Tutorial/Cross_platform_Interface.md create mode 100644 docs/assets/guide/zh/Basic_Tutorial/Data_Process.md delete mode 100644 docs/assets/guide/zh/Basic_Tutorial/Events_and_Animation.md delete mode 100644 docs/assets/guide/zh/Basic_Tutorial/Extensions_and_Plugins.md diff --git a/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md b/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md new file mode 100644 index 00000000..bc376d77 --- /dev/null +++ b/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md @@ -0,0 +1,149 @@ + +# Creating a VMind Instance +To start using the VMind intelligent visualization component, you first need to create a VMind instance. When creating a VMind instance, you need to pass in an options object as a parameter. This object contains some key information, such as the URL of the model, the model type, and the headers of the LLM service request, etc. +```ts +import VMind from '@visactor/vmind' + +const vmind = new VMind(options) +``` + +The complete type definition of options is as follows: + +```ts +export interface ILLMOptions { +url?: string; //URL of your LLM service. For gpt, default is openAI API. +/** llm request header, which has higher priority */ +headers?: HeadersInit; // this will be used directly as the header of the LLM request. +method?: 'POST' | 'GET'; //post or get +model?: Model; +max_tokens?: number; +temperature?: number; +showThoughts?: boolean; +customRequestFunc?: { +chartAdvisor: requestFunc; +dataProcess: requestFunc; +dataQuery: requestFunc; +}; +[key: string]: any; +} + +``` +In ILLMOptions, most parameters will be passed directly to the LLM service. + +If you plan to use the LLM service provided by OpenAI official and authenticate through the OpenAI api key in headers, you can simply initialize VMind like this: +```ts +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ +model: Model.GPT3_5, //use gpt-3.5-turbo model +headers: { //specify the header when calling the LLM service +Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY +} +}) +``` +In the following sections, we will explain the parameters in ILLMOptions in detail. + +## url +The url parameter is used to specify the address of your LLM service api. The default value is https://api.openai.com/v1/chat/completions + +In your use of VMind, all places that need to call the LLM will send http requests to this url. + +## headers +You can specify the http headers when requesting the LLM service through the headers parameter. The most common usage is to put your api key in headers for authentication; of course, you can also put any fields you need into headers. + +## method +The method parameter is used to specify the method type when requesting the LLM, usually POST. + +## model +You can specify the model type through the model parameter. This field will be put into the request body of the LLM service. You can import the Model type from VMind and use it as the value of the model field. +```ts +import { Model } from '@visactor/vmind' +``` + +The currently supported model types are: +```ts +//models that VMind support +//more models is under developing +export enum Model { +GPT3_5 = 'gpt-3.5-turbo', +GPT4 = 'gpt-4', +SKYLARK = 'skylark-pro', +SKYLARK2 = 'skylark2-pro-4k' +} +``` + +For different model types, VMind will use different technical implementations to complete tasks such as chart generation. + +## max_tokens and temperature +These two parameters respectively determine the maximum token quantity and temperature of the model-generated content, see [OpenAI official documentation](https://platform.openai.com/docs/api-reference/chat/create). + +In VMind, the default values of these two parameters are 2000 and 0 respectively. The effects of other values have not been fully tested, so it is not recommended to modify them. + +## showThoughts +[Related research](https://arxiv.org/abs/2201.11903) shows that the Chain-of-Thought can enhance the thinking reasoning ability of large language models and make the output results more in line with expectations. The showThoughts parameter will affect the prompt that VMind sends to the large language model, determining whether to add the thinking process to the output results when completing tasks such as chart generation and data aggregation. `showThoughts = true` will make the model explicitly output its thinking process, improving the accuracy of the generated results. However, this will increase the length of the model-generated results, bringing more token consumption. When performing tasks such as chart generation, VMind must wait for the model output to end before proceeding to the next step, which will also slow down the execution speed of various VMind methods. + +Therefore, if you expect better execution results, you can set showThoughts to true. If you want VMind to complete tasks such as chart generation and data aggregation with fewer tokens and faster speed, you can set this parameter to false. + +In VMind, showThoughts defaults to true. + +## Customizing the method of calling the LLM service through customRequestFunc + +VMind calls the LLM service through the requestGPT method by HTTP request. However, you can customize the method of calling the LLM in each task through the customRequestFunc parameter. For example, you can request your own LLM service in the form of RPC. +This parameter has three requestFunc type values, the complete type definition is as follows: +```ts +type customRequestFunc= { +chartAdvisor: requestFunc; +dataProcess: requestFunc; +dataQuery: requestFunc; +}; + +type requestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; + +export type LLMResponse = { +choices: { +index: number; +message: any; +}[]; +usage: any; +[key: string]: any; +}; +``` + +chartAdvisor, dataProcess, and dataQuery correspond to the methods of calling the LLM during chart generation, data processing, and data aggregation, respectively. Each method needs to receive the model prompt, user input, and VMind options as parameters, and ensure that the returned object is the same as the OpenAI completions API structure (see [The chat completion object](https://platform.openai.com/docs/api-reference/chat/object)). +Here is an example of using RPC for intelligent chart generation: +```ts +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ +model: Model.GPT3_5, +customRequestFunc: { +chartAdvisor: async (_prompt: string, +userMessage: string, +_options: ILLMOptions | undefined) => { +const resp = await call_RPC_LLM_Service(_prompt, userMessage, _options) + +const { result } = resp +const content = result.content.content +const gptResponse = { +usage: {}, //token usage information +choices: [{ +index: 0, +message: { +role: 'assistant', +content //Put the model's generated results into content +} +}] +} +return gptResponse //return chat completion object, see https://platform.openai.com/docs/api-reference/chat/object +} +} +}) + +const { spec } = await vmind.generateChart(userInput, fieldInfo, dataset); //Call generateChart for chart generation + +``` + +# Conclusion +This tutorial details how to create a VMind instance and how to set various parameters to meet different needs. We learned how to specify the url of the model service, how to set headers for authentication, how to choose the model type, and how to set the maximum token quantity and temperature of the model-generated content. We also learned how to control whether the model adds the thinking process to the output results through the showThoughts parameter, and how to customize the method of calling the LLM service through the customRequestFunc parameter. + +Through this tutorial, you can not only learn how to create and configure VMind instances, but also understand how to adjust and optimize the use of VMind according to your own needs and environment, so as to more effectively use VMind to complete various tasks, including chart generation, data processing, and data aggregation, etc. diff --git a/docs/assets/guide/en/Basic_Tutorial/Cross_platform_Interface.md b/docs/assets/guide/en/Basic_Tutorial/Cross_platform_Interface.md deleted file mode 100644 index f5afe884..00000000 --- a/docs/assets/guide/en/Basic_Tutorial/Cross_platform_Interface.md +++ /dev/null @@ -1,15 +0,0 @@ -# Cross-platform Interface Usage - -VRender provides a series of default interfaces to shield the impact of cross-platform. Currently, it supports environments such as `Browser`, `Node`, `feishu`, `tt`, and other environments can be supported through extensions. - -## Global - -Global is a static class that provides global cross-platform APIs. Users can directly use Global as the browser's window, and Global will automatically provide cross-platform compatibility. - -Global needs to be manually set to env, and there is no need to add cross-platform methods yourself. - -Note: For the node side, use node-canvas. Canopus will not automatically reference it, and you need to manually pass in the node-canvas package. - -## GraphicUtil - -Unlike Global, GraphicUtil provides cross-platform and graphic-related APIs, including Transform API, MeasureText API. \ No newline at end of file diff --git a/docs/assets/guide/en/Basic_Tutorial/Data_Process.md b/docs/assets/guide/en/Basic_Tutorial/Data_Process.md new file mode 100644 index 00000000..2cc9f221 --- /dev/null +++ b/docs/assets/guide/en/Basic_Tutorial/Data_Process.md @@ -0,0 +1,219 @@ + +# Data Format and Data Processing +In this tutorial, we will introduce in detail the data formats supported by VMind, and how to use the data processing functions in VMind to obtain these data. + +# VMind Data Format +## Dataset +In VMind, most functions require inputting a dataset. + +In VMind's definition, a dataset is a type of tabular data, its structure is the same as the [flattened data](https://www.visactor.io/vchart/guide/tutorial_docs/Chart_Concepts/Data/Data_Types_and_Interface) in VChart, which is an array composed of multiple data. +Take the product sales dataset as an example, the following shows an example of a dataset: +```json +// Product sales dataset +[ +{ +"Product name": "Coke", +"region": "south", +"Sales": 2350 +}, +{ +"Product name": "Coke", +"region": "east", +"Sales": 1027 +}, +{ +"Product name": "Coke", +"region": "west", +"Sales": 1027 +}, +{ +"Product name": "Coke", +"region": "north", +"Sales": 1027 +}, +{ +"Product name": "Sprite", +"region": "south", +"Sales": 215 +}, +{ +"Product name": "Sprite", +"region": "east", +"Sales": 654 +}, +{ +"Product name": "Sprite", +"region": "west", +"Sales": 159 +}, +{ +"Product name": "Sprite", +"region": "north", +"Sales": 28 +}, +{ +"Product name": "Fanta", +"region": "south", +"Sales": 345 +}, +{ +"Product name": "Fanta", +"region": "east", +"Sales": 654 +}, +{ +"Product name": "Fanta", +"region": "west", +"Sales": 2100 +}, +{ +"Product name": "Fanta", +"region": "north", +"Sales": 1679 +}, +{ +"Product name": "Mirinda", +"region": "south", +"Sales": 1476 +}, +{ +"Product name": "Mirinda", +"region": "east", +"Sales": 830 +}, +{ +"Product name": "Mirinda", +"region": "west", +"Sales": 532 +}, +{ +"Product name": "Mirinda", +"region": "north", +"Sales": 498 +} +] +``` + + +⚠️Note: **In order for the tasks such as chart generation and data aggregation in VMind to be better executed, we recommend that you use a semantically meaningful name for each field in the data (such as Product name, region, Sales, etc.). We do not recommend using field names without any semantics (column1, column2 or random strings, etc.). The large language model will depend on the semantic information contained in the field name to select fields during chart generation and data aggregation** +## Field Information fieldInfo +In VMind, you need to use the fieldInfo object to describe the field information in the dataset. FieldInfo describes the name, type, field description, etc. of each field in the data. This information will be passed to the large language model for tasks such as chart generation and data aggregation. + +The following is the type definition of the fieldInfo object: +```ts +export type SimpleFieldInfo = { +fieldName: string; +description?: string; //additional description of the field. This will help the model have a more comprehensive understanding of this field, improving the quality of chart generation. +type: DataType; +role: ROLE; +}; +``` +For the dataset shown in the previous section, the corresponding fieldInfo is as follows: +```json +[ +{ +"fieldName": "Product name", +"description": "Represents the name of the product, which is a string.", +"type": "string", +"role": "dimension" +}, +{ +"fieldName": "region", +"description": "Represents the region where the product is sold, which is a string.", +"type": "string", +"role": "dimension" +}, +{ +"fieldName": "Sales", +"description": "Represents the sales amount of the product, which is an integer.", +"type": "int", +"role": "measure" +} +] +``` + + +⚠️Note: **The large language model will depend on the field description in fieldInfo to select fields during chart generation and data aggregation. The description in fieldInfo is not mandatory and can be automatically generated by the parseCSVDataWithLLM function.** + +# Data Processing Functions +CSV data is a common and relatively simple file format that stores tabular data in plain text. In this chapter, we will introduce how to use the built-in data processing functions in VMind to convert csv data into dataset and fieldInfo. + +## parseCSVData +The parseCSVData function in VMind can convert a csv string into a dataset structure and generate fieldInfo by extracting field information through rules. During the execution of the function, the large language model will not be requested. +Taking the product sales dataset as an example, the following is an example of using the parseCSVData function: +```ts +import VMind from '@visactor/vmind' +const csv=`Product name,region,Sales +Coke,south,2350 +Coke,east,1027 +Coke,west,1027 +Coke,north,1027 +Sprite,south,215 +Sprite,east,654 +Sprite,west,159 +Sprite,north,28 +Fanta,south,345 +Fanta,east,654 +Fanta,west,2100 +Fanta,north,1679 +Mirinda,south,1476 +Mirinda,east,830 +Mirinda,west,532 +Mirinda,north,498` +const vmind = new VMind(options) +const { fieldInfo, dataset } = vmind.parseCSVData(csv); + +``` +In this example, the returned dataset is the same as the product sales dataset in the previous chapter, and the returned fieldInfo is as follows: +```json +[ +{ +"fieldName": "Product name", +"type": "string", +"role": "dimension" +}, +{ +"fieldName": "region", +"type": "string", +"role": "dimension" +}, +{ +"fieldName": "Sales", +"type": "int", +"role": "measure" +} +] +``` +The dataset and fieldInfo can be directly used for chart generation and data aggregation in VMind. + +Since this function does not pass the data to the large language model, it cannot obtain the field description in fieldInfo. You can also supplement it to get better chart generation results. + + +## parseCSVDataWithLLM +The parseCSVDataWithLLM function in VMind will pass the first 5 rows of csv data to the large language model, and obtain the dataset and fieldInfo in conjunction with the user's chart display intention. +The usage example is as follows: +```ts +import VMind from '@visactor/vmind' +const csv=`Product name,region,Sales +Coke,south,2350 +Coke,east,1027 +Coke,west,1027 +Coke,north,1027 +Sprite,south,215 +Sprite,east,654 +Sprite,west,159 +Sprite,north,28 +Fanta,south,345 +Fanta,east,654 +Fanta,west,2100 +Fanta,north,1679 +Mirinda,south,1476 +Mirinda,east,830 +Mirinda,west,532 +Mirinda,north,498` + +const describe=`Show the sales of each product in different regions` +const vmind = new VMind(options) +const { fieldInfo, dataset } = vmind.parseCSVData(parseCSVDataWithLLM, describe); +``` +In this example, the returned dataset and fieldInfo are the same as the product sales dataset in the previous chapter. diff --git a/docs/assets/guide/en/Basic_Tutorial/Events_and_Animation.md b/docs/assets/guide/en/Basic_Tutorial/Events_and_Animation.md deleted file mode 100644 index add79e8a..00000000 --- a/docs/assets/guide/en/Basic_Tutorial/Events_and_Animation.md +++ /dev/null @@ -1,78 +0,0 @@ -# Quick Start for Events and Animations - -In this section, we will learn how to use the `scene tree` to describe a scene, as well as how to use it in cross-platform environments. - -Our scene is very simple, consisting of a circular "drum." When the "drum" is clicked, it will trigger an animation, launching many small circles. - -## Create a Canvas - -``` -import { creator, Global } from '@dp/canopus' - -// No need to set env for the browser environment -Global.setEnv('tt'); - -// Create a stage with a default initial layer (layer) -const stage = createStage({ - canvas: 'main', - autoRender: true - }); -``` - -## Create Nodes - -```TypeScript -import { createCircle, createGroup } from '@dp/canopus'; - -const c1 = createCircle({ - radius: 60, - x: 300, - y: 300, - fill: 'orange', - stroke: '#ccc', - lineWidth: 6, - innerBorder: { - distance: 10, - lineWidth: 2, - stroke: '#eee' - } - }); - -const group = createGroup({}); - -group.add(c1); - -// 开启动画ticker,ticker需要手动开启,方便应用程序在合适的时候统一开始执行动画 -defaultTicker.start(); - -stage.defaultLayer.add(group); -``` - -## Add Events and Animations - -```TypeScript -// 监听click事件 -c1.addEventListener('click', () => { - c1.animate() - .to({radius: 70}, 300, 'elasticOut') - .to({radius: 60}, 600, 'linear'); - // 创建60个circle然后进行动画,完成后销毁 - for (let i = 0; i < 60; i++) { - const angle = Math.random() * Math.PI * 2; - const dir = [Math.cos(angle), Math.sin(angle)]; - const c = createCircle({ - x: 300, - y: 300, - radius: 8, - fill: colors[Math.floor(Math.random() * colors.length)] - }); - group.add(c); - c.animate({ - onEnd() { - // 动画结束后从将节点场景树中删除 - group.removeChild(c); - } - }).to({ dx: dir[0] * 200, dy: dir[1] * 200, opacity: 0 }, 2000, 'cubicOut'); - } - }); -``` \ No newline at end of file diff --git a/docs/assets/guide/en/Basic_Tutorial/Extensions_and_Plugins.md b/docs/assets/guide/en/Basic_Tutorial/Extensions_and_Plugins.md deleted file mode 100644 index 211318a5..00000000 --- a/docs/assets/guide/en/Basic_Tutorial/Extensions_and_Plugins.md +++ /dev/null @@ -1,263 +0,0 @@ -# Extensions and Plugins - -VRender supports the registration of extensions and plugins, and some built-in functions are supported by extensions and plugins. The following examples show how to write extensions and plugins. - -## Custom Rendering Extension - -Users can write their own rendering extensions to achieve the desired effects. If we want to replace the existing rect rendering with a hand-drawn style rendering, we need to: - -1. Write the RoughCanvasRectRender class, which implements the `IGraphicRender` interface - -```ts -import type { - IGraphicRender, - IRenderService, - IRect, - IGraphicAttribute, - IContext2d, - IGraphic, - IMarkAttribute, - IThemeAttribute, - IDrawContext, - IGraphicRenderDrawParams -} from '@visactor/vrender'; -import { RECT_NUMBER_TYPE, DefaultCanvasRectRender, getTheme, inject, injectable } from '@visactor/vrender'; -import rough from 'roughjs'; -import { defaultRouthThemeSpec } from './config'; - -@injectable() -export class RoughCanvasRectRender implements IGraphicRender { - type: 'rect'; - numberType: number; - style: 'rough' = 'rough'; - - constructor( - @inject(DefaultCanvasRectRender) - public readonly canvasRenderer: IGraphicRender - ) { - this.type = 'rect'; - this.numberType = RECT_NUMBER_TYPE; - } - - draw(rect: IRect, renderService: IRenderService, drawContext: IDrawContext, params?: IGraphicRenderDrawParams) { - const { context } = drawContext; - if (!context) { - return; - } - // Get the native canvas - const canvas = context.canvas.nativeCanvas; - const rc = rough.canvas(canvas); - - context.highPerformanceSave(); - - // const rectAttribute = graphicService.themeService.getCurrentTheme().rectAttribute; - const rectAttribute = getTheme(rect).rect; - let { x = rectAttribute.x, y = rectAttribute.y } = rect.attribute; - if (!rect.transMatrix.onlyTranslate()) { - // Poor performance - x = 0; - y = 0; - context.transformFromMatrix(rect.transMatrix, true); - } else { - const { dx = rectAttribute.dx, dy = rectAttribute.dy } = rect.attribute; - x += dx; - y += dy; - // The current context has rotate/scale, reset matrix - context.setTransformForCurrent(); - } - - const { - fill = rectAttribute.fill, - stroke = rectAttribute.stroke, - fillColor = rectAttribute.fill, - strokeColor = rectAttribute.stroke, - width = rectAttribute.width, - height = rectAttribute.height, - lineWidth = rectAttribute.lineWidth, - maxRandomnessOffset = defaultRouthThemeSpec.maxRandomnessOffset, - roughness = defaultRouthThemeSpec.roughness, - bowing = defaultRouthThemeSpec.bowing, - curveFitting = defaultRouthThemeSpec.curveFitting, - curveTightness = defaultRouthThemeSpec.curveTightness, - curveStepCount = defaultRouthThemeSpec.curveStepCount, - fillStyle = defaultRouthThemeSpec.fillStyle, - fillWeight = defaultRouthThemeSpec.fillWeight, - hachureAngle = defaultRouthThemeSpec.hachureAngle, - hachureGap = defaultRouthThemeSpec.hachureGap, - simplification = defaultRouthThemeSpec.simplification, - dashOffset = defaultRouthThemeSpec.dashOffset, - dashGap = defaultRouthThemeSpec.dashGap, - zigzagOffset = defaultRouthThemeSpec.zigzagOffset, - seed = defaultRouthThemeSpec.seed, - fillLineDash = defaultRouthThemeSpec.fillLineDash, - fillLineDashOffset = defaultRouthThemeSpec.fillLineDashOffset, - disableMultiStroke = defaultRouthThemeSpec.disableMultiStroke, - disableMultiStrokeFill = defaultRouthThemeSpec.disableMultiStrokeFill, - preserveVertices = defaultRouthThemeSpec.preserveVertices, - fixedDecimalPlaceDigits = defaultRouthThemeSpec.fixedDecimalPlaceDigits - } = rect.attribute as any; - rc.rectangle(x, y, width, height, { - fill: fill ? (fillColor as string) : undefined, - stroke: stroke ? (strokeColor as string) : undefined, - strokeWidth: lineWidth, - maxRandomnessOffset, - roughness, - bowing, - curveFitting, - curveTightness, - curveStepCount, - fillStyle, - fillWeight, - hachureAngle, - hachureGap, - simplification, - dashOffset, - dashGap, - zigzagOffset, - seed, - fillLineDash, - fillLineDashOffset, - disableMultiStroke, - disableMultiStrokeFill, - preserveVertices, - fixedDecimalPlaceDigits - }); - - context.highPerformanceRestore(); - } - - drawShape( - graphic: IGraphic, - ctx: IContext2d, - x: number, - y: number, - drawContext: IDrawContext, - params?: IGraphicRenderDrawParams, - fillCb?: ( - ctx: IContext2d, - markAttribute: Partial, - themeAttribute: IThemeAttribute - ) => boolean, - strokeCb?: ( - ctx: IContext2d, - markAttribute: Partial, - themeAttribute: IThemeAttribute - ) => boolean - ): void { - if (this.canvasRenderer.drawShape) { - return this.canvasRenderer.drawShape(graphic, ctx, x, y, drawContext, params, fillCb, strokeCb); - } - } -} -``` - -2. Register your class in the container - -```ts -export default new ContainerModule((bind, unbind, isBound, rebind) => { - // rect - bind(RoughCanvasRectRender).toSelf().inSingletonScope(); - bind(GraphicRender).to(RoughCanvasRectRender); -}); -``` - -3. Before the code runs, load your module - -```ts -container.load(your module); -``` - -## Custom Modification of Render Flow Injection - -If you don't want to modify the entire rendering logic but just want to do some operations before and after rendering, such as drawing the background before rect rendering, the process is as follows: - -1. Write a contribution, which implements the IBaseRenderContribution interface - -```ts -@injectable() -export class RectBackgroundRenderContribution implements IBaseRenderContribution { - time: BaseRenderContributionTime = BaseRenderContributionTime.beforeFillStroke; - useStyle: boolean = true; - order: number = 0; - drawShape( - graphic: IGraphic, - context: IContext2d, - x: number, - y: number, - doFill: boolean, - doStroke: boolean, - fVisible: boolean, - sVisible: boolean, - graphicAttribute: Required, - fillCb?: (ctx: IContext2d, markAttribute: Partial, themeAttribute: IThemeAttribute) => boolean, - strokeCb?: (ctx: IContext2d, markAttribute: Partial, themeAttribute: IThemeAttribute) => boolean, - options?: any - ) { - const { background } = graphic.attribute; - if (!background) { - return; - } - - if (graphic.backgroundImg && graphic.resources) { - const res = graphic.resources.get(background); - if (res.state !== 'success' || !res.data) { - return; - } - - context.save(); - - if (graphic.parent && !graphic.transMatrix.onlyTranslate()) { - const groupAttribute = getTheme(graphic.parent).group; - const { scrollX = groupAttribute.scrollX, scrollY = groupAttribute.scrollY } = graphic.parent.attribute; - context.setTransformFromMatrix(graphic.parent.globalTransMatrix, true); - context.translate(scrollX, scrollY); - } - context.clip(); - const b = graphic.AABBBounds; - context.setCommonStyle(graphic, graphic.attribute, x, y, graphicAttribute); - context.drawImage(res.data, b.x1, b.y1, b.width(), b.height()); - context.restore(); - if (!graphic.transMatrix.onlyTranslate()) { - context.setTransformForCurrent(); - } - } else { - context.highPerformanceSave(); - context.setCommonStyle(graphic, graphic.attribute, x, y, graphicAttribute); - context.fillStyle = background as string; - context.fill(); - context.highPerformanceRestore(); - } - } -} -``` - -2. Register your class in the container - -```ts -export default new ContainerModule((bind, unbind, isBound, rebind) => { - // rect - bind(DefaultRectBackgroundRenderContribution).toSelf().inSingletonScope(); - bind(RectRenderContribution).toService(DefaultRectBackgroundRenderContribution); -}); -``` - -3. Before the code runs, load your module - -```ts -container.load(your module); -``` - -## Developing Plugins - -Sometimes we only need to use some hooks to develop the desired plugins. For example, if you want to do automatic rendering, the plugin should be developed as follows: - -1. Write the plugin logic - -```ts -export class AutoRenderPlugin implements IPlugin { - name: 'AutoRenderPlugin' = 'AutoRenderPlugin'; - activeEvent: 'onRegister' = 'onRegister'; - pluginService: IPluginService; - _uid: number = Generator.GenAutoIncrementId(); - key: string -``` diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index d8d22039..33a160cb 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -53,14 +53,14 @@ }, "children": [ { - "path": "Events_and_Animation", + "path": "Create_VMind_Instance", "title": { "zh": "创建VMind实例", "en": "Create VMind Instance" } }, { - "path": "Animate", + "path": "Data_Process", "title": { "zh": "数据格式与数据处理", "en": "Data Format and Data Process" diff --git a/docs/assets/guide/zh/Basic_Tutorial/Animate.md b/docs/assets/guide/zh/Basic_Tutorial/Animate.md deleted file mode 100644 index eff1c318..00000000 --- a/docs/assets/guide/zh/Basic_Tutorial/Animate.md +++ /dev/null @@ -1,276 +0,0 @@ -# 动画 - -# 基本使用 - -## Graphic.Animate - -graphic.animate创建一个动画,提供`onStart`,`onEnd`,`onFrame`等钩子 - -```TypeScript -graphic - .animate({ - onStart: () => { - console.log('开始'); - }, - onEnd: () => { - console.log('结束'); - }, - onFrame: () => { - console.log('某一帧'); - } - }) - .to({ height: 200 }, 2000, 'quadIn') - .to({ x: 600 }, 200, 'quadIn') - .wait(200) - .to({ y: 600 }, 200, 'backInOut') - .to({ fillColor: 'green' }, 2000, 'quadIn'); -``` - -## Animate.to - -最通用的插值方法,从当前值插值到目标值 - -```TypeScript -graphic - .animate() - // 高度变化到200,耗时2000ms,插值函数是quadIn - .to({ height: 200 }, 2000, 'quadIn') -``` - -## Animate.wait - -等待时间 - -```TypeScript -graphic - .animate() - // 等待2000ms - .wait(2000) -``` - -## Animate.from - -最通用的插值方法,从目标值插值到当前值,和to的效果相反 - -```TypeScript -graphic - .animate() - // 高度从200插值到当前值,耗时2000ms,插值函数是quadIn - .from({ height: 200 }, 2000, 'quadIn') -``` - -## Animate.reverse - -反向执行 - -```TypeScript -graphic - .animate() - // 高度从200插值到当前值,耗时2000ms,插值函数是quadIn - .from({ height: 200 }, 2000, 'quadIn') - // 反向执行,将from变成to的效果 - .reverse(); -``` - -## Animate.loop - -循环 - -```TypeScript -graphic - .animate() - .to({ height: 200 }, 2000, 'quadIn') - // 再走count次,一共走count+1次 - .loop(count); -``` - -## Animate.bounce - -来回,需要配合loop使用 - -```TypeScript -graphic - .animate() - .to({ height: 200 }, 2000, 'quadIn') - // 执行一个来回,高度从当前变成2000,再从2000变成当前值 - .bounce() - // 循环count次,一共走count+1个单程 - .loop(count); -``` - -## Animate.startAt - -从startAt时刻开始,这个时刻不受loop的影响,只走一次 - -```TypeScript -graphic - .animate() - .startAt(2000) - .to({ height: 200 }, 2000, 'quadIn') - // 执行一个来回,高度从当前变成2000,再从2000变成当前值 - .bounce() - // 循环count次,一共走count+1个单程 - .loop(count); -``` - -# 子动画subAnimate - -子动画将动画分为不同阶段,每个阶段有独立的loop、bounce、reverse、startAt等状态,同时不同阶段也是按顺序执行 - -```TypeScript -graphic - .animate() - // 第一个动画,bounce再循环两次 - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn') - .to({ x: 200 }, 200, 'quadIn') - .wait(200) - .to({ y: 200 }, 200, 'backInOut') - .to({ fillColor: 'green' }, 200, 'quadIn') - .bounce(true) - .loop(2) - // 第二个动画,bounce再循环三次 - .subAnimate() - .startAt(2000) - .to({ x: 300 }, 200, 'quadIn') - .to({ y: 300 }, 2000, 'backIn') - .bounce(true) - .loop(3); -``` - -# 动画编排 - -animate支持一些动画编排相关的功能,用户不需要手动计算动画的执行时间即可链接不同动画 - -## Animate.after - -在某个动画结束之后执行 - -```TypeScript -const a1 = graphic.animate() - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -const a2 = graphic.animate() - .after(a1) // 在a1结束之后执行 - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -``` - -## Animate.afterAll - -在传递的动画数组内的所有动画结束之后执行 - -```TypeScript -const a1 = graphic.animate() - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -const a2 = graphic.animate() - .to({ height: 200 }, 200, 'quadIn'); -const a3 = graphic.animate() - .afterAll([a1, a2]) // a1和a2都执行完之后再执行 - .to({ height: 200 }, 200, 'quadIn'); -``` - -## Animate.parallel - -和某一个动画并行同时执行 - -```TypeScript -const a1 = graphic.animate() - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -const a2 = graphic.animate() - .after(a1) // 在a1结束之后执行 - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -const a3 = graphic.animate() - .parallel(a2) // 和a2同时执行 - .to({ height: 200 }, 200, 'quadIn'); -``` - -# 自定义插值 - -## Animate.AddInterpolate - -提供对某个key的自定义插值能力,注册函数全局生效,返回true表示插值成功 - -```TypeScript -Animate.AddInterpolate('text', (key, ratio, from, to, target, ret) => { - const _from = parseInt(from); - const _to = parseInt(to); - ret.text = (_from + (_to - _from) * ratio).toString(); - return true; - }); - // key传入空字符串,那么所有key都会匹配 - Animate.AddInterpolate('', (key, ratio, from, to, target, ret) => { - if (key === 'text') { - const _from = parseInt(from); - const _to = parseInt(to); - ret.text = (_from + (_to - _from) * ratio).toString(); - return true; - } - return false; - }); -``` - -## Animate参数interpolate(优先级更高) - -在创建animate的时候传入,这个函数只针对这个animate生效,返回true表示插值成功 - -```TypeScript -text.animate({ - interpolate(key, ratio, from, to, nextAttributes) { - if (key === 'text') { - nextAttributes.text = parseFloat(from) + (parseFloat(to + 1000) - parseFloat(from)) * ratio; - return true; - } - return false; - }, - }).to({ text: '100' }, 1000, 'quartIn'); -``` - -# 自定义动画 - -## 创建 - -继承ACustomAnimate,提供主要的方法如下 - -```TypeScript -export class IncreateCount extends ACustomAnimate { - // 这些参数都会被保存到this中 - // this.from = from; this.to = to; this.duration = duration; this.ease = ease; - constructor(from: any, to: any, duration: number, ease: EaseType) { - super(from, 0, duration, ease); - } - - // 结束时的属性 - getEndProps(): Record { - return { - text: this.to - }; - } - - // 绑定时调用,通常在这里会获取target的最初属性值 - onBind(): void { - this.to = parseFloat(this.target.getAnimatePropByName('text')); - } - - // 结束时调用,通常不需要做任何操作 - onEnd(): void { - return; - } - - // 插值时调用 - onUpdate(end: boolean, ratio: number, out: Record): void { - out.text = this.from + (this.to - this.from) * ratio; - } -} -``` - -## 使用 - -在play方法中传入自定义动画 - -```TypeScript -text .animate() .to({ fillColor: 'red' }, 1000, 'quadIn') .play(new IncreateCount(0, 0, 1000, 'quartIn')) .to({ fillColor: 'green' }, 1000, 'quadIn'); -``` \ No newline at end of file diff --git a/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md b/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md new file mode 100644 index 00000000..280f224f --- /dev/null +++ b/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md @@ -0,0 +1,148 @@ +# 创建VMind实例 +要开始使用VMind智能可视化组件,首先你需要创建一个VMind实例。在创建VMind实例时,你需要传入一个options对象作为参数,这个对象中包含了一些关键的信息,例如模型的url,模型类型,以及LLM服务请求的headers等。 +```ts +import VMind from '@visactor/vmind' + +const vmind = new VMind(options) +``` + +options的完整类型定义如下: + +```ts +export interface ILLMOptions { + url?: string; //URL of your LLM service. For gpt, default is openAI API. + /** llm request header, which has higher priority */ + headers?: HeadersInit; // this will be used directly as the header of the LLM request. + method?: 'POST' | 'GET'; //post or get + model?: Model; + max_tokens?: number; + temperature?: number; + showThoughts?: boolean; + customRequestFunc?: { + chartAdvisor: requestFunc; + dataProcess: requestFunc; + dataQuery: requestFunc; + }; + [key: string]: any; +} + +``` +在ILLMOptions中,大部分参数都会直接传递给LLM服务。 + +如果你打算使用openAI官方提供的LLM服务,并通过headers中的openAI api key进行鉴权,你可以这样简单地初始化VMind: +```ts +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ +model: Model.GPT3_5, //使用gpt-3.5-turbo模型 +headers: { //指定调用LLM服务时的header +Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY +} +}) +``` +在接下来的章节,我们将对ILLMOptions中的参数进行详细的解释。 + +## url +url参数用于指定你的LLM服务api的地址,默认值是https://api.openai.com/v1/chat/completions + +在你使用VMind的过程中,所有需要调用LLM的地方都会向这个url发送http请求。 + +## headers +你可以通过headers参数来指定请求LLM服务时的http headers。最常见的用法是将你的api key放入headers中用作鉴权;当然,你也可以将任何你需要的字段放入headers中。 + +## method +method参数用于指定请求LLM时的方法类型,通常为POST。 + +## model +你可以通过model参数来指定模型种类。这个字段将被放入LLM服务的请求体中。你可以从VMind中引入Model类型并用作model字段的值。 +```ts +import { Model } from '@visactor/vmind' +``` + +目前支持的模型种类有: +```ts +//models that VMind support +//more models is under developing +export enum Model { +GPT3_5 = 'gpt-3.5-turbo', +GPT4 = 'gpt-4', +SKYLARK = 'skylark-pro', +SKYLARK2 = 'skylark2-pro-4k' +} +``` + +对于不同的模型类型,VMind将采用不同的技术实现来完成图表生成等任务。 + +## max_tokens和temperature +这两个参数分别决定模型生成内容的最大token数量和temperature,详见[OpenAI官方文档](https://platform.openai.com/docs/api-reference/chat/create)。 + +在VMind中,这两个参数的默认值分别是2000和0,对于其他值的效果未经过充分测试,因此不建议修改。 + +## showThoughts +[相关研究](https://arxiv.org/abs/2201.11903)表明,思维链(Chain-of-Thought)可以增强大语言模型的思维推理能力,使输出的结果更加符合预期。showThoughts参数将影响VMind传给大语言模型的prompt,决定其在完成图表生成、数据聚合等任务时,是否将思考过程添加到输出结果中。`showThoughts = true`会使模型将其思考过程显式地输出,提高生成结果的准确性。然而,这会增加模型生成结果的长度,带来更多的token消耗。在执行图表生成等任务时,VMind必须等待模型输出结束后才能进行后续步骤,这也将减慢VMind各项方法的执行速度。 + +因此,如果你期望获得更好的执行效果,可以将showThoughts设置为true。如果你希望VMind能够以更少的token数量和更快的速度完成图表生成、数据聚合等任务,可以将这个参数设置为false。 + +在VMind中,showThoughts默认为true。 + +## 通过customRequestFunc自定义LLM服务调用方法 + +VMind通过requestGPT方法,通过HTTP请求进行LLM服务的调用。然而,你可以通过customRequestFunc参数,自定义在每种任务中调用LLM的方法。例如,你可以通过RPC的形式请求你自己的LLM服务。 +该参数有三个requestFunc类型的值,完整的类型定义如下: +```ts +type customRequestFunc= { +chartAdvisor: requestFunc; +dataProcess: requestFunc; +dataQuery: requestFunc; +}; + +type requestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; + +export type LLMResponse = { +choices: { +index: number; +message: any; +}[]; +usage: any; +[key: string]: any; +}; +``` + +chartAdvisor,dataProcess和dataQuery分别对应图表生成,数据处理和数据聚合时调用LLM的方法。每个方法需要接收模型prompt,用户输入和VMind options作为参数,并确保返回的对象与OpenAI completions API结构相同(详情请见[The chat completion object](https://platform.openai.com/docs/api-reference/chat/object))。 +下面展示一个使用RPC进行图表智能生成的例子: +```ts +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ +model: Model.GPT3_5, +customRequestFunc: { +chartAdvisor: async (_prompt: string, +userMessage: string, +_options: ILLMOptions | undefined) => { +const resp = await call_RPC_LLM_Service(_prompt, userMessage, _options) + +const { result } = resp +const content = result.content.content +const gptResponse = { + usage: {}, //token用量信息 + choices: [{ + index: 0, + message: { + role: 'assistant', + content //将模型的生成结果放入content中 +} +}] +} +return gptResponse //返回chat completion object,见https://platform.openai.com/docs/api-reference/chat/object +} +} +}) + +const { spec } = await vmind.generateChart(userInput, fieldInfo, dataset); //调用generateChart进行图表生成 + +``` + +# 总结 +本教程详细介绍了如何创建VMind实例,以及如何设置各种参数以满足不同的需求。我们学习了如何指定模型服务的url,如何设置headers以进行鉴权,如何选择模型类型,以及如何设置模型生成内容的最大token数量和temperature。我们还了解了如何通过showThoughts参数来控制模型是否将思考过程添加到输出结果中,以及如何通过customRequestFunc参数来自定义LLM服务的调用方法。 + +通过本教程,你不仅可以学会如何创建和配置VMind实例,更了解了如何根据自己的需求和环境来调整和优化VMind的使用,从而更有效地利用VMind来完成各种任务,包括图表生成、数据处理和数据聚合等。 diff --git a/docs/assets/guide/zh/Basic_Tutorial/Cross_platform_Interface.md b/docs/assets/guide/zh/Basic_Tutorial/Cross_platform_Interface.md deleted file mode 100644 index e4954f35..00000000 --- a/docs/assets/guide/zh/Basic_Tutorial/Cross_platform_Interface.md +++ /dev/null @@ -1,15 +0,0 @@ -# 跨端接口使用 - -VRender提供了一系列默认的接口,用于屏蔽跨端的影响,目前会支持`Browser`、`Node`、`feishu`、`tt`等环境,其余环境可以通过扩展支持。 - -## Global - -Global是一个静态类,提供了全局的跨端API,用户可以直接拿Global当浏览器的window用,Global会自动提供跨平台的兼容 - -Global需要手动设置env,不需要自行添加跨端方法 - -注意:node端使用node-canvas,Canopus不会自动引用,需要用户手动将node-canvas包传入 - -## GraphicUtil - -与Global不同的是,GraphicUtil提供的是跨端方面以及图形方面的API,其中包括Transform API,MeasureText API \ No newline at end of file diff --git a/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md b/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md new file mode 100644 index 00000000..0a3a057e --- /dev/null +++ b/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md @@ -0,0 +1,218 @@ +# 数据格式与数据处理 +在这篇教程中,我们将向你详细介绍VMind所支持的数据格式,并介绍如何使用VMind中的数据处理函数来获得这些数据。 + +# VMind数据格式 +## 数据集dataset +在VMind中,大部分函数都需要输入一个数据集dataset。 + +在VMind的定义中,数据集dataset是一种表格数据(Tabular Data),其结构与VChart中[展平的数据](https://www.visactor.io/vchart/guide/tutorial_docs/Chart_Concepts/Data/Data_Types_and_Interface)相同,是由多条数据组成的数组。 +以商品销售数据集为例,下面展示一个dataset的例子: +```json +// 商品销售数据集 +[ + { + "Product name": "Coke", + "region": "south", + "Sales": 2350 + }, + { + "Product name": "Coke", + "region": "east", + "Sales": 1027 + }, + { + "Product name": "Coke", + "region": "west", + "Sales": 1027 + }, + { + "Product name": "Coke", + "region": "north", + "Sales": 1027 + }, + { + "Product name": "Sprite", + "region": "south", + "Sales": 215 + }, + { + "Product name": "Sprite", + "region": "east", + "Sales": 654 + }, + { + "Product name": "Sprite", + "region": "west", + "Sales": 159 + }, + { + "Product name": "Sprite", + "region": "north", + "Sales": 28 + }, + { + "Product name": "Fanta", + "region": "south", + "Sales": 345 + }, + { + "Product name": "Fanta", + "region": "east", + "Sales": 654 + }, + { + "Product name": "Fanta", + "region": "west", + "Sales": 2100 + }, + { + "Product name": "Fanta", + "region": "north", + "Sales": 1679 + }, + { + "Product name": "Mirinda", + "region": "south", + "Sales": 1476 + }, + { + "Product name": "Mirinda", + "region": "east", + "Sales": 830 + }, + { + "Product name": "Mirinda", + "region": "west", + "Sales": 532 + }, + { + "Product name": "Mirinda", + "region": "north", + "Sales": 498 + } +] +``` + + +⚠️注意: **为了让VMind中的图表生成、数据聚合等任务能够更好地执行,我们建议你对数据中的每一个字段使用具有一定语义的名称(例如Product name,region,Sales等)。我们不建议使用没有任何语义的字段名称(column1,column2或随机字符串等)。大语言模型将依赖字段名称中蕴含的语义信息在图表生成、数据聚合时对字段进行选择** +## 字段信息fieldInfo +在VMind中,你需要使用fieldInfo对象来描述数据集中的字段信息。fieldInfo描述了数据中每个字段的名称、类型、字段描述等信息。这些信息将被传给LLM用于图表生成、数据聚合等任务中。 + +下面是fieldInfo对象的类型定义: +```ts +export type SimpleFieldInfo = { + fieldName: string; + description?: string; //additional description of the field. This will help the model have a more comprehensive understanding of this field, improving the quality of chart generation. + type: DataType; + role: ROLE; +}; +``` +对于上一个章节中展示的数据集,其对应的fieldInfo如下: +```json +[ + { + "fieldName": "Product name", + "description": "Represents the name of the product, which is a string.", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "region", + "description": "Represents the region where the product is sold, which is a string.", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "Sales", + "description": "Represents the sales amount of the product, which is an integer.", + "type": "int", + "role": "measure" + } +] +``` + + +⚠️注意: **大语言模型将依赖fieldInfo中的字段描述description,在图表生成、数据聚合时对字段进行选择。fieldInfo中的description不是必选项,可以通过parseCSVDataWithLLM函数自动生成。** + +# 数据处理函数 +CSV数据是一种通用的、相对简单的文件格式,它以纯文本形式存储表格数据。在本章,我们将介绍如何使用VMind内置的数据处理函数,将csv数据转换为dataset和fieldInfo + +## parseCSVData +VMind中的parseCSVData函数能够将csv字符串转换为dataset结构,并通过规则提取字段信息生成fieldInfo。在函数执行过程中,不会请求大语言模型。 +以商品销售数据集为例,下面是parseCSVData函数的使用示例: +```ts +import VMind from '@visactor/vmind' +const csv=`Product name,region,Sales +Coke,south,2350 +Coke,east,1027 +Coke,west,1027 +Coke,north,1027 +Sprite,south,215 +Sprite,east,654 +Sprite,west,159 +Sprite,north,28 +Fanta,south,345 +Fanta,east,654 +Fanta,west,2100 +Fanta,north,1679 +Mirinda,south,1476 +Mirinda,east,830 +Mirinda,west,532 +Mirinda,north,498` +const vmind = new VMind(options) +const { fieldInfo, dataset } = vmind.parseCSVData(csv); + +``` +在这个例子中,该函数返回的dataset与上一章的商品销售数据集dataset相同,返回的fieldInfo如下: +```json +[ + { + "fieldName": "Product name", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "region", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "Sales", + "type": "int", + "role": "measure" + } +] +``` +dataset和fieldInfo可直接用于VMind中的图表生成、数据聚合。 + +由于该函数未将数据传递给大语言模型,无法获得fieldInfo中的字段描述description。你也可以对其进行补充,以获得更好的图表生成效果。 + + +## parseCSVDataWithLLM +VMind中的parseCSVDataWithLLM函数会将csv数据取前5行传递给大语言模型,结合用户的图表展示意图,获得dataset和fieldInfo。 +使用示例如下: +```ts +import VMind from '@visactor/vmind' +const csv=`Product name,region,Sales +Coke,south,2350 +Coke,east,1027 +Coke,west,1027 +Coke,north,1027 +Sprite,south,215 +Sprite,east,654 +Sprite,west,159 +Sprite,north,28 +Fanta,south,345 +Fanta,east,654 +Fanta,west,2100 +Fanta,north,1679 +Mirinda,south,1476 +Mirinda,east,830 +Mirinda,west,532 +Mirinda,north,498` + +const describe=`展示各商品在不同区域销售额` +const vmind = new VMind(options) +const { fieldInfo, dataset } = vmind.parseCSVData(parseCSVDataWithLLM, describe); +``` +在这个例子中,返回的dataset和fieldInfo均与上一章的商品销售数据集dataset相同。 diff --git a/docs/assets/guide/zh/Basic_Tutorial/Events_and_Animation.md b/docs/assets/guide/zh/Basic_Tutorial/Events_and_Animation.md deleted file mode 100644 index 83140c82..00000000 --- a/docs/assets/guide/zh/Basic_Tutorial/Events_and_Animation.md +++ /dev/null @@ -1,78 +0,0 @@ -# 事件和动画快速入门 - -在本节中,我们将学习如何使用`场景树`描述场景,以及如何在跨端场景中使用。 - -我们的场景十分简单,包含一个圆形的“鼓”,当“鼓”被点击的时候,会触发动画,发射许多小圆 - -## 创建画布 - -```TypeScript -import { creator, Global } from '@dp/canopus' - -// 浏览器环境不需要设置env -Global.setEnv('tt'); - -// 创建一个stage,默认有一个初始图层(layer) -const stage = createStage({ - canvas: 'main', - autoRender: true - }); -``` - -## 创建节点 - -```TypeScript -import { createCircle, createGroup } from '@dp/canopus'; - -const c1 = createCircle({ - radius: 60, - x: 300, - y: 300, - fill: 'orange', - stroke: '#ccc', - lineWidth: 6, - innerBorder: { - distance: 10, - lineWidth: 2, - stroke: '#eee' - } - }); - -const group = createGroup({}); - -group.add(c1); - -// 开启动画ticker,ticker需要手动开启,方便应用程序在合适的时候统一开始执行动画 -defaultTicker.start(); - -stage.defaultLayer.add(group); -``` - -## 添加事件和动画 - -```TypeScript -// 监听click事件 -c1.addEventListener('click', () => { - c1.animate() - .to({radius: 70}, 300, 'elasticOut') - .to({radius: 60}, 600, 'linear'); - // 创建60个circle然后进行动画,完成后销毁 - for (let i = 0; i < 60; i++) { - const angle = Math.random() * Math.PI * 2; - const dir = [Math.cos(angle), Math.sin(angle)]; - const c = createCircle({ - x: 300, - y: 300, - radius: 8, - fill: colors[Math.floor(Math.random() * colors.length)] - }); - group.add(c); - c.animate({ - onEnd() { - // 动画结束后从将节点场景树中删除 - group.removeChild(c); - } - }).to({ dx: dir[0] * 200, dy: dir[1] * 200, opacity: 0 }, 2000, 'cubicOut'); - } - }); -``` \ No newline at end of file diff --git a/docs/assets/guide/zh/Basic_Tutorial/Extensions_and_Plugins.md b/docs/assets/guide/zh/Basic_Tutorial/Extensions_and_Plugins.md deleted file mode 100644 index 6d451108..00000000 --- a/docs/assets/guide/zh/Basic_Tutorial/Extensions_and_Plugins.md +++ /dev/null @@ -1,307 +0,0 @@ -# 扩展和插件 - -VRender 支持注册扩展和插件,并且内置的某些功能就是通过扩展和插件进行支持的,下面通过几个例子介绍如何编写扩展和插件 - -## 自定义渲染扩展 - -用户可以通过编写自己的渲染扩展,来实现自己想要的效果,如果我们想将现有的 rect 渲染替换成手绘风格的渲染,那么需要: - -1. 编写 RoughCanvasRectRender 类,该类实现了`IGraphicRender`接口 - -```ts -import type { - IGraphicRender, - IRenderService, - IRect, - IGraphicAttribute, - IContext2d, - IGraphic, - IMarkAttribute, - IThemeAttribute, - IDrawContext, - IGraphicRenderDrawParams -} from '@visactor/vrender'; -import { RECT_NUMBER_TYPE, DefaultCanvasRectRender, getTheme, inject, injectable } from '@visactor/vrender'; -import rough from 'roughjs'; -import { defaultRouthThemeSpec } from './config'; - -@injectable() -export class RoughCanvasRectRender implements IGraphicRender { - type: 'rect'; - numberType: number; - style: 'rough' = 'rough'; - - constructor( - @inject(DefaultCanvasRectRender) - public readonly canvasRenderer: IGraphicRender - ) { - this.type = 'rect'; - this.numberType = RECT_NUMBER_TYPE; - } - - draw(rect: IRect, renderService: IRenderService, drawContext: IDrawContext, params?: IGraphicRenderDrawParams) { - const { context } = drawContext; - if (!context) { - return; - } - // 获取到原生canvas - const canvas = context.canvas.nativeCanvas; - const rc = rough.canvas(canvas); - - context.highPerformanceSave(); - - // const rectAttribute = graphicService.themeService.getCurrentTheme().rectAttribute; - const rectAttribute = getTheme(rect).rect; - let { x = rectAttribute.x, y = rectAttribute.y } = rect.attribute; - if (!rect.transMatrix.onlyTranslate()) { - // 性能较差 - x = 0; - y = 0; - context.transformFromMatrix(rect.transMatrix, true); - } else { - const { dx = rectAttribute.dx, dy = rectAttribute.dy } = rect.attribute; - x += dx; - y += dy; - // 当前context有rotate/scale,重置matrix - context.setTransformForCurrent(); - } - - const { - fill = rectAttribute.fill, - stroke = rectAttribute.stroke, - fillColor = rectAttribute.fill, - strokeColor = rectAttribute.stroke, - width = rectAttribute.width, - height = rectAttribute.height, - lineWidth = rectAttribute.lineWidth, - maxRandomnessOffset = defaultRouthThemeSpec.maxRandomnessOffset, - roughness = defaultRouthThemeSpec.roughness, - bowing = defaultRouthThemeSpec.bowing, - curveFitting = defaultRouthThemeSpec.curveFitting, - curveTightness = defaultRouthThemeSpec.curveTightness, - curveStepCount = defaultRouthThemeSpec.curveStepCount, - fillStyle = defaultRouthThemeSpec.fillStyle, - fillWeight = defaultRouthThemeSpec.fillWeight, - hachureAngle = defaultRouthThemeSpec.hachureAngle, - hachureGap = defaultRouthThemeSpec.hachureGap, - simplification = defaultRouthThemeSpec.simplification, - dashOffset = defaultRouthThemeSpec.dashOffset, - dashGap = defaultRouthThemeSpec.dashGap, - zigzagOffset = defaultRouthThemeSpec.zigzagOffset, - seed = defaultRouthThemeSpec.seed, - fillLineDash = defaultRouthThemeSpec.fillLineDash, - fillLineDashOffset = defaultRouthThemeSpec.fillLineDashOffset, - disableMultiStroke = defaultRouthThemeSpec.disableMultiStroke, - disableMultiStrokeFill = defaultRouthThemeSpec.disableMultiStrokeFill, - preserveVertices = defaultRouthThemeSpec.preserveVertices, - fixedDecimalPlaceDigits = defaultRouthThemeSpec.fixedDecimalPlaceDigits - } = rect.attribute as any; - rc.rectangle(x, y, width, height, { - fill: fill ? (fillColor as string) : undefined, - stroke: stroke ? (strokeColor as string) : undefined, - strokeWidth: lineWidth, - maxRandomnessOffset, - roughness, - bowing, - curveFitting, - curveTightness, - curveStepCount, - fillStyle, - fillWeight, - hachureAngle, - hachureGap, - simplification, - dashOffset, - dashGap, - zigzagOffset, - seed, - fillLineDash, - fillLineDashOffset, - disableMultiStroke, - disableMultiStrokeFill, - preserveVertices, - fixedDecimalPlaceDigits - }); - - context.highPerformanceRestore(); - } - - drawShape( - graphic: IGraphic, - ctx: IContext2d, - x: number, - y: number, - drawContext: IDrawContext, - params?: IGraphicRenderDrawParams, - fillCb?: ( - ctx: IContext2d, - markAttribute: Partial, - themeAttribute: IThemeAttribute - ) => boolean, - strokeCb?: ( - ctx: IContext2d, - markAttribute: Partial, - themeAttribute: IThemeAttribute - ) => boolean - ): void { - if (this.canvasRenderer.drawShape) { - return this.canvasRenderer.drawShape(graphic, ctx, x, y, drawContext, params, fillCb, strokeCb); - } - } -} -``` - -2. 将你的类注册到容器中 - -```ts -export default new ContainerModule((bind, unbind, isBound, rebind) => { - // rect - bind(RoughCanvasRectRender).toSelf().inSingletonScope(); - bind(GraphicRender).to(RoughCanvasRectRender); -}); -``` - -3. 在代码运行之前,加载你的 module - -```ts -container.load(your module); -``` - -## 渲染流程注入自定义修改 - -如果你并不想修改整个渲染逻辑,而只是想在渲染前后进行一些操作,比如你需要在 rect 的渲染前绘制一次背景,那么流程如下: - -1. 编写 contribution,实现 IBaseRenderContribution 接口 - -```ts -@injectable() -export class RectBackgroundRenderContribution implements IBaseRenderContribution { - time: BaseRenderContributionTime = BaseRenderContributionTime.beforeFillStroke; - useStyle: boolean = true; - order: number = 0; - drawShape( - graphic: IGraphic, - context: IContext2d, - x: number, - y: number, - doFill: boolean, - doStroke: boolean, - fVisible: boolean, - sVisible: boolean, - graphicAttribute: Required, - fillCb?: (ctx: IContext2d, markAttribute: Partial, themeAttribute: IThemeAttribute) => boolean, - strokeCb?: (ctx: IContext2d, markAttribute: Partial, themeAttribute: IThemeAttribute) => boolean, - options?: any - ) { - const { background } = graphic.attribute; - if (!background) { - return; - } - - if (graphic.backgroundImg && graphic.resources) { - const res = graphic.resources.get(background); - if (res.state !== 'success' || !res.data) { - return; - } - - context.save(); - - if (graphic.parent && !graphic.transMatrix.onlyTranslate()) { - const groupAttribute = getTheme(graphic.parent).group; - const { scrollX = groupAttribute.scrollX, scrollY = groupAttribute.scrollY } = graphic.parent.attribute; - context.setTransformFromMatrix(graphic.parent.globalTransMatrix, true); - context.translate(scrollX, scrollY); - } - context.clip(); - const b = graphic.AABBBounds; - context.setCommonStyle(graphic, graphic.attribute, x, y, graphicAttribute); - context.drawImage(res.data, b.x1, b.y1, b.width(), b.height()); - context.restore(); - if (!graphic.transMatrix.onlyTranslate()) { - context.setTransformForCurrent(); - } - } else { - context.highPerformanceSave(); - context.setCommonStyle(graphic, graphic.attribute, x, y, graphicAttribute); - context.fillStyle = background as string; - context.fill(); - context.highPerformanceRestore(); - } - } -} -``` - -2. 将你的类注册到容器中 - -```ts -export default new ContainerModule((bind, unbind, isBound, rebind) => { - // rect - bind(DefaultRectBackgroundRenderContribution).toSelf().inSingletonScope(); - bind(RectRenderContribution).toService(DefaultRectBackgroundRenderContribution); -}); -``` - -3. 在代码运行之前,加载你的 module - -```ts -container.load(your module); -``` - -## 开发插件 - -有时候我们仅仅需要使用一些钩子开发想要的插件,比如如果想要做自动渲染,插件应该这么开发: - -1. 编写插件逻辑 - -```ts -export class AutoRenderPlugin implements IPlugin { - name: 'AutoRenderPlugin' = 'AutoRenderPlugin'; - activeEvent: 'onRegister' = 'onRegister'; - pluginService: IPluginService; - _uid: number = Generator.GenAutoIncrementId(); - key: string = this.name + this._uid; - - activate(context: IPluginService): void { - this.pluginService = context; - application.graphicService.hooks.onAttributeUpdate.tap(this.key, graphic => { - if (graphic.glyphHost) { - graphic = graphic.glyphHost; - } - if (graphic.stage === context.stage && graphic.stage != null) { - graphic.stage.renderNextFrame(); - } - }); - application.graphicService.hooks.onSetStage.tap(this.key, graphic => { - if (graphic.glyphHost) { - graphic = graphic.glyphHost; - } - if (graphic.stage === context.stage && graphic.stage != null) { - graphic.stage.renderNextFrame(); - } - }); - } - deactivate(context: IPluginService): void { - application.graphicService.hooks.onAttributeUpdate.taps = - application.graphicService.hooks.onAttributeUpdate.taps.filter(item => { - return item.name !== this.key; - }); - application.graphicService.hooks.onSetStage.taps = application.graphicService.hooks.onSetStage.taps.filter(item => { - return item.name !== this.key; - }); - } -} -``` - -2. 将插件注册到 plugin-service 中 - -```ts -stage.pluginService.register(new AutoRenderPlugin()); -``` - -3. 如果要卸载插件,调用插件的`plugin.deactivate`即可 - -```ts -stage.pluginService.findPluginsByName('AutoRenderPlugin').forEach(plugin => { - plugin.deactivate(this.pluginService); -}); -``` diff --git a/docs/package.json b/docs/package.json index b13c624c..d9acdc7d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -17,7 +17,7 @@ "react": "^18.0.0", "react-dom": "^18.0.0", "react-router-dom": "6.9.0", - "lodash": "4.17.21", + "lodash": "4.17.21" }, "devDependencies": { "@types/react": "^18.0.0", From 779ef4e0147e0eb11a0f44b9d74e3b5931fd6ce2 Mon Sep 17 00:00:00 2001 From: da730 Date: Sun, 4 Feb 2024 19:41:09 +0800 Subject: [PATCH 07/18] feat: add data aggregation docs --- README.md | 36 +- .../assets/guide/en/Basic_Tutorial/Animate.md | 276 ------------- .../Basic_Tutorial/Create_VMind_instance.md | 104 ++--- .../en/Basic_Tutorial/Data_Aggregation.md | 381 +++++++++++++++++ .../guide/en/Basic_Tutorial/Data_Process.md | 9 + docs/assets/guide/menu.json | 12 +- .../zh/Basic_Tutorial/Chart_Generation.md | 2 + .../Basic_Tutorial/Create_VMind_Instance.md | 76 ++-- .../zh/Basic_Tutorial/Data_Aggregation.md | 385 ++++++++++++++++++ .../guide/zh/Basic_Tutorial/Data_Process.md | 8 + readme-zh.md | 33 +- 11 files changed, 944 insertions(+), 378 deletions(-) delete mode 100644 docs/assets/guide/en/Basic_Tutorial/Animate.md create mode 100644 docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md create mode 100644 docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md create mode 100644 docs/assets/guide/zh/Basic_Tutorial/Data_Aggregation.md diff --git a/README.md b/README.md index dc5c05ab..361459cf 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ We want to show "the changes in sales rankings of various car brands". Call the ```typescript const describe = 'show me the changes in sales rankings of various car brand'; //Call the chart generation interface to get spec and chart animation duration -const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +const { spec, time } = await vmind.generateChart(describe, fieldInfo, dataset); ``` In this way, we get the VChart spec of the corresponding dynamic chart. We can render the chart based on this spec: @@ -164,7 +164,7 @@ Users can specify different theme styles (currently only gpt chart generation su //describe can be in both Chinese and English //Specify to generate a tech-style chart const describe = 'show me the changes in sales rankings of various car brand,tech style'; -const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +const { spec, time } = await vmind.generateChart(describe, fieldInfo, dataset); ``` You can also specify the chart type, field mapping, etc. supported by VMind. For example: @@ -173,7 +173,7 @@ You can also specify the chart type, field mapping, etc. supported by VMind. For //Specify to generate a line chart, with car manufacturers as the x-axis const describe = 'show me the changes in sales rankings of various car brands,tech style.Using a line chart, Manufacturer makes the x-axis'; -const { spec, time } = await(vmind.generateChart(csvData, describe)); +const { spec, time } = await(vmind.generateChart(csvData, describe, dataset)); ``` #### Customizing LLM Request Method @@ -196,6 +196,35 @@ temperature?: number;//recommended to set to 0 Specify your LLM service url in url (default is https://api.openai.com/v1/chat/completions) In subsequent calls, VMind will use the parameters in params to request the LLM service url. + + +#### Data Aggregation +📢 Note: The data aggregation function only supports GPT series models, more models will come soon. + +When using the chart library to draw bar charts, line charts, etc., if the data is not aggregated, it will affect the visualization effect. At the same time, because no filtering and sorting of fields has been done, some visualization intentions cannot be met, for example: show me the top 10 departments with the most cost, show me the sales of various products in the north, etc. + +VMind supports intelligent data aggregation since version 1.2.2. This function uses the data input by the user as a data table, uses a LLM to generate SQL queries according to the user's command, queries data from the data table, and uses GROUP BY and SQL aggregation methods to group, aggregate, sort, and filter data. Supported SQL statements include: SELECT, GROUP BY, WHERE, HAVING, ORDER BY, LIMIT. Supported aggregation methods are: MAX(), MIN(), SUM(), COUNT(), AVG(). Complex SQL operations such as subqueries, JOIN, and conditional statements are not supported. + + +Use the `dataQuery` function of the VMind object to aggregate data. This method has three parameters: +- userInput: user input. You can use the same input as generateChart +- fieldInfo: Dataset field information. The same as generateChart, it can be obtained by parseCSVData, or built by the user. +- dataset: Dataset. The same as generateChart, it can be obtained by parseCSVData, or built by the user. + + +```typescript +const { fieldInfo, dataset } = await vmind?.dataQuery(userInput, fieldInfo, dataset); +``` + + +The fieldInfo and dataset returned by this method are the field information and dataset after data aggregation, which can be used for chart generation. +By default, the `generateChart` function will perform a data aggregation using the same user input before generating the chart. You can disable data aggregation by passing in the fourth parameter: +```typescript +const userInput = 'show me the changes in sales rankings of various car brand'; +const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset, false); //pass false as the forth parameter to disable data aggregation before generating a chart. +``` + + #### Dialog-based editing Under development, stay tuned @@ -213,3 +242,4 @@ Under development, stay tuned #### Pie chart ![Alt text](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VChart-Video-3.gif) + diff --git a/docs/assets/guide/en/Basic_Tutorial/Animate.md b/docs/assets/guide/en/Basic_Tutorial/Animate.md deleted file mode 100644 index 289fe861..00000000 --- a/docs/assets/guide/en/Basic_Tutorial/Animate.md +++ /dev/null @@ -1,276 +0,0 @@ -# Animation - -# Basic Usage - -## Graphic.Animate - -Graphic.animate creates an animation, providing hooks such as `onStart`, `onEnd`, and `onFrame`. - -```TypeScript -graphic - .animate({ - onStart: () => { - console.log('开始'); - }, - onEnd: () => { - console.log('结束'); - }, - onFrame: () => { - console.log('某一帧'); - } - }) - .to({ height: 200 }, 2000, 'quadIn') - .to({ x: 600 }, 200, 'quadIn') - .wait(200) - .to({ y: 600 }, 200, 'backInOut') - .to({ fillColor: 'green' }, 2000, 'quadIn'); -``` - -## Animate.to - -The most common interpolation method, interpolating from the current value to the target value. - -```TypeScript -graphic - .animate() - // 高度变化到200,耗时2000ms,插值函数是quadIn - .to({ height: 200 }, 2000, 'quadIn') -``` - -## Animate.wait - -Wait time. - -```TypeScript -graphic - .animate() - // 等待2000ms - .wait(2000) -``` - -## Animate.from - -The most common interpolation method, interpolating from the target value to the current value, which has the opposite effect of `to`. - -```TypeScript -graphic - .animate() - // 高度从200插值到当前值,耗时2000ms,插值函数是quadIn - .from({ height: 200 }, 2000, 'quadIn') -``` - -## Animate.reverse - -Reverse execution. - -```TypeScript -graphic - .animate() - // 高度从200插值到当前值,耗时2000ms,插值函数是quadIn - .from({ height: 200 }, 2000, 'quadIn') - // 反向执行,将from变成to的效果 - .reverse(); -``` - -## Animate.loop - -Looping. - -```TypeScript -graphic - .animate() - .to({ height: 200 }, 2000, 'quadIn') - // 再走count次,一共走count+1次 - .loop(count); -``` - -## Animate.bounce - -Round-trip, needs to be used in conjunction with `loop`. - -```TypeScript -graphic - .animate() - .to({ height: 200 }, 2000, 'quadIn') - // 执行一个来回,高度从当前变成2000,再从2000变成当前值 - .bounce() - // 循环count次,一共走count+1个单程 - .loop(count); -``` - -## Animate.startAt - -Start at the `startAt` moment. This moment is not affected by the loop and will only run once. - -```TypeScript -graphic - .animate() - .startAt(2000) - .to({ height: 200 }, 2000, 'quadIn') - // 执行一个来回,高度从当前变成2000,再从2000变成当前值 - .bounce() - // 循环count次,一共走count+1个单程 - .loop(count); -``` - -# Sub-animations (subAnimate) - -Sub-animation divides the animation into different stages, each stage has independent loop, bounce, reverse, startAt, and other states, and different stages are executed sequentially. - -```TypeScript -graphic - .animate() - // 第一个动画,bounce再循环两次 - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn') - .to({ x: 200 }, 200, 'quadIn') - .wait(200) - .to({ y: 200 }, 200, 'backInOut') - .to({ fillColor: 'green' }, 200, 'quadIn') - .bounce(true) - .loop(2) - // 第二个动画,bounce再循环三次 - .subAnimate() - .startAt(2000) - .to({ x: 300 }, 200, 'quadIn') - .to({ y: 300 }, 2000, 'backIn') - .bounce(true) - .loop(3); -``` - -# Animation Arrangement - -Animate supports some animation arrangement-related features, allowing users to link different animations without manually calculating the animation execution time. - -## Animate.after - -Execute after a certain animation has ended. - -```TypeScript -const a1 = graphic.animate() - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -const a2 = graphic.animate() - .after(a1) // 在a1结束之后执行 - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -``` - -## Animate.afterAll - -Execute after all animations within the passed animation array have ended. - -```TypeScript -const a1 = graphic.animate() - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -const a2 = graphic.animate() - .to({ height: 200 }, 200, 'quadIn'); -const a3 = graphic.animate() - .afterAll([a1, a2]) // a1和a2都执行完之后再执行 - .to({ height: 200 }, 200, 'quadIn'); -``` - -## Animate.parallel - -Execute simultaneously with a certain animation in parallel. - -```TypeScript -const a1 = graphic.animate() - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -const a2 = graphic.animate() - .after(a1) // 在a1结束之后执行 - .startAt(2000) - .to({ height: 200 }, 200, 'quadIn'); -const a3 = graphic.animate() - .parallel(a2) // 和a2同时执行 - .to({ height: 200 }, 200, 'quadIn'); -``` - -# Custom Interpolation - -## Animate.AddInterpolate - -Provides custom interpolation capabilities for a particular key. The registered function takes global effect, and returning true indicates successful interpolation. - -```TypeScript -Animate.AddInterpolate('text', (key, ratio, from, to, target, ret) => { - const _from = parseInt(from); - const _to = parseInt(to); - ret.text = (_from + (_to - _from) * ratio).toString(); - return true; - }); - // key传入空字符串,那么所有key都会匹配 - Animate.AddInterpolate('', (key, ratio, from, to, target, ret) => { - if (key === 'text') { - const _from = parseInt(from); - const _to = parseInt(to); - ret.text = (_from + (_to - _from) * ratio).toString(); - return true; - } - return false; - }); -``` - -## Animate parameter interpolate (higher priority) - -Pass it in when creating the animate. This function only applies to this animate and returns true if the interpolation is successful. - -```TypeScript -text.animate({ - interpolate(key, ratio, from, to, nextAttributes) { - if (key === 'text') { - nextAttributes.text = parseFloat(from) + (parseFloat(to + 1000) - parseFloat(from)) * ratio; - return true; - } - return false; - }, - }).to({ text: '100' }, 1000, 'quartIn'); -``` - -# Custom Animation - -## Creation - -Extend ACustomAnimate, providing the main methods as follows. - -```TypeScript -export class IncreateCount extends ACustomAnimate { - // 这些参数都会被保存到this中 - // this.from = from; this.to = to; this.duration = duration; this.ease = ease; - constructor(from: any, to: any, duration: number, ease: EaseType) { - super(from, 0, duration, ease); - } - - // 结束时的属性 - getEndProps(): Record { - return { - text: this.to - }; - } - - // 绑定时调用,通常在这里会获取target的最初属性值 - onBind(): void { - this.to = parseFloat(this.target.getAnimatePropByName('text')); - } - - // 结束时调用,通常不需要做任何操作 - onEnd(): void { - return; - } - - // 插值时调用 - onUpdate(end: boolean, ratio: number, out: Record): void { - out.text = this.from + (this.to - this.from) * ratio; - } -} -``` - -## Usage - -Pass in the custom animation in the play method. - -```TypeScript -text .animate() .to({ fillColor: 'red' }, 1000, 'quadIn') .play(new IncreateCount(0, 0, 1000, 'quartIn')) .to({ fillColor: 'green' }, 1000, 'quadIn'); -``` \ No newline at end of file diff --git a/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md b/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md index bc376d77..c0c7f18f 100644 --- a/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md +++ b/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md @@ -11,20 +11,20 @@ The complete type definition of options is as follows: ```ts export interface ILLMOptions { -url?: string; //URL of your LLM service. For gpt, default is openAI API. -/** llm request header, which has higher priority */ -headers?: HeadersInit; // this will be used directly as the header of the LLM request. -method?: 'POST' | 'GET'; //post or get -model?: Model; -max_tokens?: number; -temperature?: number; -showThoughts?: boolean; -customRequestFunc?: { -chartAdvisor: requestFunc; -dataProcess: requestFunc; -dataQuery: requestFunc; -}; -[key: string]: any; + url?: string; //URL of your LLM service. For gpt, default is openAI API. + /** llm request header, which has higher priority */ + headers?: HeadersInit; // this will be used directly as the header of the LLM request. + method?: 'POST' | 'GET'; //post or get + model?: Model; + max_tokens?: number; + temperature?: number; + showThoughts?: boolean; + customRequestFunc?: { + chartAdvisor: requestFunc; + dataProcess: requestFunc; + dataQuery: requestFunc; + }; + [key: string]: any; } ``` @@ -35,9 +35,9 @@ If you plan to use the LLM service provided by OpenAI official and authenticate import VMind, { Model } from '@visactor/vmind' const vmind = new VMind({ -model: Model.GPT3_5, //use gpt-3.5-turbo model -headers: { //specify the header when calling the LLM service -Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY + model: Model.GPT3_5, //use gpt-3.5-turbo model + headers: { //specify the header when calling the LLM service + Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY } }) ``` @@ -65,10 +65,10 @@ The currently supported model types are: //models that VMind support //more models is under developing export enum Model { -GPT3_5 = 'gpt-3.5-turbo', -GPT4 = 'gpt-4', -SKYLARK = 'skylark-pro', -SKYLARK2 = 'skylark2-pro-4k' + GPT3_5 = 'gpt-3.5-turbo', + GPT4 = 'gpt-4', + SKYLARK = 'skylark-pro', + SKYLARK2 = 'skylark2-pro-4k' } ``` @@ -92,20 +92,20 @@ VMind calls the LLM service through the requestGPT method by HTTP request. Howev This parameter has three requestFunc type values, the complete type definition is as follows: ```ts type customRequestFunc= { -chartAdvisor: requestFunc; -dataProcess: requestFunc; -dataQuery: requestFunc; + chartAdvisor: requestFunc; + dataProcess: requestFunc; + dataQuery: requestFunc; }; type requestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; export type LLMResponse = { -choices: { -index: number; -message: any; -}[]; -usage: any; -[key: string]: any; + choices: { + index: number; + message: any; + }[]; + usage: any; + [key: string]: any; }; ``` @@ -115,28 +115,28 @@ Here is an example of using RPC for intelligent chart generation: import VMind, { Model } from '@visactor/vmind' const vmind = new VMind({ -model: Model.GPT3_5, -customRequestFunc: { -chartAdvisor: async (_prompt: string, -userMessage: string, -_options: ILLMOptions | undefined) => { -const resp = await call_RPC_LLM_Service(_prompt, userMessage, _options) - -const { result } = resp -const content = result.content.content -const gptResponse = { -usage: {}, //token usage information -choices: [{ -index: 0, -message: { -role: 'assistant', -content //Put the model's generated results into content -} -}] -} -return gptResponse //return chat completion object, see https://platform.openai.com/docs/api-reference/chat/object -} -} + model: Model.GPT3_5, + customRequestFunc: { + chartAdvisor: async (_prompt: string, + userMessage: string, + _options: ILLMOptions | undefined) => { + const resp = await call_RPC_LLM_Service(_prompt, userMessage, _options) + + const { result } = resp + const content = result.content.content + const gptResponse = { + usage: {}, //token usage information + choices: [{ + index: 0, + message: { + role: 'assistant', + content //Put the model's generated results into content + } + }] + } + return gptResponse //return chat completion object, see https://platform.openai.com/docs/api-reference/chat/object + } + } }) const { spec } = await vmind.generateChart(userInput, fieldInfo, dataset); //Call generateChart for chart generation diff --git a/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md b/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md new file mode 100644 index 00000000..8a478d43 --- /dev/null +++ b/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md @@ -0,0 +1,381 @@ +# Data Aggregation +📢 Note: Currently, the data aggregation feature only supports GPT series models, and we are working hard to integrate more models. + +## Overview of Data Aggregation +When we use chart libraries like VChart to draw bar charts, line charts, etc., if the dataset used has not been aggregated, it may have a negative impact on the visualization effect. +For example, suppose we have a product sales detail dataset: +```json +// Product sales dataset +[ + { + "Product name": "Coke", + "Sales": 2350 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Sprite", + "Sales": 215 + }, + { + "Product name": "Sprite", + "Sales": 654 + }, + { + "Product name": "Sprite", + "Sales": 159 + }, + { + "Product name": "Sprite", + "Sales": 28 + }, + { + "Product name": "Fanta", + "Sales": 345 + }, + { + "Product name": "Fanta", + "Sales": 654 + }, + { + "Product name": "Fanta", + "Sales": 2100 + }, + { + "Product name": "Fanta", + "Sales": 1679 + }, + { + "Product name": "Mirinda", + "Sales": 1476 + }, + { + "Product name": "Mirinda", + "Sales": 830 + }, + { + "Product name": "Mirinda", + "Sales": 532 + }, + { + "Product name": "Mirinda", + "Sales": 498 + } +] +``` +In this dataset, there are two fields Product name and Sales. It can be seen that in this dataset, multiple data have the same Product name. If we want to use this data to draw a bar chart with Product name as the X-axis and Sales as the Y-axis to show the sales in different regions, there will be multiple bars corresponding to each dimension value on the X-axis. + +Different chart libraries handle this kind of dataset differently. VChart's approach is to stack these bars for display: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_stack.png) + +Drawing charts with this unaggregated dataset may have the following problems: + +- Data overload: If the dataset is very large, there may be a large number of graphic elements in the chart, which may make the chart very chaotic, difficult to read and understand, and cause performance problems. +- Hiding important information: If the data has not been properly aggregated, it may hide some important information. For example, if you have a dataset containing daily sales, drawing this dataset directly may make the chart very chaotic. However, if you aggregate the data by month, it may be easier to see the trend of sales. +- Unclear data distribution: Unaggregated data may make the distribution characteristics of the data unclear, such as the average, median, mode, etc. + +Therefore, we usually aggregate the data appropriately before drawing the chart to better display the characteristics and trends of the data. + +At the same time, because the original dataset does not filter and sort the fields, some chart display intentions cannot be met, such as: show me the 10 departments with the highest sales, show me the sales of various products in the northern region, etc. + +Starting from version 1.2.2, VMind supports the intelligent data aggregation function. This function takes the data input by the user as a data table, generates SQL query statements according to the user's instructions using the large language model, queries data from the data table, and uses GROUP BY and aggregate functions to group, aggregate, sort, and filter the data. + + +Next, we will detail the usage of the VMind data aggregation function. + + +## dataQuery +The dataQuery function of the VMind object is a powerful data aggregation tool. It takes three parameters: userPrompt for user display intent, fieldInfo for dataset field information, and the original dataset. Detailed information about fieldInfo and dataset can be found in [Data Format and Data Processing](./Data_Process.md). VMind will write SQL statements based on the user's display intent, execute queries on the dataset, and the query results will be stored in the dataset property of the function return value; at the same time, the fields in the query results may change, and the updated field information will also be stored in the fieldInfo property of the return result. + +Next, let's see how to use the dataQuery function through an example: +```ts +import VMind from '@visactor/vmind' +const sourceDataset = [ + { + "Product name": "Coke", + "Sales": 2350 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Sprite", + "Sales": 215 + }, + { + "Product name": "Sprite", + "Sales": 654 + }, + { + "Product name": "Sprite", + "Sales": 159 + }, + { + "Product name": "Sprite", + "Sales": 28 + }, + { + "Product name": "Fanta", + "Sales": 345 + }, + { + "Product name": "Fanta", + "Sales": 654 + }, + { + "Product name": "Fanta", + "Sales": 2100 + }, + { + "Product name": "Fanta", + "Sales": 1679 + }, + { + "Product name": "Mirinda", + "Sales": 1476 + }, + { + "Product name": "Mirinda", + "Sales": 830 + }, + { + "Product name": "Mirinda", + "Sales": 532 + }, + { + "Product name": "Mirinda", + "Sales": 498 + } +] + +const sourceFieldInfo = [ + { + "fieldName": "Product name", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "Sales", + "type": "int", + "role": "measure" + } +] + +const describe=`Show the sales of each product` +const vmind = new VMind(options) + +// Call dataQuery with describe, sourceFieldInfo, and sourceDataset to perform data aggregation +const { fieldInfo, dataset } = vmind.dataQuery(describe, sourceFieldInfo, sourceDataset); +``` + +In this example, the dataset returned by the dataQuery function is as follows: +```json +[ + { + "Product name": "Coke", + "total_sales": 5431 + }, + { + "Product name": "Sprite", + "total_sales": 1056 + }, + { + "Product name": "Fanta", + "total_sales": 4778 + }, + { + "Product name": "Mirinda", + "total_sales": 3336 + } +] +``` + +The returned fieldInfo is as follows: +```json +[ + { + "fieldName": "Product name", + "description": "The name of the product.", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "total_sales", + "description": "An aggregated field representing the total sales of each product. It is generated by summing up the 'Sales' values for each product.", + "type": "int", + "role": "measure" + } +] + +``` + +With this information, we can directly use fieldInfo and dataset to generate charts. You can find the specific operation steps in the [Intelligent Chart Generation](./Chart_Generation.md) section. + +Finally, we will get the following bar chart: + + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_aggregated_bar.png) + +In this example, the SQL statement generated by VMind is: +```SQL +SELECT `Product name`, SUM(`Sales`) AS total_sales FROM dataSource GROUP BY `Product name` +``` + +This SQL statement selects the Produce name and Sales fields from the sourceDataset, groups by Produce name, and sums the Sales field to generate a new field total_sales. VMind will execute this SQL statement to get the aggregated dataset. + +It should be noted that the SQL keywords currently supported in the dataQuery execution process are: SELECT, GROUP BY, WHERE, HAVING, ORDER BY, LIMIT. The currently supported aggregation functions are: MAX(), MIN(), SUM(), COUNT(), AVG(), but complex SQL operations such as subqueries, JOIN, conditional statements, etc. are not supported. + +### Data Filtering and Sorting +In this section, we will learn how to use natural language to perform operations such as filtering and sorting on the dataset. + +First, let's take a look at the following dataset and field information: + +```ts +import VMind from '@visactor/vmind' + +const sourceDataset = [ +{ + "Product name": "Coke", + "region": "south", + "Sales": 2350 + }, + { + "Product name": "Coke", + "region": "east", + "Sales": 1027 + }, + { + "Product name": "Coke", + "region": "west", + "Sales": 1027 + }, + { + "Product name": "Coke", + "region": "north", + "Sales": 1027 + }, + { + "Product name": "Sprite", + "region": "south", + "Sales": 215 + }, + { + "Product name": "Sprite", + "region": "east", + "Sales": 654 + }, + { + "Product name": "Sprite", + "region": "west", + "Sales": 159 + }, + { + "Product name": "Sprite", + "region": "north", + "Sales": 28 + }, + { + "Product name": "Fanta", + "region": "south", + "Sales": 345 + }, + { + "Product name": "Fanta", + "region": "east", + "Sales": 654 + }, + { + "Product name": "Fanta", + "region": "west", + "Sales": 2100 + }, + { + "Product name": "Fanta", + "region": "north", + "Sales": 1679 + }, + { + "Product name": "Mirinda", + "region": "south", + "Sales": 1476 + }, + { + "Product name": "Mirinda", + "region": "east", + "Sales": 830 + }, + { + "Product name": "Mirinda", + "region": "west", + "Sales": 532 + }, + { + "Product name": "Mirinda", + "region": "north", + "Sales": 498 + } +] + +const sourceFieldInfo = [ + { + "fieldName": "Product name", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "region", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "Sales", + "type": "int", + "role": "measure" + } +] + +``` + +Suppose we want to show the top three products in terms of sales in the north region, we can do this: + +```ts +const describe = `Show me the top three products in terms of sales in the north region` +const vmind = new VMind(options) + +// Call the dataQuery method, pass in describe, sourceFieldInfo, and sourceDataset to perform data aggregation +const { fieldInfo, dataset } = vmind.dataQuery(describe, sourceFieldInfo, sourceDataset); +``` + +During the execution of the dataQuery method, the following SQL statement will be generated: + +```SQL +SELECT `Product name`, SUM(`Sales`) AS total_sales FROM dataSource WHERE region = 'north' GROUP BY `Product name` ORDER BY total_sales DESC LIMIT 3 +``` + +This SQL statement will filter out data where the region is 'north', then group by "Product name", and calculate the total sales of each product, finally sort by sales from high to low, and only take the top three products with the highest sales. + + +Finally, perform the chart generation operation, and we can get the following chart: + + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_order.png) diff --git a/docs/assets/guide/en/Basic_Tutorial/Data_Process.md b/docs/assets/guide/en/Basic_Tutorial/Data_Process.md index 2cc9f221..99b5b0ec 100644 --- a/docs/assets/guide/en/Basic_Tutorial/Data_Process.md +++ b/docs/assets/guide/en/Basic_Tutorial/Data_Process.md @@ -164,6 +164,10 @@ const vmind = new VMind(options) const { fieldInfo, dataset } = vmind.parseCSVData(csv); ``` + +For the creation of the VMind instance and the detailed configuration in options, please refer to [Creating VMind Instance](./Create_VMind_Instance.md) + + In this example, the returned dataset is the same as the product sales dataset in the previous chapter, and the returned fieldInfo is as follows: ```json [ @@ -184,6 +188,11 @@ In this example, the returned dataset is the same as the product sales dataset i } ] ``` + + +For the creation of the VMind instance and the detailed configuration in options, please refer to [Creating VMind Instance](./Create_VMind_Instance.md) + + The dataset and fieldInfo can be directly used for chart generation and data aggregation in VMind. Since this function does not pass the data to the large language model, it cannot obtain the field description in fieldInfo. You can also supplement it to get better chart generation results. diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index 33a160cb..67ef4f84 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -67,17 +67,17 @@ } }, { - "path": "Animate", + "path": "Data_Aggregation", "title": { - "zh": "图表智能生成", - "en": "Intelligent Chart Generation" + "zh": "智能数据聚合", + "en": "Intelligent Data Aggregation" } }, { - "path": "Extensions_and_Plugins", + "path": "Animate", "title": { - "zh": "智能数据聚合", - "en": "Intelligent Data Aggregation" + "zh": "图表智能生成", + "en": "Intelligent Chart Generation" } }, { diff --git a/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md b/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md new file mode 100644 index 00000000..72eac95e --- /dev/null +++ b/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md @@ -0,0 +1,2 @@ +# 图表生成 +本教程将介绍VMind中的图表智能生成函数,并提供一些示例 diff --git a/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md b/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md index 280f224f..8bbe232b 100644 --- a/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md +++ b/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md @@ -34,9 +34,9 @@ export interface ILLMOptions { import VMind, { Model } from '@visactor/vmind' const vmind = new VMind({ -model: Model.GPT3_5, //使用gpt-3.5-turbo模型 -headers: { //指定调用LLM服务时的header -Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY + model: Model.GPT3_5, //使用gpt-3.5-turbo模型 + headers: { //指定调用LLM服务时的header + Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY } }) ``` @@ -64,10 +64,10 @@ import { Model } from '@visactor/vmind' //models that VMind support //more models is under developing export enum Model { -GPT3_5 = 'gpt-3.5-turbo', -GPT4 = 'gpt-4', -SKYLARK = 'skylark-pro', -SKYLARK2 = 'skylark2-pro-4k' + GPT3_5 = 'gpt-3.5-turbo', + GPT4 = 'gpt-4', + SKYLARK = 'skylark-pro', + SKYLARK2 = 'skylark2-pro-4k' } ``` @@ -91,20 +91,20 @@ VMind通过requestGPT方法,通过HTTP请求进行LLM服务的调用。然而 该参数有三个requestFunc类型的值,完整的类型定义如下: ```ts type customRequestFunc= { -chartAdvisor: requestFunc; -dataProcess: requestFunc; -dataQuery: requestFunc; + chartAdvisor: requestFunc; + dataProcess: requestFunc; + dataQuery: requestFunc; }; type requestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; export type LLMResponse = { -choices: { -index: number; -message: any; -}[]; -usage: any; -[key: string]: any; + choices: { + index: number; + message: any; + }[]; + usage: any; + [key: string]: any; }; ``` @@ -114,28 +114,28 @@ chartAdvisor,dataProcess和dataQuery分别对应图表生成,数据处理和 import VMind, { Model } from '@visactor/vmind' const vmind = new VMind({ -model: Model.GPT3_5, -customRequestFunc: { -chartAdvisor: async (_prompt: string, -userMessage: string, -_options: ILLMOptions | undefined) => { -const resp = await call_RPC_LLM_Service(_prompt, userMessage, _options) - -const { result } = resp -const content = result.content.content -const gptResponse = { - usage: {}, //token用量信息 - choices: [{ - index: 0, - message: { - role: 'assistant', - content //将模型的生成结果放入content中 -} -}] -} -return gptResponse //返回chat completion object,见https://platform.openai.com/docs/api-reference/chat/object -} -} + model: Model.GPT3_5, + customRequestFunc: { + chartAdvisor: async (_prompt: string, + userMessage: string, + _options: ILLMOptions | undefined) => { + const resp = await call_RPC_LLM_Service(_prompt, userMessage, _options) + + const { result } = resp + const content = result.content.content + const gptResponse = { + usage: {}, //token用量信息 + choices: [{ + index: 0, + message: { + role: 'assistant', + content //将模型的生成结果放入content中 + } + }] + } + return gptResponse //返回chat completion object,见https://platform.openai.com/docs/api-reference/chat/object + } + } }) const { spec } = await vmind.generateChart(userInput, fieldInfo, dataset); //调用generateChart进行图表生成 diff --git a/docs/assets/guide/zh/Basic_Tutorial/Data_Aggregation.md b/docs/assets/guide/zh/Basic_Tutorial/Data_Aggregation.md new file mode 100644 index 00000000..d8ddeb0c --- /dev/null +++ b/docs/assets/guide/zh/Basic_Tutorial/Data_Aggregation.md @@ -0,0 +1,385 @@ +# 数据聚合 +📢 注意:目前数据聚合功能仅支持GPT系列模型,我们正在努力接入更多模型。 + +## 数据聚合概述 +当我们使用VChart等图表库来绘制柱状图、折线图等图表时,如果使用的数据集dataset并未经过聚合处理,可能会对可视化效果产生不良影响。 +举例来说,假设我们有一份商品销售额明细数据集: +```json +// 商品销售数据集 +[ + { + "Product name": "Coke", + "Sales": 2350 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Sprite", + "Sales": 215 + }, + { + "Product name": "Sprite", + "Sales": 654 + }, + { + "Product name": "Sprite", + "Sales": 159 + }, + { + "Product name": "Sprite", + "Sales": 28 + }, + { + "Product name": "Fanta", + "Sales": 345 + }, + { + "Product name": "Fanta", + "Sales": 654 + }, + { + "Product name": "Fanta", + "Sales": 2100 + }, + { + "Product name": "Fanta", + "Sales": 1679 + }, + { + "Product name": "Mirinda", + "Sales": 1476 + }, + { + "Product name": "Mirinda", + "Sales": 830 + }, + { + "Product name": "Mirinda", + "Sales": 532 + }, + { + "Product name": "Mirinda", + "Sales": 498 + } +] +``` +在这个数据集中,有两个字段Product name和Sales。可以看出在这个数据集中,有多条数据具有相同的Product name。如果我们想使用这份数据将Product name作为X轴,Sales作为Y轴来绘制柱状图,展示不同地区的销售额,则在X轴每个维值下面将有多条柱子与之对应。 + +对于这种数据集,不同图表库的处理方式不同。VChart的处理方式是将这些柱子堆叠起来进行展示: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_stack.png) + +使用这种未聚合的数据集绘制图表可能会有以下几个问题: + +- 数据过载:如果数据集非常大,那么图表中可能会有大量的图元,这可能会使图表变得非常混乱,难以阅读和理解,还会导致性能问题。 +- 隐藏重要的信息:如果数据没有经过适当的聚合,那么可能会隐藏一些重要的信息。例如,如果你有一个包含每天销售额的数据集,那么直接绘制这个数据集可能会导致图表变得非常混乱。但是,如果你将数据按月聚合,那么可能会更容易看出销售额的趋势。 +- 数据分布不清:未聚合的数据可能会使得数据的分布特征不明显,例如平均值、中位数、众数等。 + +因此,通常在绘制图表之前,我们会先对数据进行适当的聚合,以便更好地展示数据的特征和趋势。 + +同时由于原始的数据集没有对字段进行筛选和排序,某些图表展示意图无法满足,例如:帮我展示销售额最多的10个部门,帮我展示北方区域各商品的销售额等。 + +VMind 1.2.2版本开始支持智能数据聚合功能。该功能会将用户传入的数据作为一张数据表,使用大语言模型根据用户的指令生成SQL查询语句,从数据表中查询数据,并通过GROUP BY和聚合函数对数据进行分组聚合、排序、筛选。 + + +接下来,我们将详细介绍VMind数据聚合功能的使用方法。 + + +## dataQuery +VMind对象的dataQuery函数是一个强大的数据聚合工具。它接收三个参数:用户展示意图userPrompt,数据集字段信息fieldInfo和原始数据集dataset。你可以在[数据格式与数据处理](./Data_Process.md)中找到关于fieldInfo和dataset的详细信息。VMind会根据用户的展示意图,编写SQL语句并对dataset执行查询,查询结果会被储存在函数返回值的dataset属性中;同时,查询结果中的字段可能会发生变化,更新后的字段信息也会被储存在返回结果的fieldInfo属性中。 + +下面,让我们通过一个示例来看看如何使用dataQuery函数: +```ts +import VMind from '@visactor/vmind' +const sourceDataset = [ + { + "Product name": "Coke", + "Sales": 2350 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Coke", + "Sales": 1027 + }, + { + "Product name": "Sprite", + "Sales": 215 + }, + { + "Product name": "Sprite", + "Sales": 654 + }, + { + "Product name": "Sprite", + "Sales": 159 + }, + { + "Product name": "Sprite", + "Sales": 28 + }, + { + "Product name": "Fanta", + "Sales": 345 + }, + { + "Product name": "Fanta", + "Sales": 654 + }, + { + "Product name": "Fanta", + "Sales": 2100 + }, + { + "Product name": "Fanta", + "Sales": 1679 + }, + { + "Product name": "Mirinda", + "Sales": 1476 + }, + { + "Product name": "Mirinda", + "Sales": 830 + }, + { + "Product name": "Mirinda", + "Sales": 532 + }, + { + "Product name": "Mirinda", + "Sales": 498 + } +] + +const sourceFieldInfo = [ + { + "fieldName": "Product name", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "Sales", + "type": "int", + "role": "measure" + } +] + +const describe=`展示各商品销售额` +const vmind = new VMind(options) + +//调用dataQuery传入describe,sourceFieldInfo和sourceDataset,执行数据聚合 +const { fieldInfo, dataset } = vmind.dataQuery(describe, sourceFieldInfo, sourceDataset); +``` + +在这个例子中,dataQuery函数返回的dataset如下: +```json +[ + { + "Product name": "Coke", + "total_sales": 5431 + }, + { + "Product name": "Sprite", + "total_sales": 1056 + }, + { + "Product name": "Fanta", + "total_sales": 4778 + }, + { + "Product name": "Mirinda", + "total_sales": 3336 + } +] +``` + +返回的fieldInfo如下: +```json +[ + { + "fieldName": "Product name", + "description": "The name of the product.", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "total_sales", + "description": "An aggregated field representing the total sales of each product. It is generated by summing up the 'Sales' values for each product.", + "type": "int", + "role": "measure" + } +] +``` + +有了这些信息,我们就可以直接使用fieldInfo和dataset生成图表了。具体的操作步骤,你可以在[图表智能生成](./Chart_Generation.md)章节中找到。 + +最后,我们将得到如下的柱状图: + + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_aggregated_bar.png) + +在这个例子中,VMind生成的SQL语句为: +```SQL +SELECT `Product name`, SUM(`Sales`) AS total_sales FROM dataSource GROUP BY `Product name` +``` + +这条SQL语句从sourceDataset中筛选出Produce name和Sales两个字段,按照Produce name进行分组,并对Sales字段进行了求和,生成了新的字段total_sales。VMind将执行这一sql语句,得到聚合后的数据集。 + +需要注意的是,dataQuery执行过程中,目前支持的SQL关键词有:SELECT, GROUP BY, WHERE, HAVING, ORDER BY, LIMIT。目前支持的聚合函数有:MAX(), MIN(), SUM(), COUNT(), AVG(),但不支持子查询、JOIN、条件语句等复杂的SQL操作。 + +### 数据筛选与排序 +在这个部分,我们将学习如何使用自然语言来对数据集进行筛选和排序等操作。 + +首先,让我们看一下下面的数据集(dataset)和字段信息(fieldInfo): + +```ts +import VMind from '@visactor/vmind' + +const sourceDataset = [ +{ + "商品名称": "可乐", + "region": "south", + "销售额": 2350 + }, + { + "商品名称": "可乐", + "region": "east", + "销售额": 1027 + }, + { + "商品名称": "可乐", + "region": "west", + "销售额": 1027 + }, + { + "商品名称": "可乐", + "region": "north", + "销售额": 1027 + }, + { + "商品名称": "雪碧", + "region": "south", + "销售额": 215 + }, + { + "商品名称": "雪碧", + "region": "east", + "销售额": 654 + }, + { + "商品名称": "雪碧", + "region": "west", + "销售额": 159 + }, + { + "商品名称": "雪碧", + "region": "north", + "销售额": 28 + }, + { + "商品名称": "芬达", + "region": "south", + "销售额": 345 + }, + { + "商品名称": "芬达", + "region": "east", + "销售额": 654 + }, + { + "商品名称": "芬达", + "region": "west", + "销售额": 2100 + }, + { + "商品名称": "芬达", + "region": "north", + "销售额": 1679 + }, + { + "商品名称": "醒目", + "region": "south", + "销售额": 1476 + }, + { + "商品名称": "醒目", + "region": "east", + "销售额": 830 + }, + { + "商品名称": "醒目", + "region": "west", + "销售额": 532 + }, + { + "商品名称": "醒目", + "region": "north", + "销售额": 498 + } +] + +const sourceFieldInfo = [ + { + "fieldName": "商品名称", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "region", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "销售额", + "type": "int", + "role": "measure" + } +] + +``` + +假设我们想要展示北方区域销售额排名前三的商品,我们可以这样做: + +```ts +const describe = `帮我展示north区域排名前三的商品销售额` +const vmind = new VMind(options) + +// 调用dataQuery方法,传入describe,sourceFieldInfo和sourceDataset,执行数据聚合 +const { fieldInfo, dataset } = vmind.dataQuery(describe, sourceFieldInfo, sourceDataset); +``` + +在dataQuery方法执行过程中,会生成如下的SQL语句: + +```SQL +SELECT `商品名称`, SUM(`销售额`) AS total_sales FROM dataSource WHERE region = 'north' GROUP BY `商品名称` ORDER BY total_sales DESC LIMIT 3 +``` + +这个SQL语句将筛选出区域(region)为'north'的数据,然后按照"商品名称"进行分组,并计算每个商品的总销售额,最后按照销售额从高到低排序,并只取销售额最高的前三个商品。 + + +最后,执行图表生成操作,我们就可以得到如下的图表: + + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_order.png) + + + + + diff --git a/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md b/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md index 0a3a057e..a7091c6d 100644 --- a/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md +++ b/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md @@ -163,6 +163,10 @@ const vmind = new VMind(options) const { fieldInfo, dataset } = vmind.parseCSVData(csv); ``` + +关于VMind实例的创建以及options中的详细配置,可以参见[创建VMind实例](./Create_VMind_Instance.md) + + 在这个例子中,该函数返回的dataset与上一章的商品销售数据集dataset相同,返回的fieldInfo如下: ```json [ @@ -215,4 +219,8 @@ const describe=`展示各商品在不同区域销售额` const vmind = new VMind(options) const { fieldInfo, dataset } = vmind.parseCSVData(parseCSVDataWithLLM, describe); ``` + +关于VMind实例的创建以及options中的详细配置,可以参见[创建VMind实例](./Create_VMind_Instance.md) + + 在这个例子中,返回的dataset和fieldInfo均与上一章的商品销售数据集dataset相同。 diff --git a/readme-zh.md b/readme-zh.md index 7ad87ca0..c89648b5 100644 --- a/readme-zh.md +++ b/readme-zh.md @@ -138,7 +138,7 @@ const { fieldInfo, dataset } = await vmind.parseCSVDataWithLLM(csv, userInput); ```typescript const describe = 'show me the changes in sales rankings of various car brand'; //调用图表生成接口,获得 spec 和图表动画时长 -const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +const { spec, time } = await vmind.generateChart(describe, fieldInfo, dataset); ``` 这样我们就得到了对应动态图表的 VChart spec。我们可以基于该 spec 渲染图表: @@ -164,7 +164,7 @@ vchart.renderAsync(); //describe使用中英文均可 //指定生成科技感风格的图表 const describe = 'show me the changes in sales rankings of various car brand,tech style'; -const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +const { spec, time } = await vmind.generateChart(describe, fieldInfo, dataset); ``` 也可以指定 VMind 支持的图表类型,字段映射等等。比如: @@ -173,7 +173,7 @@ const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); //指定生成折线图,汽车厂商做 x 轴 const describe = 'show me the changes in sales rankings of various car brands,tech style.Using a line chart, Manufacturer makes the x-axis'; -const { spec, time } = await(vmind.generateChart(csvData, describe)); +const { spec, time } = await(vmind.generateChart(csvData, describe, dataset)); ``` #### 自定义大模型调用方式 @@ -196,6 +196,33 @@ const vmind = new VMind(openAIKey:string, params:{ 在 url 中指定您的大模型服务 url(默认为https://api.openai.com/v1/chat/completions) 在随后的调用中,VMind 会使用 params 中的参数请求大模型服务 url +#### 数据聚合 +📢 Note: 数据聚合功能只支持GPT系列模型,更多模型正在接入中。 + +在使用图表库绘制柱状图、折线图等图表时,若传入的数据不是聚合后的数据,会影响可视化效果。同时由于没有对字段进行筛选和排序,某些图表展示意图无法满足,例如:帮我展示使用量最多的10个部门,帮我展示北方各商品的销售额等。 + +VMind 1.2.2版本开始支持智能数据聚合功能。该功能会将用户传入的数据作为一张数据表,使用大模型根据用户的指令生成SQL查询,从数据表中查询数据,并通过GROUP BY和SQL聚合函数对数据进行分组聚合、排序、筛选。目前支持的SQL语句:SELECT, GROUP BY, WHERE, HAVING, ORDER BY, LIMIT。目前支持的聚合函数:MAX(), MIN(), SUM(), COUNT(), AVG()。不支持子查询、JOIN、条件语句等复杂的SQL操作。 + + +使用VMind对象的`dataQuery`函数对数据进行聚合。该方法有3个参数: +- userInput:用户输入。使用与generateChart相同的输入即可 +- fieldInfo:数据集字段信息。与generateChart相同,可使用parseCSVData获得,或者由用户自己构建。 +- dataset:数据集。与generateChart相同,可使用parseCSVData获得,或者由用户自己构建。 + + +```typescript +const { fieldInfo, dataset } = await vmind?.dataQuery(userInput, fieldInfo, dataset); +``` + + +该方法返回的fieldInfo和dataset是数据聚合后的字段信息和数据集,可用于后续的图表生成。 +`generateChart`函数默认会在生成图表之前,使用相同的用户输入进行一次数据聚合。可通过传入第四个参数来禁用数据聚合: +```typescript +const userInput = 'show me the changes in sales rankings of various car brand'; +const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset, false); //pass false as the forth parameter to disable data aggregation before generating a chart. +``` + + #### 对话式编辑 开发中,敬请期待 From eb4f0a428c547e07dc472024ed50352c20b2f2ff Mon Sep 17 00:00:00 2001 From: da730 Date: Sun, 4 Feb 2024 23:19:00 +0800 Subject: [PATCH 08/18] feat: add chart generation --- .../Basic_Tutorial/Create_VMind_instance.md | 10 +- .../en/Basic_Tutorial/Data_Aggregation.md | 2 + docs/assets/guide/menu.json | 2 +- .../zh/Basic_Tutorial/Chart_Generation.md | 287 +++++++++++++++++- .../Basic_Tutorial/Create_VMind_Instance.md | 10 +- .../zh/Basic_Tutorial/Data_Aggregation.md | 14 +- docs/assets/guide/zh/Intro_to_VMind.md | 2 +- packages/vmind/docs/getting-started.md | 6 +- .../src/gpt/chart-generation/NLToChart.ts | 3 + 9 files changed, 314 insertions(+), 22 deletions(-) diff --git a/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md b/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md index c0c7f18f..ad2db0aa 100644 --- a/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md +++ b/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md @@ -20,9 +20,9 @@ export interface ILLMOptions { temperature?: number; showThoughts?: boolean; customRequestFunc?: { - chartAdvisor: requestFunc; - dataProcess: requestFunc; - dataQuery: requestFunc; + chartAdvisor: requestFunc; + dataProcess: requestFunc; + dataQuery: requestFunc; }; [key: string]: any; } @@ -37,8 +37,8 @@ import VMind, { Model } from '@visactor/vmind' const vmind = new VMind({ model: Model.GPT3_5, //use gpt-3.5-turbo model headers: { //specify the header when calling the LLM service - Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY -} + Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY + } }) ``` In the following sections, we will explain the parameters in ILLMOptions in detail. diff --git a/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md b/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md index 8a478d43..6f6017ea 100644 --- a/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md +++ b/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md @@ -231,6 +231,8 @@ The returned fieldInfo is as follows: With this information, we can directly use fieldInfo and dataset to generate charts. You can find the specific operation steps in the [Intelligent Chart Generation](./Chart_Generation.md) section. +📢 **Attention: The dataQuery method will pass the userPrompt and fieldInfo to the large model to generate SQL, and the detailed data in the dataset will not be passed.** + Finally, we will get the following bar chart: diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index 67ef4f84..0d486c40 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -74,7 +74,7 @@ } }, { - "path": "Animate", + "path": "Chart_Generation", "title": { "zh": "图表智能生成", "en": "Intelligent Chart Generation" diff --git a/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md b/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md index 72eac95e..5b121806 100644 --- a/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md +++ b/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md @@ -1,2 +1,287 @@ # 图表生成 -本教程将介绍VMind中的图表智能生成函数,并提供一些示例 +📢 注意:图表生成功能支持OpenAI GPT-3.5,GPT-4 系列模型和火山引擎[云雀(skylark-pro)](https://www.volcengine.com/product/yunque)系列模型,未来我们将支持更多的大语言模型,欢迎访问[Github页面](https://github.com/VisActor/VMind/issues/new/choose)提出你的需求。 + + +本教程将介绍VMind中的图表智能生成函数,并提供一些使用示例 + +生成图表的途径多种多样,例如可以在PowerBI、Tableau等专业的BI可视化工具中,使用数据集中的字段制作可视化图表;或者直接使用VChart、ECharts、MatPlotlib等图表库,通过代码进行图表绘制。此外,VChart、Echarts等图表库还提供了简单易用的图表编辑器,用户可以上传数据并进行图表制作。 + + +然而传统的图表生成方法,也面临很多难点: + +- 小白用户不会写代码,不具备使用图表库生成图表的能力 +- 图表类型多种多样,用户进行数据展示的目的也各不相同,这就导致了适合展示的图表类型和对应的字段映射也会有所不同。对于非专业用户来说,他们可能无法准确地选择出最适合表达自己观点的图表类型。 +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_chart_generation.png) +- 用户对于图表样式、动画的需求因人而异,常常需要具备一定设计能力才能满足。设计出令人眼前一亮的图表并不容易,它需要设计技能和审美意识,而这些是许多用户所缺乏的。 + + + +这就增加了数据可视化的创作门槛,阻碍了非专业用户创符合自己意图的可视化作品。 + +VMind提供的解决方法是,借助大语言模型的自然语言理解能力和公域知识,根据用户数据和展示意图,推荐合适的图表类型,并将字段映射到合适的视觉通道上,实现图表的智能生成,降低用户进行数据可视化的门槛。 + +## generateChart +VMind中的generateChart函数用于图表智能生成。该函数接收以下几个参数: +- userPrompt: 用户的可视化意图(想用图表展示哪些信息) +- fieldInfo: 数据集中字段的信息,字段名称,类型等 +- dataset: 图表中使用的数据集 +- enableDataQuery: 可选,是否在图表生成过程中开启数据聚合 +- colorPalette: 可选,图表的调色板 +- animationDuration: 可选,图表动画的动画播放持续时间 + +该方法将返回[VChart图表spec](https://www.visactor.io/vchart/guide/tutorial_docs/Basic/A_Basic_Spec)。 + + +📢 **注意:generateChart方法会将userPrompt和fieldInfo传递给大语言模型用于生成图表,dataset中的明细数据并不会被传递。** + + +在生成图表时,VMind首先借助大语言模型,根据userPrompt和fieldInfo,推荐一个合适的图表类型,随后将fieldInfo中的字段映射到图表的x轴、y轴、颜色、尺寸等视觉通道上。 + + +VMind默认给生成的图表添加了入场动画,因此还会返回图表动画时长time。将spec.animation设为false可关闭图表动画。 + + +可以在[VChart动画教程](https://www.visactor.io/vchart/guide/tutorial_docs/Animation/Animation_Types)了解更多图表动画相关信息。 + +下面展示一个使用generateChart进行图表生成的例子: +```ts +import VMind from '@visactor/vmind'; + +const vmind = new VMind(options) +const userPrompt = 'show me the changes in sales rankings of various car brand'; +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); +``` +你可以在[创建VMind实例](./Create_VMind_Instance.md)了解如何创建VMind实例和options中的参数信息,在[数据格式与数据处理](./Data_Process.md)章节中获取更多关于fieldInfo和dataset的相关信息。 + +你可以对spec进行二次加工,改变图表的颜色、样式、动画等配置,也可以直接渲染VChart图表: + +```html + + +
+ +``` +```ts +import VChart from '@visactor/vchart'; + +// Create vchart instance +const vchart = new VChart(spec, { dom: 'chart' }); +// Render Chart +vchart.renderSync(); +``` + +在userPrompt中,你可以描述你想展示的内容,这将作为大语言模型推荐图表类型时的依据;你也可以通过colorPalette传入一个颜色字符串数组,它将被用作图表的颜色主题。 + + +## 参数详解 +### userPrompt +你可以在userPrompt描述你想使用dataset展示什么内容,它将被传递给大语言模型用作图表生成时的参考。、 + +例如,对于下面这个手机品牌销售数据集: +```json +[ + { + "品牌名称": "Apple", + "市场份额": 0.5, + "平均价格": 7068, + "净利润": 314531 + }, + { + "品牌名称": "Samsung", + "市场份额": 0.2, + "平均价格": 6059, + "净利润": 362345 + }, + { + "品牌名称": "Vivo", + "市场份额": 0.05, + "平均价格": 3406, + "净利润": 234512 + }, + { + "品牌名称": "Nokia", + "市场份额": 0.01, + "平均价格": 1064, + "净利润": -1345 + }, + { + "品牌名称": "Xiaomi", + "市场份额": 0.1, + "平均价格": 4087, + "净利润": 131345 + } +] +``` +你可以将userPrompt设置为`展示各品牌市场占有率`调用generateChart,它将为你生成一个饼图: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_pie.png) + + +你也可以展示各品牌的净利润情况,修改userPrompt为:`展示各品牌的净利润`,生成的图表如下: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_column.png) + + +你也可以指定图表类型,修改userPrompt为`展示各品牌的净利润,用折线图`,生成的图表如下: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_line.png) + + +你也可以指定图表视觉通道的映射,例如`使用平均价格做x轴,净利润做y轴,品牌名称用作颜色,市场份额做点的大小,绘制散点图`: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_scatter.png) + + +VMind的强大之处在于,用户无需关心图表生成的细节,仅需一句话描述需求,借助大语言模型所掌握的公域知识,便可以生成想要的图表。 + +例如对于下面这份数据 +```json +时间,男-早餐,女-早餐 +周一,15,22 +周二,12,10 +周三,15,20 +周四,10,12 +周五,13,15 +周六,10,15 +周日,12,14 +``` + +用户输入的展示意图为`展示男女早餐饭量不同`,将会生成一个双轴图: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_dual_axis.png) + + +VMind还支持[动态条形图(ranking bar)](https://www.visactor.io/vchart/demo/storytelling/ranking-bar)这一叙事图表,它使用不断变化的柱状图展示不同时间节点不同种类的数据在排名上的变化。为了生成一个动态条形图,要求数据中必须有一个时间字段。 + +例如,我们有下面的dataset和fieldInfo: +```json +[ + { + "country": "USA", + "continent": "North America", + "GDP": 239270, + "year": 1973 + }, + { + "country": "India", + "continent": "Asia", + "GDP": 22960, + "year": 1973 + }, + { + "country": "South Korea", + "continent": "Asia", + "GDP": 7870, + "year": 1973 + }, + { + "country": "Indonesia", + "continent": "Asia", + "GDP": 10980, + "year": 1973 + }, + { + "country": "Saudi Arabia", + "continent": "Asia", + "GDP": 23760, + "year": 1973 + }, + { + "country": "Thailand", + "continent": "Asia", + "GDP": 4130, + "year": 1973 + }, + { + "country": "Philippines", + "continent": "Asia", + "GDP": 5660, + "year": 1974 + }, + { + "country": "Malaysia", + "continent": "Asia", + "GDP": 2780, + "year": 1974 + }, + { + "country": "United Kingdom", + "continent": "Europe", + "GDP": 114750, + "year": 1974, + } + ...... //完整数据集请见VMind仓库中的packages/vmind/__tests__/browser/src/constants/mockData.ts文件 +] +``` +```json +[ + { + "fieldName": "country", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "continent", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "GDP", + "type": "float", + "role": "measure" + }, + { + "fieldName": "year", + "type": "date", + "role": "measure" + } +] +``` + +若userPrompt为`Show me the change of the GDP rankings of each country`,则将生成一个动态条形图: +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_dynamic_bar.gif) + + +为了使VMind生成符合预期的图表,你必须尽可能清晰地在userPrompt中描述你的展示意图、目的等信息。另外,你还必须确保数据集的字段名称具有一定的语义,或者在fieldInfo中添加字段描述,具体请见[数据格式与数据处理](./Data_Process.md)章节。 + +### enableDataQuery +在[数据聚合](./Data_Aggregation.md)章节中我们提到过,为了支持诸如`帮我展示销售额最多的10个部门`,`帮我展示北方区域各商品的销售额`等图表展示需求,需要对数据进行聚合后再用于图表生成。generateChart函数默认在执行过程中会调用一次dataQuery,使用相同的userPrompt,fieldInfo和dataset对数据进行聚合,使用聚合后的数据完成后续图表生成步骤。 + + +如果你确定你的数据无需进行进一步的聚合、筛选和排序就可以满足用户的图表展示需求,你可以通过将enableDataQuery设置为false来强行关闭这一流程: +```ts +import VMind from '@visactor/vmind'; + +const vmind = new VMind(options) +const userPrompt = 'show me the changes in sales rankings of various car brand'; +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset, false); //将enableDataQuery设置为false,关闭数据聚合 +``` +这样可以减少一次调用大模型的过程,降低token消耗,提高图表生成速度。关于VMind数据聚合的更多信息,请见[数据聚合](./Data_Aggregation.md)章节。 + +## 支持的图表类型 +VMind目前支持VChart中常见的13种图表类型: +- 柱状图 +- 折线图 +- 饼图 +- 散点图 +- 双轴图 +- 词云 +- 玫瑰图 +- 雷达图 +- 箱型图 +- 漏斗图 +- 桑基图 +- 瀑布图 +- [动态条形图(ranking bar)](https://www.visactor.io/vchart/demo/storytelling/ranking-bar) + +根据userPrompt和fieldInfo的不同,这些图表类型都有可能被大语言模型推荐。 + + +你可以在[Github页面](https://github.com/VisActor/VMind/issues/new/choose)提出你对新的图表类型的需求。 + + + + + + + diff --git a/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md b/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md index 8bbe232b..dd31df99 100644 --- a/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md +++ b/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md @@ -19,9 +19,9 @@ export interface ILLMOptions { temperature?: number; showThoughts?: boolean; customRequestFunc?: { - chartAdvisor: requestFunc; - dataProcess: requestFunc; - dataQuery: requestFunc; + chartAdvisor: requestFunc; + dataProcess: requestFunc; + dataQuery: requestFunc; }; [key: string]: any; } @@ -36,8 +36,8 @@ import VMind, { Model } from '@visactor/vmind' const vmind = new VMind({ model: Model.GPT3_5, //使用gpt-3.5-turbo模型 headers: { //指定调用LLM服务时的header - Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY -} + Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY + } }) ``` 在接下来的章节,我们将对ILLMOptions中的参数进行详细的解释。 diff --git a/docs/assets/guide/zh/Basic_Tutorial/Data_Aggregation.md b/docs/assets/guide/zh/Basic_Tutorial/Data_Aggregation.md index d8ddeb0c..4441e563 100644 --- a/docs/assets/guide/zh/Basic_Tutorial/Data_Aggregation.md +++ b/docs/assets/guide/zh/Basic_Tutorial/Data_Aggregation.md @@ -181,11 +181,11 @@ const sourceFieldInfo = [ } ] -const describe=`展示各商品销售额` +const userPrompt=`展示各商品销售额` const vmind = new VMind(options) -//调用dataQuery传入describe,sourceFieldInfo和sourceDataset,执行数据聚合 -const { fieldInfo, dataset } = vmind.dataQuery(describe, sourceFieldInfo, sourceDataset); +//调用dataQuery传入userPrompt,sourceFieldInfo和sourceDataset,执行数据聚合 +const { fieldInfo, dataset } = vmind.dataQuery(userPrompt, sourceFieldInfo, sourceDataset); ``` 在这个例子中,dataQuery函数返回的dataset如下: @@ -230,6 +230,8 @@ const { fieldInfo, dataset } = vmind.dataQuery(describe, sourceFieldInfo, source 有了这些信息,我们就可以直接使用fieldInfo和dataset生成图表了。具体的操作步骤,你可以在[图表智能生成](./Chart_Generation.md)章节中找到。 +📢 **注意:dataQuery方法会将userPrompt和fieldInfo传递给大模型用于生成SQL,dataset中的明细数据并不会被传递。** + 最后,我们将得到如下的柱状图: @@ -358,11 +360,11 @@ const sourceFieldInfo = [ 假设我们想要展示北方区域销售额排名前三的商品,我们可以这样做: ```ts -const describe = `帮我展示north区域排名前三的商品销售额` +const userPrompt = `帮我展示north区域排名前三的商品销售额` const vmind = new VMind(options) -// 调用dataQuery方法,传入describe,sourceFieldInfo和sourceDataset,执行数据聚合 -const { fieldInfo, dataset } = vmind.dataQuery(describe, sourceFieldInfo, sourceDataset); +// 调用dataQuery方法,传入userPrompt,sourceFieldInfo和sourceDataset,执行数据聚合 +const { fieldInfo, dataset } = vmind.dataQuery(userPrompt, sourceFieldInfo, sourceDataset); ``` 在dataQuery方法执行过程中,会生成如下的SQL语句: diff --git a/docs/assets/guide/zh/Intro_to_VMind.md b/docs/assets/guide/zh/Intro_to_VMind.md index 5f6eedb7..99ca24f4 100644 --- a/docs/assets/guide/zh/Intro_to_VMind.md +++ b/docs/assets/guide/zh/Intro_to_VMind.md @@ -15,7 +15,7 @@ VMind是在VChart、VTable等可视化组件库的基础能力之上,构建的 ![VMind架构图](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_structure.png) -在VMind组件中,最底层是由VChart图表库提供的图表渲染、动画、标注能力、VChart文档,以及大模型提供的自然语言理解、代码生成能力。其中,数据处理与交互层负责处理用户输入的数据和自然语言,包括数据聚合模块进行字段解析、数据转换、聚合等操作,交互通信模块负责处理用户与VMind、VMind与大模型之间的通信,包括用户意图识别、Prompt管理,模型通信,结果解析。 +在VMind组件中,最底层是由VChart图表库提供的图表渲染、动画、标注能力、VChart文档,以及大语言模型提供的自然语言理解、代码生成能力。其中,数据处理与交互层负责处理用户输入的数据和自然语言,包括数据聚合模块进行字段解析、数据转换、聚合等操作,交互通信模块负责处理用户与VMind、VMind与大语言模型之间的通信,包括用户意图识别、Prompt管理,模型通信,结果解析。 ## VMind核心能力 diff --git a/packages/vmind/docs/getting-started.md b/packages/vmind/docs/getting-started.md index fd1182aa..77d7ca1d 100644 --- a/packages/vmind/docs/getting-started.md +++ b/packages/vmind/docs/getting-started.md @@ -31,8 +31,8 @@ import VMind from '@visactor/vmind'; ``` ## 初始化VMind实例 -首先我们需要初始化一个VMind实例,并用它完成后续操作。VMind目前仅支持OpenAI GPT-3.5模型,你需要提供[OpenAI API key](https://platform.openai.com/account/api-keys)才能使用。未来我们将支持更多的大模型,并允许用户自定义调用大模型的方法。 -使用以下代码初始化一个VMind实例: +首先我们需要初始化一个VMind实例,并用它完成后续操作。VMind目前仅支持OpenAI GPT-3.5模型,你需要提供[OpenAI API key](https://platform.openai.com/account/api-keys)才能使用。未来我们将支持更多的大语言模型,欢迎访问[Github页面](https://github.com/VisActor/VMind/issues/new/choose)提出你的需求。 + ```js const vmind = new VMind(openAIKey); //传入您的openAI key ``` @@ -145,4 +145,4 @@ const gifSrc = await vmind.exportGIF(spec, time); //传入图表spec和GIF时长 ## 总结 -本章介绍了如何安装并使用VMind进行图表生成,并演示了如何将生成的图表保存为GIF和视频。VMind目前支持柱状图、饼图、折线图、散点图、词云、动态条形图,更多图表类型正在开发中。VMind能够根据用户数据和展示意图,推荐合适的图表类型,并将字段映射到合适的视觉通道上,自动生成符合用户需求的色板,降低用户进行数据可视化的门槛,帮助您轻松完成数据叙事。 \ No newline at end of file +本章介绍了如何安装并使用VMind进行图表生成,并演示了如何将生成的图表保存为GIF和视频。VMind目前支持柱状图、饼图、折线图、散点图、词云、动态条形图,更多图表类型正在开发中。VMind能够根据用户数据和展示意图,推荐合适的图表类型,并将字段映射到合适的视觉通道上,自动生成符合用户需求的色板,降低用户进行数据可视化的门槛,帮助您轻松完成数据叙事。 diff --git a/packages/vmind/src/gpt/chart-generation/NLToChart.ts b/packages/vmind/src/gpt/chart-generation/NLToChart.ts index a50bb841..69251c3b 100644 --- a/packages/vmind/src/gpt/chart-generation/NLToChart.ts +++ b/packages/vmind/src/gpt/chart-generation/NLToChart.ts @@ -24,6 +24,8 @@ export const generateChartWithGPT = async ( let dataset: DataItem[] = propsDataset; let fieldInfo: SimpleFieldInfo[] = propsFieldInfo; let chartSource: string = options.model; + console.log(propsDataset, fieldInfo); + try { if (enableDataQuery) { const { dataset: queryDataset, fieldInfo: fieldInfoNew } = await queryDatasetWithGPT( @@ -52,6 +54,7 @@ export const generateChartWithGPT = async ( chartType = patchResult.chartTypeNew; cell = patchResult.cellNew; } + console.log(dataset); } catch (err) { console.warn(err); console.warn('LLM generation error, use rule generation.'); From e82f725801a56c23273224122f3ed2862d543337 Mon Sep 17 00:00:00 2001 From: da730 Date: Sun, 4 Feb 2024 23:19:56 +0800 Subject: [PATCH 09/18] feat: remove console.log --- packages/vmind/src/gpt/chart-generation/NLToChart.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/vmind/src/gpt/chart-generation/NLToChart.ts b/packages/vmind/src/gpt/chart-generation/NLToChart.ts index 69251c3b..422847ec 100644 --- a/packages/vmind/src/gpt/chart-generation/NLToChart.ts +++ b/packages/vmind/src/gpt/chart-generation/NLToChart.ts @@ -24,7 +24,6 @@ export const generateChartWithGPT = async ( let dataset: DataItem[] = propsDataset; let fieldInfo: SimpleFieldInfo[] = propsFieldInfo; let chartSource: string = options.model; - console.log(propsDataset, fieldInfo); try { if (enableDataQuery) { @@ -54,7 +53,6 @@ export const generateChartWithGPT = async ( chartType = patchResult.chartTypeNew; cell = patchResult.cellNew; } - console.log(dataset); } catch (err) { console.warn(err); console.warn('LLM generation error, use rule generation.'); From c7c2d7d3734fc267af1bd490553bacec479c8a01 Mon Sep 17 00:00:00 2001 From: da730 Date: Mon, 5 Feb 2024 11:53:29 +0800 Subject: [PATCH 10/18] feat: add chart generation docs --- .../en/Basic_Tutorial/Chart_Generation.md | 272 ++++++++++++++++++ .../zh/Basic_Tutorial/Chart_Generation.md | 100 +++---- 2 files changed, 316 insertions(+), 56 deletions(-) create mode 100644 docs/assets/guide/en/Basic_Tutorial/Chart_Generation.md diff --git a/docs/assets/guide/en/Basic_Tutorial/Chart_Generation.md b/docs/assets/guide/en/Basic_Tutorial/Chart_Generation.md new file mode 100644 index 00000000..ba84fbbb --- /dev/null +++ b/docs/assets/guide/en/Basic_Tutorial/Chart_Generation.md @@ -0,0 +1,272 @@ +# Chart Generation +📢 Note: The chart generation feature currently supports OpenAI GPT-3.5, GPT-4 series models, and Volcano Engine [Skylark-pro](https://www.volcengine.com/product/yunque) series models. We will continue to expand the range of supported models. If you have any requirements, feel free to propose them on our [Github page](https://github.com/VisActor/VMind/issues/new/choose). + +This tutorial will provide you with a detailed introduction to the intelligent chart generation feature in VMind and provide some examples. + +There are many ways to generate charts, such as using professional BI visualization tools like PowerBI, Tableau, etc., to create visual charts using the fields of datasets; or you can directly use chart libraries like VChart, ECharts, MatPlotlib, etc., to draw charts by writing code. In addition, chart libraries like VChart, Echarts also provide simple and easy-to-use chart editors, where users can upload data and create charts. + +However, traditional chart generation methods also have some problems: + +- For programming beginners, they may not know how to write code, so they cannot use chart libraries to generate charts. +- There are many types of charts, and the purpose of users' data display varies, which leads to different suitable chart types and corresponding field mappings. For non-professional users, they may not be able to accurately choose the chart type that best expresses their views. +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_chart_generation.png) +- Users have different requirements for chart styles and animations, which often require certain design capabilities to meet. Designing a stunning chart is not easy, it requires design skills and aesthetic sense, which many users lack. + +These problems increase the threshold of data visualization creation and hinder non-professional users from creating visual works that meet their intentions. + +VMind's solution is to use the natural language understanding ability and public domain knowledge of large language models, recommend suitable chart types according to the user's data and display intentions, and map the fields to the appropriate visual channels to achieve intelligent chart generation, thereby reducing the threshold for users to perform data visualization. + + +## generateChart +VMind's generateChart function is a powerful tool that can help you intelligently generate charts. This function requires the following parameters: +- userPrompt: User's visualization intention (what information you want to display with the chart) +- fieldInfo: Information about the fields in the dataset, including field names, types, etc. +- dataset: The dataset used for the chart +- enableDataQuery: Optional parameter, decide whether to enable data aggregation during chart generation +- colorPalette: Optional parameter, used to set the chart's color palette +- animationDuration: Optional parameter, used to set the duration of the chart animation + +This method will return a [VChart chart spec](https://www.visactor.io/vchart/guide/tutorial_docs/Basic/A_Basic_Spec). + +📢 **Please note: The generateChart method will pass userPrompt and fieldInfo to the large language model for chart generation, but the detailed data in the dataset will not be passed.** + +In the process of generating the chart, VMind will first use the large language model, recommend a suitable chart type based on userPrompt and fieldInfo. Then, it will map the fields in fieldInfo to the visual channels of the chart, such as the x-axis, y-axis, color, size, etc. + +VMind will add an entrance animation to the generated chart by default, so it will also return the duration of the chart animation time. If you don't want the chart animation, you can set spec.animation to false. + +You can learn more about chart animations in the [VChart animation tutorial](https://www.visactor.io/vchart/guide/tutorial_docs/Animation/Animation_Types). + +Here is an example of using generateChart to generate a chart: +```ts +import VMind from '@visactor/vmind'; + +const vmind = new VMind(options) +const userPrompt = 'show me the changes in sales rankings of various car brand'; +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); +``` +You can learn how to create a VMind instance and the information of the parameters in options in [Creating a VMind Instance](./Create_VMind_Instance.md), and get more information about fieldInfo and dataset in the [Data Format and Data Processing](./Data_Process.md) section. + +You can reprocess the spec to change the color, style, animation, etc. of the chart, or you can directly render the VChart chart: + +```html + + +
+ +``` +```ts +import VChart from '@visactor/vchart'; + +// Create vchart instance +const vchart = new VChart(spec, { dom: 'chart' }); +// Render Chart +vchart.renderSync(); +``` + +In userPrompt, you can describe what you want to show, which will be used as the basis for the large language model to recommend chart types; you can also pass in a color string array through colorPalette, which will be used as the color theme of the chart. + + +## Parameter Explanation +### userPrompt +The `userPrompt` parameter is used to describe the content you want to display with the dataset. This description will be passed to the large language model as a reference when generating the chart. + +For example, suppose we have a mobile phone brand sales dataset, as shown below: +```json +[ + { + "Brand Name": "Apple", + "Market Share": 0.5, + "Average Price": 7068, + "Net Profit": 314531 + }, + { + "Brand Name": "Samsung", + "Market Share": 0.2, + "Average Price": 6059, + "Net Profit": 362345 + }, + { + "Brand Name": "Vivo", + "Market Share": 0.05, + "Average Price": 3406, + "Net Profit": 234512 + }, + { + "Brand Name": "Nokia", + "Market Share": 0.01, + "Average Price": 1064, + "Net Profit": -1345 + }, + { + "Brand Name": "Xiaomi", + "Market Share": 0.1, + "Average Price": 4087, + "Net Profit": 131345 + } +] +``` +You can set `userPrompt` to `Show the market share of each brand`, and then call the `generateChart` method, which will generate a pie chart: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_pie.png) + + +You can also set `userPrompt` to `Show the net profit of each brand`, and the generated chart will show the net profit of each brand: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_column.png) + + +You can even specify the chart type, such as setting `userPrompt` to `Show the net profit of each brand, with a line chart`, and the generated chart will be a line chart: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_line.png) + + +You can even specify the mapping of the chart's visual channels, such as setting `userPrompt` to `Use the average price as the x-axis, net profit as the y-axis, brand name as the color, market share as the size of the point, and draw a scatter plot`: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_scatter.png) + + +The power of VMind is that you can generate the chart you want by simply describing your needs in a sentence, without worrying about the details of chart generation. This is thanks to the public knowledge mastered by the large language model. + +For example, for the following csv data: +```json +Time,Male-Breakfast,Female-Breakfast +Monday,15,22 +Tuesday,12,10 +Wednesday,15,20 +Thursday,10,12 +Friday,13,15 +Saturday,10,15 +Sunday,12,14 +``` + +If your display intention is `Show the difference in breakfast quantity between men and women`, then a dual-axis chart will be generated: + +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_dual_axis.png) + + +VMind also supports [dynamic bar charts (ranking bar)](https://www.visactor.io/vchart/demo/storytelling/ranking-bar), which is a narrative chart that shows the changes in the rankings of different types of data at different time points through constantly changing bar charts. To generate a dynamic bar chart, there must be a time field in the data. + +For example, we have the following dataset and field information: +```json +[ +{ +"country": "USA", +"continent": "North America", +"GDP": 239270, +"year": 1973 +}, +{ +"country": "India", +"continent": "Asia", +"GDP": 22960, +"year": 1973 +}, +{ +"country": "South Korea", +"continent": "Asia", +"GDP": 7870, +"year": 1973 +}, +{ +"country": "Indonesia", +"continent": "Asia", +"GDP": 10980, +"year": 1973 +}, +{ +"country": "Saudi Arabia", +"continent": "Asia", +"GDP": 23760, +"year": 1973 +}, +{ +"country": "Thailand", +"continent": "Asia", +"GDP": 4130, +"year": 1973 +}, +{ +"country": "Philippines", +"continent": "Asia", +"GDP": 5660, +"year": 1974 +}, +{ +"country": "Malaysia", +"continent": "Asia", +"GDP": 2780, +"year": 1974 +}, +{ +"country": "United Kingdom", +"continent": "Europe", +"GDP": 114750, +"year": 1974, +} +...... //For the complete dataset, please see the packages/vmind/__tests__/browser/src/constants/mockData.ts file in the VMind repository +] +``` +```json +[ + { + "fieldName": "country", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "continent", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "GDP", + "type": "float", + "role": "measure" + }, + { + "fieldName": "year", + "type": "date", + "role": "measure" + } +] +``` + +If `userPrompt` is `Show me the change of the GDP rankings of each country`, then a dynamic bar chart will be generated: +![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_dynamic_bar.gif) + + +To make VMind generate a chart that meets your expectations, you need to describe your display intention and purpose as clearly as possible in `userPrompt`. In addition, you need to ensure that the field names in the dataset have certain semantics, or add field descriptions in the field information, please refer to the [Data Format and Data Processing](./Data_Process.md) chapter for details. + + +### enableDataQuery +In the [Data Aggregation](./Data_Aggregation.md) chapter, we have introduced that in order to meet the chart display requirements such as `showing the top 10 departments with the most sales` or `showing the sales of various products in the northern region`, we need to aggregate the data first, and then generate the chart. By default, the `generateChart` function will call `dataQuery` once during execution, using the same `userPrompt`, `fieldInfo` and `dataset` to aggregate the data, and then complete the subsequent chart generation steps with the aggregated data. + +However, if you are sure that your data can meet the user's chart display requirements without further aggregation, filtering and sorting, you can turn off this process by setting `enableDataQuery` to `false`: +```ts +import VMind from '@visactor/vmind'; + +const vmind = new VMind(options) +const userPrompt = 'show me the changes in sales rankings of various car brand'; +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset, false); // Set enableDataQuery to false to turn off data aggregation +``` +This can reduce the process of calling the large model once, reduce token consumption, and improve chart generation speed. For more information about VMind data aggregation, please refer to the [Data Aggregation](./Data_Aggregation.md) chapter. + +## Chart Types Supported by VMind +VMind currently supports 13 common chart types in VChart: +- Bar chart +- Line chart +- Pie chart +- Scatter plot +- Dual-axis chart +- Word cloud +- Rose chart +- Radar chart +- Box plot +- Funnel chart +- Sankey diagram +- Waterfall chart +- [Dynamic bar chart (ranking bar)](https://www.visactor.io/vchart/demo/storytelling/ranking-bar) + +Depending on the `userPrompt` and `fieldInfo`, these chart types may all be recommended by the large language model. + +If you have new chart type requirements, feel free to propose them on our [Github page](https://github.com/VisActor/VMind/issues/new/choose). diff --git a/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md b/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md index 5b121806..fde1715d 100644 --- a/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md +++ b/docs/assets/guide/zh/Basic_Tutorial/Chart_Generation.md @@ -1,49 +1,42 @@ # 图表生成 -📢 注意:图表生成功能支持OpenAI GPT-3.5,GPT-4 系列模型和火山引擎[云雀(skylark-pro)](https://www.volcengine.com/product/yunque)系列模型,未来我们将支持更多的大语言模型,欢迎访问[Github页面](https://github.com/VisActor/VMind/issues/new/choose)提出你的需求。 +📢 提示:图表生成功能目前支持OpenAI GPT-3.5,GPT-4 系列模型和火山引擎[云雀(skylark-pro)](https://www.volcengine.com/product/yunque)系列模型。我们将不断扩大支持的模型范围,如果你有任何需求,欢迎在我们的[Github页面](https://github.com/VisActor/VMind/issues/new/choose)提出。 +本教程将向你详细介绍VMind中的图表智能生成功能,并提供一些示例。 -本教程将介绍VMind中的图表智能生成函数,并提供一些使用示例 +生成图表的方式有很多,比如你可以在PowerBI、Tableau等专业的BI可视化工具中,利用数据集的字段来制作可视化图表;或者你也可以直接使用VChart、ECharts、MatPlotlib等图表库,通过编写代码来绘制图表。此外,VChart、Echarts等图表库还提供了简单易用的图表编辑器,用户可以上传数据并进行图表制作。 -生成图表的途径多种多样,例如可以在PowerBI、Tableau等专业的BI可视化工具中,使用数据集中的字段制作可视化图表;或者直接使用VChart、ECharts、MatPlotlib等图表库,通过代码进行图表绘制。此外,VChart、Echarts等图表库还提供了简单易用的图表编辑器,用户可以上传数据并进行图表制作。 +然而,传统的图表生成方式也存在一些问题: - -然而传统的图表生成方法,也面临很多难点: - -- 小白用户不会写代码,不具备使用图表库生成图表的能力 -- 图表类型多种多样,用户进行数据展示的目的也各不相同,这就导致了适合展示的图表类型和对应的字段映射也会有所不同。对于非专业用户来说,他们可能无法准确地选择出最适合表达自己观点的图表类型。 +- 对于编程新手来说,他们可能不会编写代码,也就无法使用图表库来生成图表。 +- 图表类型繁多,用户展示数据的目的各不相同,这就导致了适合展示的图表类型和对应的字段映射也会有所不同。对于非专业用户来说,他们可能无法准确地选择出最能表达自己观点的图表类型。 ![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_chart_generation.png) -- 用户对于图表样式、动画的需求因人而异,常常需要具备一定设计能力才能满足。设计出令人眼前一亮的图表并不容易,它需要设计技能和审美意识,而这些是许多用户所缺乏的。 +- 用户对于图表样式、动画的需求各不相同,往往需要一定的设计能力才能满足。设计出令人眼前一亮的图表并不容易,它需要设计技能和审美意识,而这些是许多用户所缺乏的。 +这些问题增加了数据可视化的创作门槛,阻碍了非专业用户创作符合自己意图的可视化作品。 +VMind的解决方案是,利用大语言模型的自然语言理解能力和公域知识,根据用户的数据和展示意图,推荐合适的图表类型,并将字段映射到合适的视觉通道上,实现图表的智能生成,从而降低用户进行数据可视化的门槛。 -这就增加了数据可视化的创作门槛,阻碍了非专业用户创符合自己意图的可视化作品。 - -VMind提供的解决方法是,借助大语言模型的自然语言理解能力和公域知识,根据用户数据和展示意图,推荐合适的图表类型,并将字段映射到合适的视觉通道上,实现图表的智能生成,降低用户进行数据可视化的门槛。 ## generateChart -VMind中的generateChart函数用于图表智能生成。该函数接收以下几个参数: -- userPrompt: 用户的可视化意图(想用图表展示哪些信息) -- fieldInfo: 数据集中字段的信息,字段名称,类型等 -- dataset: 图表中使用的数据集 -- enableDataQuery: 可选,是否在图表生成过程中开启数据聚合 -- colorPalette: 可选,图表的调色板 -- animationDuration: 可选,图表动画的动画播放持续时间 - -该方法将返回[VChart图表spec](https://www.visactor.io/vchart/guide/tutorial_docs/Basic/A_Basic_Spec)。 +VMind的generateChart函数是一个强大的工具,它可以帮助你智能生成图表。这个函数需要以下几个参数: +- userPrompt: 用户的可视化意图(你想用图表展示什么信息) +- fieldInfo: 数据集中字段的信息,包括字段名称,类型等 +- dataset: 用于图表的数据集 +- enableDataQuery: 可选参数,决定是否在图表生成过程中开启数据聚合 +- colorPalette: 可选参数,用于设置图表的调色板 +- animationDuration: 可选参数,用于设置图表动画的播放持续时间 +这个方法会返回一个[VChart图表spec](https://www.visactor.io/vchart/guide/tutorial_docs/Basic/A_Basic_Spec)。 -📢 **注意:generateChart方法会将userPrompt和fieldInfo传递给大语言模型用于生成图表,dataset中的明细数据并不会被传递。** +📢 **请注意:generateChart方法会将userPrompt和fieldInfo传递给大语言模型用于生成图表,但是dataset中的详细数据并不会被传递。** +在生成图表的过程中,VMind首先会利用大语言模型,根据userPrompt和fieldInfo,推荐一个适合的图表类型。然后,它会将fieldInfo中的字段映射到图表的x轴、y轴、颜色、尺寸等视觉通道上。 -在生成图表时,VMind首先借助大语言模型,根据userPrompt和fieldInfo,推荐一个合适的图表类型,随后将fieldInfo中的字段映射到图表的x轴、y轴、颜色、尺寸等视觉通道上。 +VMind默认会为生成的图表添加入场动画,因此它还会返回图表动画的时长time。如果你不想要图表动画,可以将spec.animation设为false。 +你可以在[VChart动画教程](https://www.visactor.io/vchart/guide/tutorial_docs/Animation/Animation_Types)中了解更多关于图表动画的信息。 -VMind默认给生成的图表添加了入场动画,因此还会返回图表动画时长time。将spec.animation设为false可关闭图表动画。 - - -可以在[VChart动画教程](https://www.visactor.io/vchart/guide/tutorial_docs/Animation/Animation_Types)了解更多图表动画相关信息。 - -下面展示一个使用generateChart进行图表生成的例子: +下面是一个使用generateChart生成图表的例子: ```ts import VMind from '@visactor/vmind'; @@ -51,7 +44,7 @@ const vmind = new VMind(options) const userPrompt = 'show me the changes in sales rankings of various car brand'; const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` -你可以在[创建VMind实例](./Create_VMind_Instance.md)了解如何创建VMind实例和options中的参数信息,在[数据格式与数据处理](./Data_Process.md)章节中获取更多关于fieldInfo和dataset的相关信息。 +你可以在[创建VMind实例](./Create_VMind_Instance.md)中了解如何创建VMind实例和options中的参数信息,在[数据格式与数据处理](./Data_Process.md)章节中获取更多关于fieldInfo和dataset的相关信息。 你可以对spec进行二次加工,改变图表的颜色、样式、动画等配置,也可以直接渲染VChart图表: @@ -73,11 +66,12 @@ vchart.renderSync(); 在userPrompt中,你可以描述你想展示的内容,这将作为大语言模型推荐图表类型时的依据;你也可以通过colorPalette传入一个颜色字符串数组,它将被用作图表的颜色主题。 + ## 参数详解 ### userPrompt -你可以在userPrompt描述你想使用dataset展示什么内容,它将被传递给大语言模型用作图表生成时的参考。、 +`userPrompt`参数是你用来描述你想要用数据集展示的内容,这个描述会被传递给大语言模型,作为生成图表时的参考依据。 -例如,对于下面这个手机品牌销售数据集: +举个例子,假设我们有一个手机品牌销售数据集,如下所示: ```json [ { @@ -112,29 +106,29 @@ vchart.renderSync(); } ] ``` -你可以将userPrompt设置为`展示各品牌市场占有率`调用generateChart,它将为你生成一个饼图: +你可以将`userPrompt`设置为`展示各品牌市场占有率`,然后调用`generateChart`方法,这样就会生成一个饼图: ![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_pie.png) -你也可以展示各品牌的净利润情况,修改userPrompt为:`展示各品牌的净利润`,生成的图表如下: +你也可以设置`userPrompt`为`展示各品牌的净利润`,这样生成的图表就会展示各品牌的净利润情况: ![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_column.png) -你也可以指定图表类型,修改userPrompt为`展示各品牌的净利润,用折线图`,生成的图表如下: +你还可以指定图表类型,比如设置`userPrompt`为`展示各品牌的净利润,用折线图`,这样生成的图表就会是一个折线图: ![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_line.png) -你也可以指定图表视觉通道的映射,例如`使用平均价格做x轴,净利润做y轴,品牌名称用作颜色,市场份额做点的大小,绘制散点图`: +你甚至可以指定图表视觉通道的映射,例如设置`userPrompt`为`使用平均价格做x轴,净利润做y轴,品牌名称用作颜色,市场份额做点的大小,绘制散点图`: ![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_scatter.png) -VMind的强大之处在于,用户无需关心图表生成的细节,仅需一句话描述需求,借助大语言模型所掌握的公域知识,便可以生成想要的图表。 +VMind的强大之处在于,你只需要用一句话描述你的需求,就可以生成你想要的图表,而无需关心图表生成的细节。这得益于大语言模型所掌握的公域知识。 -例如对于下面这份数据 +例如,对于下面这份csv数据: ```json 时间,男-早餐,女-早餐 周一,15,22 @@ -146,14 +140,14 @@ VMind的强大之处在于,用户无需关心图表生成的细节,仅需一 周日,12,14 ``` -用户输入的展示意图为`展示男女早餐饭量不同`,将会生成一个双轴图: +如果你输入的展示意图为`展示男女早餐饭量不同`,那么就会生成一个双轴图: ![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_dual_axis.png) -VMind还支持[动态条形图(ranking bar)](https://www.visactor.io/vchart/demo/storytelling/ranking-bar)这一叙事图表,它使用不断变化的柱状图展示不同时间节点不同种类的数据在排名上的变化。为了生成一个动态条形图,要求数据中必须有一个时间字段。 +VMind还支持[动态条形图(ranking bar)](https://www.visactor.io/vchart/demo/storytelling/ranking-bar),这是一种叙事图表,它通过不断变化的柱状图展示不同时间节点不同种类的数据在排名上的变化。为了生成一个动态条形图,数据中必须有一个时间字段。 -例如,我们有下面的dataset和fieldInfo: +例如,我们有下面的数据集和字段信息: ```json [ { @@ -238,17 +232,17 @@ VMind还支持[动态条形图(ranking bar)](https://www.visactor.io/vchart/ ] ``` -若userPrompt为`Show me the change of the GDP rankings of each country`,则将生成一个动态条形图: +如果`userPrompt`为`Show me the change of the GDP rankings of each country`,那么就会生成一个动态条形图: ![](https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/vmind/tutorials/VMind_dynamic_bar.gif) -为了使VMind生成符合预期的图表,你必须尽可能清晰地在userPrompt中描述你的展示意图、目的等信息。另外,你还必须确保数据集的字段名称具有一定的语义,或者在fieldInfo中添加字段描述,具体请见[数据格式与数据处理](./Data_Process.md)章节。 +为了让VMind生成符合预期的图表,你需要在`userPrompt`中尽可能清晰地描述你的展示意图和目的。此外,你还需要确保数据集的字段名称具有一定的语义,或者在字段信息中添加字段描述,具体请参见[数据格式与数据处理](./Data_Process.md)章节。 -### enableDataQuery -在[数据聚合](./Data_Aggregation.md)章节中我们提到过,为了支持诸如`帮我展示销售额最多的10个部门`,`帮我展示北方区域各商品的销售额`等图表展示需求,需要对数据进行聚合后再用于图表生成。generateChart函数默认在执行过程中会调用一次dataQuery,使用相同的userPrompt,fieldInfo和dataset对数据进行聚合,使用聚合后的数据完成后续图表生成步骤。 +### enableDataQuery +在[数据聚合](./Data_Aggregation.md)章节中,我们已经介绍过,为了满足`展示销售额最多的10个部门`或`展示北方区域各商品的销售额`等图表展示需求,我们需要先对数据进行聚合,然后再生成图表。在默认情况下,`generateChart`函数会在执行过程中调用一次`dataQuery`,使用相同的`userPrompt`,`fieldInfo`和`dataset`对数据进行聚合,然后使用聚合后的数据完成后续的图表生成步骤。 -如果你确定你的数据无需进行进一步的聚合、筛选和排序就可以满足用户的图表展示需求,你可以通过将enableDataQuery设置为false来强行关闭这一流程: +然而,如果你确定你的数据无需进行进一步的聚合、筛选和排序就可以满足用户的图表展示需求,你可以通过将`enableDataQuery`设置为`false`来关闭这一流程: ```ts import VMind from '@visactor/vmind'; @@ -256,9 +250,9 @@ const vmind = new VMind(options) const userPrompt = 'show me the changes in sales rankings of various car brand'; const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset, false); //将enableDataQuery设置为false,关闭数据聚合 ``` -这样可以减少一次调用大模型的过程,降低token消耗,提高图表生成速度。关于VMind数据聚合的更多信息,请见[数据聚合](./Data_Aggregation.md)章节。 +这样做可以减少一次调用大模型的过程,降低token消耗,提高图表生成速度。关于VMind数据聚合的更多信息,请参考[数据聚合](./Data_Aggregation.md)章节。 -## 支持的图表类型 +## VMind支持的图表类型 VMind目前支持VChart中常见的13种图表类型: - 柱状图 - 折线图 @@ -274,14 +268,8 @@ VMind目前支持VChart中常见的13种图表类型: - 瀑布图 - [动态条形图(ranking bar)](https://www.visactor.io/vchart/demo/storytelling/ranking-bar) -根据userPrompt和fieldInfo的不同,这些图表类型都有可能被大语言模型推荐。 - - -你可以在[Github页面](https://github.com/VisActor/VMind/issues/new/choose)提出你对新的图表类型的需求。 - - - - +根据`userPrompt`和`fieldInfo`的不同,这些图表类型都有可能被大语言模型推荐。 +如果你有新的图表类型需求,欢迎在我们的[Github页面](https://github.com/VisActor/VMind/issues/new/choose)提出。 From d3320c4549341b1a2bd47336eb1174eeaffe4a73 Mon Sep 17 00:00:00 2001 From: da730 Date: Mon, 5 Feb 2024 14:30:51 +0800 Subject: [PATCH 11/18] feat: update node options while build --- .github/workflows/pre-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index e37a6348..59e45d7b 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -53,6 +53,7 @@ jobs: env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} NPM_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + NODE_OPTIONS: '--max_old_space_size=4096' run: node common/scripts/install-run-rush.js publish --publish --include-all --tag ${{ steps.semver_parser.outputs.pre_release_type }} - name: Update shrinkwrap From f92a157b878e855be6ed53d5ae14eefcbf33a802 Mon Sep 17 00:00:00 2001 From: da730 Date: Mon, 5 Feb 2024 18:40:57 +0800 Subject: [PATCH 12/18] feat: add custom request docs --- .../Basic_Tutorial/Create_VMind_instance.md | 16 ++--- .../guide/en/Basic_Tutorial/Custom_Request.md | 67 +++++++++++++++++++ docs/assets/guide/menu.json | 11 +-- .../Basic_Tutorial/Create_VMind_Instance.md | 14 ++-- .../guide/zh/Basic_Tutorial/Custom_Request.md | 66 ++++++++++++++++++ packages/vmind/src/typings/index.ts | 8 +-- 6 files changed, 154 insertions(+), 28 deletions(-) create mode 100644 docs/assets/guide/en/Basic_Tutorial/Custom_Request.md create mode 100644 docs/assets/guide/zh/Basic_Tutorial/Custom_Request.md diff --git a/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md b/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md index ad2db0aa..032ab7d8 100644 --- a/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md +++ b/docs/assets/guide/en/Basic_Tutorial/Create_VMind_instance.md @@ -20,9 +20,9 @@ export interface ILLMOptions { temperature?: number; showThoughts?: boolean; customRequestFunc?: { - chartAdvisor: requestFunc; - dataProcess: requestFunc; - dataQuery: requestFunc; + chartAdvisor: RequestFunc; + dataProcess: RequestFunc; + dataQuery: RequestFunc; }; [key: string]: any; } @@ -89,15 +89,15 @@ In VMind, showThoughts defaults to true. ## Customizing the method of calling the LLM service through customRequestFunc VMind calls the LLM service through the requestGPT method by HTTP request. However, you can customize the method of calling the LLM in each task through the customRequestFunc parameter. For example, you can request your own LLM service in the form of RPC. -This parameter has three requestFunc type values, the complete type definition is as follows: +This parameter has three RequestFunc type values, the complete type definition is as follows: ```ts type customRequestFunc= { - chartAdvisor: requestFunc; - dataProcess: requestFunc; - dataQuery: requestFunc; + chartAdvisor: RequestFunc; + dataProcess: RequestFunc; + dataQuery: RequestFunc; }; -type requestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; +type RequestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; export type LLMResponse = { choices: { diff --git a/docs/assets/guide/en/Basic_Tutorial/Custom_Request.md b/docs/assets/guide/en/Basic_Tutorial/Custom_Request.md new file mode 100644 index 00000000..f1f69cae --- /dev/null +++ b/docs/assets/guide/en/Basic_Tutorial/Custom_Request.md @@ -0,0 +1,67 @@ + +# Customizing Large Language Model (LLM) Invocation Method +In previous chapters, we have mentioned that VMind calls the Large Language Model (LLM) during the processes of [data processing](./Data_Process.md), [data aggregation](./Data_Aggregation.md), and [chart generation](./Chart_Generation.md). By default, we call the LLM via HTTP requests. You can specify the URL of the LLM service and set the header for authentication when [initializing the VMind instance](./Create_VMind_Instance.md). + +However, in some special cases, you may need to customize the way the LLM service is called. For example, you may want to request the service via RPC, or you may want to do some extra processing after the model returns the results, and then return the processed results to VMind. To meet these needs, we provide an option to set the `customRequestFunc` object when initializing the VMind object. You can use this option to customize the way the LLM service is called at different stages. + +The type definition of `customRequestFunc` is as follows: + +```ts +type customRequestFunc= { + chartAdvisor: RequestFunc; // Chart generation stage + dataProcess: RequestFunc; // Data processing stage + dataQuery: RequestFunc; // Data aggregation stage +}; + +type RequestFunc = (prompt: string, userPrompt: string, options: ILLMOptions | undefined) => Promise; + +type LLMResponse = { + choices: { + index: number; + message: any; + }[]; + usage: any; + [key: string]: any; +}; + +``` + +The `customRequestFunc` object has three properties: `chartAdvisor`, `dataProcess`, and `dataQuery`, which correspond to the three functions of chart generation (`vmind.generateChart`), data processing (`vmind.parseCSVDataWithLLM`), and data aggregation (`vmind.dataQuery`) in VMind. Each property is a function of type `RequestFunc`, the parameters of which are the prompt information `prompt`, the user input display intention `userPrompt`, and the `options` object when the model executes the task. When VMind requests the LLM service, it will call your custom function and pass these three parameters. You need to use `prompt` and `userPrompt` to request the LLM service in your custom function and return the model's generated results in the format of `LLMResponse`. The structure of `LLMResponse` is the same as that of the OpenAI completions API (for details, see [The chat completion object](https://platform.openai.com/docs/api-reference/chat/object)). + +Note that the functions in `customRequestFunc` are asynchronous, and VMind will use `await` to wait for the end of the model request. + +Below is an example of using RPC to call the LLM service during the chart generation process: + +```ts +import VMind, { Model } from '@visactor/vmind' + +// Custom a RequestFunc type function +const ChartGenerationRequestFunc = async (prompt: string, userMessage: string, options: ILLMOptions | undefined) => { +// Use prompt, userMessage, and options to call the LLM service via RPC +const resp = await call_RPC_LLM_Service(prompt, userMessage, options) + +const { result } = resp +const content = result.content // Get the results generated by the model +const gptResponse = { + usage: {}, // Token usage information + choices: [{ + index: 0, + message: { + role: 'assistant', + content // Put the results generated by the model into content +} +}] +} +return gptResponse // Return chat completion object, see https://platform.openai.com/docs/api-reference/chat/object +} + +const vmind = new VMind({ + model: Model.GPT3_5, + customRequestFunc: { + chartAdvisor: ChartGenerationRequestFunc // Pass the custom function to chartAdvisor +} +}) + +const { spec } = await vmind.generateChart(userInput, fieldInfo, dataset); // Call generateChart for chart generation + +``` diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index 0d486c40..6c21716d 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -81,18 +81,11 @@ } }, { - "path": "Extensions_and_Plugins", + "path": "Custom_Request", "title": { - "zh": "自定义LLM接入方式", + "zh": "自定义LLM调用", "en": "Custom LLM Access Function" } - }, - { - "path": "Extensions_and_Plugins", - "title": { - "zh": "导出图表视频/GIF", - "en": "Export Chart Video/GIF" - } } ] } diff --git a/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md b/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md index dd31df99..c0e49605 100644 --- a/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md +++ b/docs/assets/guide/zh/Basic_Tutorial/Create_VMind_Instance.md @@ -19,9 +19,9 @@ export interface ILLMOptions { temperature?: number; showThoughts?: boolean; customRequestFunc?: { - chartAdvisor: requestFunc; - dataProcess: requestFunc; - dataQuery: requestFunc; + chartAdvisor: RequestFunc; + dataProcess: RequestFunc; + dataQuery: RequestFunc; }; [key: string]: any; } @@ -91,12 +91,12 @@ VMind通过requestGPT方法,通过HTTP请求进行LLM服务的调用。然而 该参数有三个requestFunc类型的值,完整的类型定义如下: ```ts type customRequestFunc= { - chartAdvisor: requestFunc; - dataProcess: requestFunc; - dataQuery: requestFunc; + chartAdvisor: RequestFunc; + dataProcess: RequestFunc; + dataQuery: RequestFunc; }; -type requestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; +type RequestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; export type LLMResponse = { choices: { diff --git a/docs/assets/guide/zh/Basic_Tutorial/Custom_Request.md b/docs/assets/guide/zh/Basic_Tutorial/Custom_Request.md new file mode 100644 index 00000000..ee64d0eb --- /dev/null +++ b/docs/assets/guide/zh/Basic_Tutorial/Custom_Request.md @@ -0,0 +1,66 @@ +# 自定义大语言模型(LLM)调用方式 +在前面的章节中,我们已经提到,VMind在进行[数据处理](./Data_Process.md)、[数据聚合](./Data_Aggregation.md)和[图表生成](./Chart_Generation.md)的过程中,都会调用大语言模型(LLM)。默认情况下,我们是通过HTTP请求的方式来调用LLM的,你可以在[初始化VMind实例](./Create_VMind_Instance.md)时,通过指定LLM服务的url和设置header来完成鉴权。 + +然而,在某些特殊情况下,你可能需要自定义LLM服务的调用方式。比如,你可能想通过RPC方式来请求服务,或者你可能想在模型返回结果后进行一些额外的处理,然后再将处理后的结果返回给VMind。为了满足这些需求,我们提供了一个在初始化VMind对象时设置`customRequestFunc`对象的选项,你可以通过这个选项来自定义LLM服务在不同阶段的调用方式。 + +`customRequestFunc`的类型定义如下: + +```ts +type customRequestFunc= { +chartAdvisor: RequestFunc; //图表生成阶段 +dataProcess: RequestFunc; //数据处理阶段 +dataQuery: RequestFunc; //数据聚合阶段 +}; + +type RequestFunc = (prompt: string, userPrompt: string, options: ILLMOptions | undefined) => Promise; + +type LLMResponse = { + choices: { + index: number; + message: any; + }[]; + usage: any; + [key: string]: any; +}; + +``` + +`customRequestFunc`对象有三个属性:`chartAdvisor`,`dataProcess`和`dataQuery`,它们分别对应VMind中的图表生成(`vmind.generateChart`),数据处理(`vmind.parseCSVDataWithLLM`)和数据聚合(`vmind.dataQuery`)三个功能。每个属性都是一个`RequestFunc`类型的函数,这个函数的参数分别是模型执行任务时的提示信息`prompt`,用户输入的展示意图`userPrompt`和`options`对象。当VMind在请求LLM服务时,会调用你自定义的函数,并将这三个参数传入。你需要在自定义的函数中使用`prompt`和`userPrompt`来请求LLM服务,并按照`LLMResponse`的格式返回模型的生成结果。`LLMResponse`的结构与OpenAI completions API的结构相同(详情请见[The chat completion object](https://platform.openai.com/docs/api-reference/chat/object))。 + +需要注意的是,`customRequestFunc`中的函数都是异步函数,VMind会使用`await`来等待模型请求的结束。 + +下面是一个在图表生成过程中使用RPC调用LLM服务的示例: + +```ts +import VMind, { Model } from '@visactor/vmind' + +//自定义一个RequestFunc类型的函数 +const ChartGenerationRequestFunc = async (prompt: string, userMessage: string, options: ILLMOptions | undefined) => { + //使用prompt,userMessage和options, 通过RPC调用LLM服务 + const resp = await call_RPC_LLM_Service(prompt, userMessage, options) + + const { result } = resp + const content = result.content //获取模型生成的结果 + const gptResponse = { + usage: {}, //token使用信息 + choices: [{ + index: 0, + message: { + role: 'assistant', + content //将模型的生成结果放入content中 + } + }] + } + return gptResponse //返回chat completion object,见https://platform.openai.com/docs/api-reference/chat/object + } + +const vmind = new VMind({ + model: Model.GPT3_5, + customRequestFunc: { + chartAdvisor: ChartGenerationRequestFunc //将自定义函数传递给chartAdvisor + } +}) + +const { spec } = await vmind.generateChart(userInput, fieldInfo, dataset); //调用generateChart进行图表生成 + +``` diff --git a/packages/vmind/src/typings/index.ts b/packages/vmind/src/typings/index.ts index 35cb0f67..b2a0cfe1 100644 --- a/packages/vmind/src/typings/index.ts +++ b/packages/vmind/src/typings/index.ts @@ -8,14 +8,14 @@ export interface ILLMOptions { temperature?: number; showThoughts?: boolean; customRequestFunc?: { - chartAdvisor: requestFunc; - dataProcess: requestFunc; - dataQuery: requestFunc; + chartAdvisor: RequestFunc; + dataProcess: RequestFunc; + dataQuery: RequestFunc; }; [key: string]: any; } -type requestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; +type RequestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; export type SimpleFieldInfo = { fieldName: string; From 91d85473f9aba536b03bbac59192c0a665dd8f40 Mon Sep 17 00:00:00 2001 From: da730 Date: Mon, 5 Feb 2024 12:30:08 +0800 Subject: [PATCH 13/18] feat: export video and gif --- common/config/rush/pnpm-lock.yaml | 676 ++++++++++----------- packages/vmind/package.json | 5 +- packages/vmind/src/chart-to-video/index.ts | 2 +- packages/vmind/src/core/VMind.ts | 33 +- packages/vmind/src/typings/index.ts | 9 + 5 files changed, 340 insertions(+), 385 deletions(-) diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 25db1326..6d4f4fab 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -12,10 +12,6 @@ importers: '@types/markdown-it': ^13.0.0 '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 - '@visactor/vchart': ^1.9.0 - '@visactor/vgrammar': ~0.5.7 - '@visactor/vrender': ~0.17.19 - '@visactor/vutils': ~0.17.4 '@vitejs/plugin-react': 3.1.0 axios: ^1.4.0 chalk: ^3.0.0 @@ -34,11 +30,7 @@ importers: vite: 3.2.6 yargs: ^17.1.1 dependencies: - '@arco-design/web-react': 2.46.1_p2jlmv6k7k3po6tueteg46f2ku - '@visactor/vchart': 1.9.0 - '@visactor/vgrammar': 0.5.7 - '@visactor/vrender': 0.17.19 - '@visactor/vutils': 0.17.4 + '@arco-design/web-react': 2.46.1_tmih5ryase7m737mtcsxs5l4a4 axios: 1.6.7 highlight.js: 11.9.0 lodash: 4.17.21 @@ -49,7 +41,7 @@ importers: devDependencies: '@types/highlightjs': 9.12.6 '@types/markdown-it': 13.0.7 - '@types/react': 18.2.48 + '@types/react': 18.2.53 '@types/react-dom': 18.2.18 '@vitejs/plugin-react': 3.1.0_vite@3.2.6 chalk: 3.0.0 @@ -83,18 +75,17 @@ importers: '@internal/eslint-config': link:../../share/eslint-config '@internal/ts-config': link:../../share/ts-config '@types/jest': 26.0.24 - '@types/node': 20.11.6 + '@types/node': 20.11.16 jest: 26.6.3_ts-node@10.9.0 npm-run-all: 4.1.5 rimraf: 3.0.2 ts-jest: 26.5.6_xuote2qreek47x2di7kesslrai - ts-node: 10.9.0_vkghqkqmqa7oouldkgme4f7c4i + ts-node: 10.9.0_4lhcgfu2tqlb5z5dwdvf5srjjq typescript: 4.9.5 ../../packages/vmind: specifiers: '@arco-design/web-react': 2.46.1 - '@ffmpeg/core': ^0.11.0 '@ffmpeg/ffmpeg': ^0.11.6 '@internal/bundler': workspace:* '@internal/eslint-config': workspace:* @@ -144,7 +135,7 @@ importers: '@visactor/calculator': link:../calculator '@visactor/chart-advisor': 0.1.10 '@visactor/vdataset': 0.17.4 - '@visactor/vrender-core': 0.17.19 + '@visactor/vrender-core': 0.17.23 '@visactor/vutils': 0.17.4 axios: 1.6.7 dayjs: 1.11.10 @@ -154,8 +145,7 @@ importers: lodash: 4.17.21 node-sql-parser: 4.17.0 devDependencies: - '@arco-design/web-react': 2.46.1_p2jlmv6k7k3po6tueteg46f2ku - '@ffmpeg/core': 0.11.0 + '@arco-design/web-react': 2.46.1_tmih5ryase7m737mtcsxs5l4a4 '@ffmpeg/ffmpeg': 0.11.6 '@internal/bundler': link:../../tools/bundler '@internal/eslint-config': link:../../share/eslint-config @@ -165,12 +155,12 @@ importers: '@types/jest': 26.0.24 '@types/js-yaml': 4.0.9 '@types/lodash': 4.14.182 - '@types/node': 20.11.6 - '@types/react': 18.2.48 + '@types/node': 20.11.16 + '@types/react': 18.2.53 '@types/react-dom': 18.2.18 '@typescript-eslint/eslint-plugin': 5.30.0_cow5zg7tx6c3eisi5a4ud5kwia '@typescript-eslint/parser': 5.30.0_vwud3sodsb5zxmzckoj7rdwdbq - '@visactor/vchart': 1.9.0 + '@visactor/vchart': 1.9.2 '@vitejs/plugin-react': 3.1.0_vite@3.2.6 dotenv: 16.3.2 eslint: 8.18.0 @@ -186,7 +176,7 @@ importers: react-dom: 18.2.0_react@18.2.0 react-router-dom: 6.9.0_biqbaboplfbrettd7655fr4n2y typescript: 4.9.5 - vite: 3.2.6_2spomixywugicrp5ojnu5wf6qy + vite: 3.2.6_jdocevgq4sbitbjausmg7n6jgy vite-plugin-css: 1.0.4 vite-plugin-libcss: 1.1.1_vite@3.2.6 @@ -349,7 +339,7 @@ importers: '@types/merge2': 1.4.0 '@types/minimist': 1.2.2 '@types/ms': 0.7.31 - '@types/node': 20.11.6 + '@types/node': 20.11.16 '@types/semver': 7.3.12 '@types/terser': 3.12.0 '@types/through2': 2.0.38 @@ -357,7 +347,7 @@ importers: '@types/vinyl': 2.0.7 '@types/yargs-parser': 21.0.0 eslint: 8.18.0 - ts-node: 10.9.0_vkghqkqmqa7oouldkgme4f7c4i + ts-node: 10.9.0_4lhcgfu2tqlb5z5dwdvf5srjjq typescript: 4.9.5 vitest: 0.30.1_less@4.1.3+terser@5.17.1 @@ -381,11 +371,11 @@ importers: yargs: ^17.1.1 dependencies: '@types/json-schema': 7.0.15 - '@types/node': 20.11.6 + '@types/node': 20.11.16 glob: 7.2.3 path-equal: 1.2.5 safe-stable-stringify: 2.4.3 - ts-node: 10.9.0_vkghqkqmqa7oouldkgme4f7c4i + ts-node: 10.9.0_4lhcgfu2tqlb5z5dwdvf5srjjq typescript: 4.9.5 yargs: 17.7.2 devDependencies: @@ -416,14 +406,14 @@ packages: dependencies: color: 3.2.1 - /@arco-design/web-react/2.46.1_p2jlmv6k7k3po6tueteg46f2ku: + /@arco-design/web-react/2.46.1_tmih5ryase7m737mtcsxs5l4a4: resolution: {integrity: sha512-XjG44rODJklDu++OApvxjt/TbRrgkNqVq6grt/H+9skysm46jFn2SwhuSljBHmjo11LtIeB1m/OMPMaFtafeYg==} peerDependencies: react: '>=16' react-dom: '>=16' dependencies: '@arco-design/color': 0.4.0 - '@babel/runtime': 7.17.0 + '@babel/runtime': 7.23.9 b-tween: 0.3.3 b-validate: 1.5.3 compute-scroll-into-view: 1.0.20 @@ -432,7 +422,7 @@ packages: number-precision: 1.6.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - react-focus-lock: 2.9.7_7kh72gklg5qjlh5zc6s6v3p6v4 + react-focus-lock: 2.9.7_pb7ekkrhicoexndz65hx2mjtey react-transition-group: 4.4.5_biqbaboplfbrettd7655fr4n2y resize-observer-polyfill: 1.5.1 scroll-into-view-if-needed: 2.2.20 @@ -511,12 +501,12 @@ packages: dependencies: '@babel/compat-data': 7.23.5 '@babel/helper-validator-option': 7.23.5 - browserslist: 4.22.2 + browserslist: 4.22.3 lru-cache: 5.1.1 semver: 6.3.1 - /@babel/helper-create-class-features-plugin/7.23.9_@babel+core@7.20.12: - resolution: {integrity: sha512-B2L9neXTIyPQoXDm+NtovPvG6VOLWnaXu3BIeVDWwdKFgG30oNa6CqVGiJPDWQwIAK49t9gnQI9c6K6RzabiKw==} + /@babel/helper-create-class-features-plugin/7.23.10_@babel+core@7.20.12: + resolution: {integrity: sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -746,7 +736,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.20.12 - '@babel/helper-create-class-features-plugin': 7.23.9_@babel+core@7.20.12 + '@babel/helper-create-class-features-plugin': 7.23.10_@babel+core@7.20.12 '@babel/helper-plugin-utils': 7.22.5 dev: false @@ -758,7 +748,7 @@ packages: '@babel/core': ^7.12.0 dependencies: '@babel/core': 7.20.12 - '@babel/helper-create-class-features-plugin': 7.23.9_@babel+core@7.20.12 + '@babel/helper-create-class-features-plugin': 7.23.10_@babel+core@7.20.12 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-class-static-block': 7.14.5_@babel+core@7.20.12 dev: false @@ -894,7 +884,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.20.12 - '@babel/helper-create-class-features-plugin': 7.23.9_@babel+core@7.20.12 + '@babel/helper-create-class-features-plugin': 7.23.10_@babel+core@7.20.12 '@babel/helper-plugin-utils': 7.22.5 dev: false @@ -907,7 +897,7 @@ packages: dependencies: '@babel/core': 7.20.12 '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.9_@babel+core@7.20.12 + '@babel/helper-create-class-features-plugin': 7.23.10_@babel+core@7.20.12 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-private-property-in-object': 7.14.5_@babel+core@7.20.12 dev: false @@ -1512,7 +1502,7 @@ packages: dependencies: '@babel/core': 7.20.12 '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.9_@babel+core@7.20.12 + '@babel/helper-create-class-features-plugin': 7.23.10_@babel+core@7.20.12 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript': 7.23.3_@babel+core@7.20.12 dev: false @@ -1668,18 +1658,11 @@ packages: resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} dev: false - /@babel/runtime/7.17.0: - resolution: {integrity: sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.11 - /@babel/runtime/7.23.9: resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 - dev: true /@babel/template/7.23.9: resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==} @@ -1777,7 +1760,7 @@ packages: debug: 4.3.4 espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.0 + ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -1808,16 +1791,12 @@ packages: lodash.uniq: 4.5.0 dev: false - /@ffmpeg/core/0.11.0: - resolution: {integrity: sha512-9Tt/+2PMpkGPXUK8n6He9G8Y+qR6qmCPSCw9iEKZxHHOvJ9BE/r0Fccj+YgDZTlyu6rXxc9x6EqCaFBIt7qzjA==} - dev: true - /@ffmpeg/ffmpeg/0.11.6: resolution: {integrity: sha512-uN8J8KDjADEavPhNva6tYO9Fj0lWs9z82swF3YXnTxWMBoFLGq3LZ6FLlIldRKEzhOBKnkVfA8UnFJuvGvNxcA==} engines: {node: '>=12.16.1'} dependencies: is-url: 1.2.4 - node-fetch: 2.6.7 + node-fetch: 2.7.0 regenerator-runtime: 0.13.11 resolve-url: 0.2.1 transitivePeerDependencies: @@ -1886,7 +1865,7 @@ packages: engines: {node: '>= 10.14.2'} dependencies: '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 chalk: 4.1.2 jest-message-util: 26.6.2 jest-util: 26.6.2 @@ -1902,7 +1881,7 @@ packages: '@jest/test-result': 26.6.2 '@jest/transform': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 ansi-escapes: 4.3.2 chalk: 4.1.2 exit: 0.1.2 @@ -1942,7 +1921,7 @@ packages: '@jest/test-result': 26.6.2 '@jest/transform': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 ansi-escapes: 4.3.2 chalk: 4.1.2 exit: 0.1.2 @@ -1991,7 +1970,7 @@ packages: dependencies: '@jest/fake-timers': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 jest-mock: 26.6.2 dev: true @@ -2010,7 +1989,7 @@ packages: dependencies: '@jest/types': 26.6.2 '@sinonjs/fake-timers': 6.0.1 - '@types/node': 20.11.6 + '@types/node': 20.11.16 jest-message-util: 26.6.2 jest-mock: 26.6.2 jest-util: 26.6.2 @@ -2204,7 +2183,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.11.6 + '@types/node': 20.11.16 '@types/yargs': 15.0.19 chalk: 4.1.2 dev: true @@ -2262,7 +2241,7 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.16.0 + fastq: 1.17.0 /@remix-run/router/1.4.0: resolution: {integrity: sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==} @@ -2274,6 +2253,7 @@ packages: cpu: [arm] os: [android] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-android-arm64/2.4.1: @@ -2282,6 +2262,7 @@ packages: cpu: [arm64] os: [android] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-darwin-arm64/2.4.1: @@ -2290,6 +2271,7 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-darwin-x64/2.4.1: @@ -2298,6 +2280,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-linux-arm-gnueabihf/2.4.1: @@ -2306,6 +2289,7 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-linux-arm64-gnu/2.4.1: @@ -2314,6 +2298,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-linux-arm64-musl/2.4.1: @@ -2322,6 +2307,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-linux-x64-gnu/2.4.1: @@ -2330,6 +2316,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-linux-x64-musl/2.4.1: @@ -2338,6 +2325,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-win32-arm64-msvc/2.4.1: @@ -2346,6 +2334,7 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-win32-ia32-msvc/2.4.1: @@ -2354,6 +2343,7 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true + dev: true optional: true /@resvg/resvg-js-win32-x64-msvc/2.4.1: @@ -2362,6 +2352,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: true optional: true /@resvg/resvg-js/2.4.1: @@ -2380,6 +2371,7 @@ packages: '@resvg/resvg-js-win32-arm64-msvc': 2.4.1 '@resvg/resvg-js-win32-ia32-msvc': 2.4.1 '@resvg/resvg-js-win32-x64-msvc': 2.4.1 + dev: true /@rollup/plugin-alias/5.0.0_rollup@3.20.5: resolution: {integrity: sha512-l9hY5chSCjuFRPsnRm16twWBiSApl2uYFLsepQYwtBuAxNMQ/1dJqADld40P0Jkqm65GRTLy/AC6hnpVebtLsA==} @@ -2445,7 +2437,7 @@ packages: astring: 1.8.6 estree-walker: 2.0.2 fast-glob: 3.3.2 - magic-string: 0.30.5 + magic-string: 0.30.6 dev: true /@rollup/plugin-json/6.0.1_rollup@3.20.5: @@ -2704,7 +2696,7 @@ packages: /@types/clean-css/4.2.6: resolution: {integrity: sha512-Ze1tf+LnGPmG6hBFMi0B4TEB0mhF7EiMM5oyjLDNPE9hxrPU0W+5+bHvO+eFPA+bt0iC1zkQMoU/iGdRVjcRbw==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 source-map: 0.6.1 dev: true @@ -2723,13 +2715,13 @@ packages: /@types/fs-extra/9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 dev: true /@types/glob-stream/8.0.2: resolution: {integrity: sha512-kyuRfGE+yiSJWzSO3t74rXxdZNdYfLcllO0IUha4eX1fl40pm9L02Q/TEc3mykTLjoWz4STBNwYnUWdFu3I0DA==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 '@types/picomatch': 2.3.3 '@types/streamx': 2.9.5 dev: true @@ -2737,26 +2729,26 @@ packages: /@types/glob-watcher/5.0.2: resolution: {integrity: sha512-MZeh2nIzibl/euv5UV0femkGzcKTSE4G2+zv48d6ymeitWwCx52+4X+FqzML9oH2mQnPs+N/JHp3CsBPj1x1Ug==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 dev: true /@types/glob/7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 dev: true /@types/graceful-fs/4.1.9: resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 dev: true /@types/gulp-if/0.0.34: resolution: {integrity: sha512-r2A04hHDC+ZWMRAm+3q6/UeC3ggvl+TZm9P1+2umnp4q9bOlBmUQnR178Io3c0DkZPQAwup8VNtOvmvaWCpP5w==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 '@types/vinyl': 2.0.7 dev: true @@ -2770,7 +2762,7 @@ packages: /@types/gulp-sourcemaps/0.0.35: resolution: {integrity: sha512-vUBuizwA4CAV3Mke0DJYHQxyN4YOB1aAql284qAO7Et7fe0hmnPi/R9Fhu2UhxMuSxAwFktsJUOQk5dJHOU1eA==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 '@types/vinyl': 2.0.7 dev: true @@ -2853,7 +2845,7 @@ packages: /@types/merge2/1.4.0: resolution: {integrity: sha512-MRHDvln2ldZELrUC8n1PGaQzZ33aNh8uDcsGehREW0zR1Fr818a4/JTZjO9eloHPPxnpUp8fz/YFTRc5CWm7Xw==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 dev: true /@types/minimatch/5.1.2: @@ -2880,8 +2872,8 @@ packages: resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} dev: false - /@types/node/20.11.6: - resolution: {integrity: sha512-+EOokTnksGVgip2PbYbr3xnR7kZigh4LbybAfBAw5BpnQ+FqBYUsvCEjYd70IXKlbohQ64mzEYmMtlWUY8q//Q==} + /@types/node/20.11.16: + resolution: {integrity: sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==} dependencies: undici-types: 5.26.5 @@ -2903,11 +2895,11 @@ packages: /@types/react-dom/18.2.18: resolution: {integrity: sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==} dependencies: - '@types/react': 18.2.48 + '@types/react': 18.2.53 dev: true - /@types/react/18.2.48: - resolution: {integrity: sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==} + /@types/react/18.2.53: + resolution: {integrity: sha512-52IHsMDT8qATp9B9zoOyobW8W3/0QhaJQTw1HwRj0UY2yBpCAQ7+S/CqHYQ8niAm3p4ji+rWUQ9UCib0GxQ60w==} dependencies: '@types/prop-types': 15.7.11 '@types/scheduler': 0.16.8 @@ -2935,7 +2927,7 @@ packages: /@types/streamx/2.9.5: resolution: {integrity: sha512-IHYsa6jYrck8VEdSwpY141FTTf6D7boPeMq9jy4qazNrFMA4VbRz/sw5LSsfR7jwdDcx0QKWkUexZvsWBC2eIQ==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 dev: true /@types/terser/3.12.0: @@ -2948,7 +2940,7 @@ packages: /@types/through2/2.0.38: resolution: {integrity: sha512-YFu+nHmjxMurkH1BSzA0Z1WrKDAY8jUKPZctNQn7mc+/KKtp2XxnclHFXxdB1m7Iqnzb5aywgP8TMK283LezGQ==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 dev: true /@types/undertaker-registry/1.0.4: @@ -2958,7 +2950,7 @@ packages: /@types/undertaker/1.2.8: resolution: {integrity: sha512-gW3PRqCHYpo45XFQHJBhch7L6hytPsIe0QeLujlnFsjHPnXLhJcPdN6a9368d7aIQgH2I/dUTPFBlGeSNA3qOg==} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 '@types/undertaker-registry': 1.0.4 async-done: 1.3.2 dev: true @@ -2967,7 +2959,7 @@ packages: resolution: {integrity: sha512-ckYz9giHgV6U10RFuf9WsDQ3X86EFougapxHmmoxLK7e6ICQqO8CE+4V/3lBN148V5N1pb4nQMmMjyScleVsig==} dependencies: '@types/glob-stream': 8.0.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 '@types/vinyl': 2.0.7 dev: true @@ -2975,7 +2967,7 @@ packages: resolution: {integrity: sha512-4UqPv+2567NhMQuMLdKAyK4yzrfCqwaTt6bLhHEs8PFcxbHILsrxaY63n4wgE/BRLDWDQeI+WcTmkXKExh9hQg==} dependencies: '@types/expect': 1.20.4 - '@types/node': 20.11.6 + '@types/node': 20.11.16 /@types/yargs-parser/21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} @@ -3011,7 +3003,7 @@ packages: debug: 4.3.4 eslint: 8.18.0 functional-red-black-tree: 1.0.1 - ignore: 5.3.0 + ignore: 5.3.1 regexpp: 3.2.0 semver: 7.5.4 tsutils: 3.21.0_typescript@4.9.5 @@ -3121,23 +3113,24 @@ packages: lodash: 4.17.21 dev: false - /@visactor/vchart/1.9.0: - resolution: {integrity: sha512-2iZg1TjBQ068De6IHjQl3zdoYlwcZ+yZmHr1R/+MGVevSOHKkpqq4O5fIQPzHDqDnk4PW7amfl6g9+B+JQ5GsA==} + /@visactor/vchart/1.9.2: + resolution: {integrity: sha512-wvzskhploTKzsspPBlx3s+m6tAMM1OU6Fyk96fRy/4WP5udjZ7X6gXFbZ2f2C4NmmleirN1nF8psVB2Q+VVk+Q==} dependencies: '@visactor/vdataset': 0.17.4 - '@visactor/vgrammar-core': 0.11.5 - '@visactor/vgrammar-hierarchy': 0.11.5 - '@visactor/vgrammar-projection': 0.11.5 - '@visactor/vgrammar-sankey': 0.11.5 - '@visactor/vgrammar-util': 0.11.5 - '@visactor/vgrammar-wordcloud': 0.11.5 - '@visactor/vgrammar-wordcloud-shape': 0.11.5 - '@visactor/vrender-components': 0.17.19 - '@visactor/vrender-core': 0.17.19 - '@visactor/vrender-kits': 0.17.19 + '@visactor/vgrammar-core': 0.11.11 + '@visactor/vgrammar-hierarchy': 0.11.11 + '@visactor/vgrammar-projection': 0.11.11 + '@visactor/vgrammar-sankey': 0.11.11 + '@visactor/vgrammar-util': 0.11.11 + '@visactor/vgrammar-wordcloud': 0.11.11 + '@visactor/vgrammar-wordcloud-shape': 0.11.11 + '@visactor/vrender-components': 0.17.23 + '@visactor/vrender-core': 0.17.23 + '@visactor/vrender-kits': 0.17.23 '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 - '@visactor/vutils-extension': 1.9.0 + '@visactor/vutils-extension': 1.9.2 + dev: true /@visactor/vdataset/0.17.4: resolution: {integrity: sha512-o43a4/z9J3Wr/u+5BI8G+XwtWAJSHl+Pg0+UZDYoS+lXQLJV64THokAfhWUEWrMqxnrUbdBqaPgZAozYzaZJdg==} @@ -3160,171 +3153,120 @@ packages: simplify-geojson: 1.0.5 topojson-client: 3.1.0 - /@visactor/vgrammar-coordinate/0.11.5: - resolution: {integrity: sha512-j3oIOQOI229s5g3FlJGqUmPd9kFMqdNDXK2lim1g+SLxLKxIvf5lP7w6IrJL18dL5r5bfw0OO7qfWQrHMxm5eA==} + /@visactor/vgrammar-coordinate/0.11.11: + resolution: {integrity: sha512-2gwXXfi+NrkdcoQABL2heYs31qfzIWuv3AqYm/qO5pFQ78+eGsB9ZGo/8DldjvfMH8zw50QzB+tzgLrlEcUenA==} dependencies: - '@visactor/vgrammar-util': 0.11.5 + '@visactor/vgrammar-util': 0.11.11 '@visactor/vutils': 0.17.4 + dev: true - /@visactor/vgrammar-coordinate/0.5.7: - resolution: {integrity: sha512-7eDnI8Bd9IQzF7Tm1DFiJqTcpIdk79RfXHVieiG/szbCNOvxxqxWzzAbEI28GKFYUBPehRR7e33n5JsIRFp5vA==} - dependencies: - '@visactor/vgrammar-util': 0.5.7 - '@visactor/vutils': 0.13.3 - dev: false - - /@visactor/vgrammar-core/0.11.5: - resolution: {integrity: sha512-mjhps1xC9sYvWmgVp1lV3UVl8dUT+waHhPC3hL2XDRZ+YV0e694U2HPiWlh0JsVHXerYFdjm63t1UVfy48LqRg==} + /@visactor/vgrammar-core/0.11.11: + resolution: {integrity: sha512-3y1EPhWn95FaqA6UnNR+LNHzTM3zaJRUPLl29a9oUXVV6OgOTo05dEFyETuaybrxIDpPodqroBGU2yemikvgjA==} dependencies: '@visactor/vdataset': 0.17.4 - '@visactor/vgrammar-coordinate': 0.11.5 - '@visactor/vgrammar-util': 0.11.5 - '@visactor/vrender-components': 0.17.19 - '@visactor/vrender-core': 0.17.19 - '@visactor/vrender-kits': 0.17.19 + '@visactor/vgrammar-coordinate': 0.11.11 + '@visactor/vgrammar-util': 0.11.11 + '@visactor/vrender-components': 0.17.23 + '@visactor/vrender-core': 0.17.23 + '@visactor/vrender-kits': 0.17.23 '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 + dev: true - /@visactor/vgrammar-hierarchy/0.11.5: - resolution: {integrity: sha512-HVsKusLuL1VwcuNXXqQA0uZ9XIQc25uLa0D3xBBwzkTxyMAvRWSmfh/sLFxnd+HiCZsV8iTXXzvyPUY9V/uOpQ==} + /@visactor/vgrammar-hierarchy/0.11.11: + resolution: {integrity: sha512-iJmUYV++GxguZgpeoH3g2C6b1Es25hXdSr7wvZyckQBEMhfXoLj8zDV00BNkMKO46gPNUGBq6lH84NHDmXfCAw==} dependencies: - '@visactor/vgrammar-core': 0.11.5 - '@visactor/vgrammar-util': 0.11.5 - '@visactor/vrender-core': 0.17.19 - '@visactor/vrender-kits': 0.17.19 + '@visactor/vgrammar-core': 0.11.11 + '@visactor/vgrammar-util': 0.11.11 + '@visactor/vrender-core': 0.17.23 + '@visactor/vrender-kits': 0.17.23 '@visactor/vutils': 0.17.4 + dev: true - /@visactor/vgrammar-projection/0.11.5: - resolution: {integrity: sha512-ZzzP0UMn4iD8wIFGG/R59kJbTsN0hruyx6vxju7tYQTNCwO/n7T+JDAbjVFpVSfMmu8/xYO0NKRdJX0PqQ8iZA==} + /@visactor/vgrammar-projection/0.11.11: + resolution: {integrity: sha512-fop112v6EROgZQA4jOpkRa5MFymo7JrfUybIt1d0qZzW2TDHNP1BCDZl6GmODMflBNXs03zalwgzj/GnEBC6bw==} dependencies: - '@visactor/vgrammar-core': 0.11.5 - '@visactor/vgrammar-util': 0.11.5 + '@visactor/vgrammar-core': 0.11.11 + '@visactor/vgrammar-util': 0.11.11 '@visactor/vutils': 0.17.4 d3-geo: 1.12.1 + dev: true - /@visactor/vgrammar-sankey/0.11.5: - resolution: {integrity: sha512-SOsMj0tj9Zu13NBErdQkKoQcyUNu3Er3BnZP85fyv0lGzdQW6m3o/T2ziVP7sZJwWm8vXwiUOI2dYEaN9zJNwQ==} + /@visactor/vgrammar-sankey/0.11.11: + resolution: {integrity: sha512-J98xvPW6aJXCJ/AIb0Mw5RU7HVCH63k7ZoQXyphbT850AZXN7s+cztY6TQk9/CHe2Fv536Wf+bHe8mdbty5jlw==} dependencies: - '@visactor/vgrammar-core': 0.11.5 - '@visactor/vgrammar-util': 0.11.5 - '@visactor/vrender-core': 0.17.19 - '@visactor/vrender-kits': 0.17.19 + '@visactor/vgrammar-core': 0.11.11 + '@visactor/vgrammar-util': 0.11.11 + '@visactor/vrender-core': 0.17.23 + '@visactor/vrender-kits': 0.17.23 '@visactor/vutils': 0.17.4 + dev: true - /@visactor/vgrammar-util/0.11.5: - resolution: {integrity: sha512-trbgNsbj+TBa+202Iw+ews79w0iiZSeLgoWcq80pS+2U+xiuCjjdyDe6U1sbJV/6HKtRR1mSk4dwdR0NRVs0hQ==} + /@visactor/vgrammar-util/0.11.11: + resolution: {integrity: sha512-3R4KdQ2j0JH0ZeM8eMSoa8RM/RXHWNv3AFiO5ebzBZDALzkgBvcYmKmyMEINTkakRlojEFpaP27LqkCL0CpYPg==} dependencies: '@visactor/vutils': 0.17.4 + dev: true - /@visactor/vgrammar-util/0.5.7: - resolution: {integrity: sha512-k1UeYvUyhtzUW+s/GIt/B8uRakJzbtWUMR7PpgDJQOlXL+zdyumK2I01U1gRLaY6t6VWbpLjk32iifJfO7oQHg==} - dependencies: - '@visactor/vutils': 0.13.3 - dev: false - - /@visactor/vgrammar-wordcloud-shape/0.11.5: - resolution: {integrity: sha512-+6hKAXZ3OaNiw3PfNcPc5K0BLz8Z6tC5F3eYdzrlLBVvzQGyea+o7LjHPMfcPH6jHhatOXsPOrXb6QAVoL9A0A==} + /@visactor/vgrammar-wordcloud-shape/0.11.11: + resolution: {integrity: sha512-kzPJgfZonxWUVsKNn0ov81KIrzJAV3d6MQm6A/yYWfJvqF4T44iB38FRo9Ox+uBZ19wLqnx8ueE2WgId3Far5w==} dependencies: - '@visactor/vgrammar-core': 0.11.5 - '@visactor/vgrammar-util': 0.11.5 - '@visactor/vrender-core': 0.17.19 - '@visactor/vrender-kits': 0.17.19 + '@visactor/vgrammar-core': 0.11.11 + '@visactor/vgrammar-util': 0.11.11 + '@visactor/vrender-core': 0.17.23 + '@visactor/vrender-kits': 0.17.23 '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 + dev: true - /@visactor/vgrammar-wordcloud/0.11.5: - resolution: {integrity: sha512-zWzfs1nQyQJv/pgJHilC/DnDhe+M3u/d51bBPlaAmSNijPVY85sNSIwbGVJVuGi2zSJLmB5YbbFuZCWp23TuwA==} + /@visactor/vgrammar-wordcloud/0.11.11: + resolution: {integrity: sha512-OPThALDHaXKBw9EadNuFhUoOBD+vvtxTvdV+YxJrZ7B1dDfr8lJ896ACNqacQ9lUikHJdO8DhutdcS5FQw1/gg==} dependencies: - '@visactor/vgrammar-core': 0.11.5 - '@visactor/vgrammar-util': 0.11.5 - '@visactor/vrender-core': 0.17.19 - '@visactor/vrender-kits': 0.17.19 + '@visactor/vgrammar-core': 0.11.11 + '@visactor/vgrammar-util': 0.11.11 + '@visactor/vrender-core': 0.17.23 + '@visactor/vrender-kits': 0.17.23 '@visactor/vutils': 0.17.4 + dev: true - /@visactor/vgrammar/0.5.7: - resolution: {integrity: sha512-bm9pxj/hIs8dh2i+liKyk/wx4N+yINph9kLig+BLYXXlctjwRl4ge7Zh9PRZGOiLVLRM0WKEQt/eAdMrUCfQfg==} - dependencies: - '@visactor/vgrammar-coordinate': 0.5.7 - '@visactor/vgrammar-util': 0.5.7 - '@visactor/vrender': 0.13.14 - '@visactor/vrender-components': 0.13.17 - '@visactor/vscale': 0.13.4 - '@visactor/vutils': 0.13.3 - dev: false - - /@visactor/vrender-components/0.13.17: - resolution: {integrity: sha512-9UjNk/4g/JEm/89Cd/uUuq9As78YeUVdEP+A6uRm8v5Bryg5c4+gBZ500Hxweo8Kx2UDIAbGIDo+ioaNysDRzw==} - dependencies: - '@visactor/vrender': 0.13.14 - '@visactor/vscale': 0.13.4 - '@visactor/vutils': 0.13.3 - inversify: 6.0.1 - dev: false - - /@visactor/vrender-components/0.17.19: - resolution: {integrity: sha512-B5Hj9n71OuWBMPo16G0HUUgHJFFiQDklwojtJvUgWmdp0gjGkbGJN4//+C1tEN1ONSAJc+uJvo2fZZMxcnpi7w==} + /@visactor/vrender-components/0.17.23: + resolution: {integrity: sha512-unFzLVodABDVh5RQA3ls/eR6mLHoy/nx6yyoMm6VibuHZUYORI7W3x30vgFHn+POo7yPV3aVjB56Y2IUH7FrtQ==} dependencies: - '@visactor/vrender-core': 0.17.19 - '@visactor/vrender-kits': 0.17.19 + '@visactor/vrender-core': 0.17.23 + '@visactor/vrender-kits': 0.17.23 '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 + dev: true - /@visactor/vrender-core/0.17.19: - resolution: {integrity: sha512-ylqm0QDZb2vk7HbFjJrp7JES6A0LneaeFK/EYcV/A32x7U60wi8WOIwuVhHWv0rxBeQ6YzgiDbGCPnjwHux5jA==} + /@visactor/vrender-core/0.17.23: + resolution: {integrity: sha512-3m7p63TV7JvNCsoeb7oqsNPP3noUCNI1BJxl99mTBn6fu5DW5Wb/fTlRZ3VYo1hCGEkTk76d5kj1HhDEJvUC/w==} dependencies: '@visactor/vutils': 0.17.4 color-convert: 2.0.1 - /@visactor/vrender-kits/0.17.19: - resolution: {integrity: sha512-qnlJkgJj+dVy6jpscv5fG02f/cUeInO/v9VSfxIgS2w1ZTEAiV09U6FVvGCIPlrX+UylihzVexTMI4L44GkX7Q==} + /@visactor/vrender-kits/0.17.23: + resolution: {integrity: sha512-3Mnr5y62ZTeZweaEGNLMM8Wf3vkf2K8aTiW4kinXkk0Am0k78v/0kdkwaYEnNM89uJ4zRVXPkkLG6h+/4KMo8Q==} dependencies: '@resvg/resvg-js': 2.4.1 - '@visactor/vrender-core': 0.17.19 + '@visactor/vrender-core': 0.17.23 '@visactor/vutils': 0.17.4 roughjs: 4.5.2 - - /@visactor/vrender/0.13.14: - resolution: {integrity: sha512-Pu0l+Pg2KpwroX+pSRcZ4zzW/A6pEDo3KD4V61G/iYkaQ/ajJkwHfkSKSzo/dMKo6lipKY/r1R6svmYqBdFOEA==} - dependencies: - '@visactor/vutils': 0.13.3 - color-convert: 2.0.1 - core-js: 3.31.1 - inversify: 6.0.1 - dev: false - - /@visactor/vrender/0.17.19: - resolution: {integrity: sha512-ZQqYXPe49zQ74Rxk6k8P7e/keg29KUQG5J3hcBI+FrmR6GSegODFATnif7o7z4tfeaqGJiDcrwczdcParQSLiw==} - dependencies: - '@visactor/vrender-core': 0.17.19 - '@visactor/vrender-kits': 0.17.19 - dev: false - - /@visactor/vscale/0.13.4: - resolution: {integrity: sha512-UeyPYN+vAmvI+CURCfRN1s+peKeFDGxdblTJCgvZj/bho1oJF6WeI/mqAOquLeCT4+Y3f3SYoqIqDL5nSHJkZw==} - dependencies: - '@visactor/vutils': 0.13.3 - dev: false + dev: true /@visactor/vscale/0.17.4: resolution: {integrity: sha512-gF9SWmduQxat8ct8BkDwT3C/E7aWxsqKctJ6zI+XZzL/wLD4NELnA7zUSiuRmyAunjaH87B9jNtiPcBRMviVEw==} dependencies: '@visactor/vutils': 0.17.4 + dev: true - /@visactor/vutils-extension/1.9.0: - resolution: {integrity: sha512-yZpk+E8tyil/Iz/0riIXQRB40H2ExfKfv0fm6UFrzGit3kigIk5vKKGe2rO2OO30FGC+V1DpG4H2U/5QKmNOIA==} + /@visactor/vutils-extension/1.9.2: + resolution: {integrity: sha512-qOL5lsUx+RSM3/A/kEJB3+50QPC+wQs2tEclrfa7EXWdXQzVPNlcU2evDikTJska6b/WlMJIdtdNvbAhaTz51A==} dependencies: - '@visactor/vrender-core': 0.17.19 - '@visactor/vrender-kits': 0.17.19 + '@visactor/vrender-core': 0.17.23 + '@visactor/vrender-kits': 0.17.23 '@visactor/vscale': 0.17.4 '@visactor/vutils': 0.17.4 - - /@visactor/vutils/0.13.3: - resolution: {integrity: sha512-lCFiuUHwqz/0RCvIYa79ycduCLAILWaXddPOjxEd3VRX9CCoWMUmRtM3gF5JxtK2pK6Mu7hW7LaMSuWFw+0Kkw==} - dependencies: - '@turf/helpers': 6.5.0 - '@turf/invariant': 6.5.0 - eventemitter3: 4.0.7 - dev: false + dev: true /@visactor/vutils/0.17.4: resolution: {integrity: sha512-tii2RpNEhXsvU+DRgadFcfo0UM/xOIZz7bxhycA624TUQdPnH/tOpdjAtSdvnjusrMmqsx8yAJa8j1imXkZLsg==} @@ -3369,7 +3311,7 @@ packages: /@vitest/snapshot/0.30.1: resolution: {integrity: sha512-fJZqKrE99zo27uoZA/azgWyWbFvM1rw2APS05yB0JaLwUIg9aUtvvnBf4q7JWhEcAHmSwbrxKFgyBUga6tq9Tw==} dependencies: - magic-string: 0.30.5 + magic-string: 0.30.6 pathe: 1.1.2 pretty-format: 27.5.1 dev: true @@ -3698,11 +3640,12 @@ packages: resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} engines: {node: '>=0.10.0'} - /array-buffer-byte-length/1.0.0: - resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + /array-buffer-byte-length/1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 - is-array-buffer: 3.0.2 + is-array-buffer: 3.0.4 /array-each/1.0.1: resolution: {integrity: sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==} @@ -3720,7 +3663,7 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 is-string: 1.0.7 /array-initial/1.1.0: @@ -3768,6 +3711,17 @@ packages: resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} engines: {node: '>=0.10.0'} + /array.prototype.filter/1.0.3: + resolution: {integrity: sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-array-method-boxes-properly: 1.0.0 + is-string: 1.0.7 + dev: true + /array.prototype.findlastindex/1.2.3: resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} engines: {node: '>= 0.4'} @@ -3776,7 +3730,7 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.3 es-shim-unscopables: 1.0.2 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 dev: true /array.prototype.flat/1.3.2: @@ -3808,16 +3762,17 @@ packages: is-string: 1.0.7 dev: true - /arraybuffer.prototype.slice/1.0.2: - resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + /arraybuffer.prototype.slice/1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} engines: {node: '>= 0.4'} dependencies: - array-buffer-byte-length: 1.0.0 + array-buffer-byte-length: 1.0.1 call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - get-intrinsic: 1.2.2 - is-array-buffer: 3.0.2 + es-errors: 1.3.0 + get-intrinsic: 1.2.3 + is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.2 /asn1/0.2.6: @@ -3897,8 +3852,8 @@ packages: peerDependencies: postcss: ^8.1.0 dependencies: - browserslist: 4.22.2 - caniuse-lite: 1.0.30001580 + browserslist: 4.22.3 + caniuse-lite: 1.0.30001584 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -3906,8 +3861,8 @@ packages: postcss-value-parser: 4.2.0 dev: false - /available-typed-arrays/1.0.5: - resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + /available-typed-arrays/1.0.6: + resolution: {integrity: sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==} engines: {node: '>= 0.4'} /aws-sign2/0.7.0: @@ -4248,15 +4203,15 @@ packages: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} dev: true - /browserslist/4.22.2: - resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} + /browserslist/4.22.3: + resolution: {integrity: sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001580 - electron-to-chromium: 1.4.646 + caniuse-lite: 1.0.30001584 + electron-to-chromium: 1.4.656 node-releases: 2.0.14 - update-browserslist-db: 1.0.13_browserslist@4.22.2 + update-browserslist-db: 1.0.13_browserslist@4.22.3 /bs-logger/0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} @@ -4340,7 +4295,7 @@ packages: resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} dependencies: function-bind: 1.1.2 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 set-function-length: 1.2.0 /callsites/3.1.0: @@ -4362,8 +4317,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite/1.0.30001580: - resolution: {integrity: sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA==} + /caniuse-lite/1.0.30001584: + resolution: {integrity: sha512-LOz7CCQ9M1G7OjJOF9/mzmqmj3jE/7VOmrfw6Mgs0E8cjOsbRXQJHsPBfmBOXDskXKrHLyyW3n7kpDW/4BsfpQ==} /capture-exit/2.0.0: resolution: {integrity: sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==} @@ -4731,12 +4686,7 @@ packages: /core-js-compat/3.35.1: resolution: {integrity: sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw==} dependencies: - browserslist: 4.22.2 - dev: false - - /core-js/3.31.1: - resolution: {integrity: sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ==} - requiresBuild: true + browserslist: 4.22.3 dev: false /core-util-is/1.0.2: @@ -4982,7 +4932,7 @@ packages: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 gopd: 1.0.1 has-property-descriptors: 1.0.1 @@ -5084,7 +5034,7 @@ packages: /dom-helpers/5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} dependencies: - '@babel/runtime': 7.17.0 + '@babel/runtime': 7.23.9 csstype: 3.1.3 /dom-serializer/1.4.1: @@ -5183,8 +5133,8 @@ packages: safer-buffer: 2.1.2 dev: true - /electron-to-chromium/1.4.646: - resolution: {integrity: sha512-vThkQ0JuF45qT/20KbRgM56lV7IuGt7SjhawQ719PDHzhP84KAO1WJoaxgCoAffKHK47FmVKP1Fqizx7CwK1SA==} + /electron-to-chromium/1.4.656: + resolution: {integrity: sha512-9AQB5eFTHyR3Gvt2t/NwR0le2jBSUNwCnMbUCejFWHD+so4tH40/dRLgoE+jxlPeWS43XJewyvCv+I8LPMl49Q==} /electron/11.5.0: resolution: {integrity: sha512-WjNDd6lGpxyiNjE3LhnFCAk/D9GIj1rU3GSDealVShhkkkPR3Vh4q8ErXGDl1OAO/faomVa10KoFPUN/pLbNxg==} @@ -5257,14 +5207,14 @@ packages: resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} engines: {node: '>= 0.4'} dependencies: - array-buffer-byte-length: 1.0.0 - arraybuffer.prototype.slice: 1.0.2 - available-typed-arrays: 1.0.5 + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.6 call-bind: 1.0.5 es-set-tostringtag: 2.0.2 es-to-primitive: 1.2.1 function.prototype.name: 1.1.6 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 get-symbol-description: 1.0.0 globalthis: 1.0.3 gopd: 1.0.1 @@ -5273,13 +5223,13 @@ packages: has-symbols: 1.0.3 hasown: 2.0.0 internal-slot: 1.0.6 - is-array-buffer: 3.0.2 + is-array-buffer: 3.0.4 is-callable: 1.2.7 is-negative-zero: 2.0.2 is-regex: 1.1.4 is-shared-array-buffer: 1.0.2 is-string: 1.0.7 - is-typed-array: 1.1.12 + is-typed-array: 1.1.13 is-weakref: 1.0.2 object-inspect: 1.13.1 object-keys: 1.1.1 @@ -5295,12 +5245,16 @@ packages: typed-array-byte-offset: 1.0.0 typed-array-length: 1.0.4 unbox-primitive: 1.0.2 - which-typed-array: 1.1.13 + which-typed-array: 1.1.14 /es-array-method-boxes-properly/1.0.0: resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} dev: true + /es-errors/1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + /es-iterator-helpers/1.0.15: resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} dependencies: @@ -5310,7 +5264,7 @@ packages: es-abstract: 1.22.3 es-set-tostringtag: 2.0.2 function-bind: 1.1.2 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 globalthis: 1.0.3 has-property-descriptors: 1.0.1 has-proto: 1.0.1 @@ -5324,8 +5278,8 @@ packages: resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.2 - has-tostringtag: 1.0.0 + get-intrinsic: 1.2.3 + has-tostringtag: 1.0.2 hasown: 2.0.0 /es-shim-unscopables/1.0.2: @@ -5681,7 +5635,7 @@ packages: is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.7 - object.groupby: 1.0.1 + object.groupby: 1.0.2 object.values: 1.1.7 semver: 6.3.1 tsconfig-paths: 3.15.0 @@ -5823,7 +5777,7 @@ packages: functional-red-black-tree: 1.0.1 glob-parent: 6.0.2 globals: 13.24.0 - ignore: 5.3.0 + ignore: 5.3.1 import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 @@ -6090,8 +6044,8 @@ packages: /fast-levenshtein/2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - /fastq/1.16.0: - resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} + /fastq/1.17.0: + resolution: {integrity: sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==} dependencies: reusify: 1.0.4 @@ -6231,7 +6185,7 @@ packages: resolution: {integrity: sha512-a8Ge6cdKh9za/GZR/qtigTAk7SrGore56EFcoMshClsh7FLk1zwszc/ltuMfKhx56qeuyL/jWQ4J4axou0iJ9w==} engines: {node: '>=10'} dependencies: - tslib: 2.3.1 + tslib: 2.6.2 /follow-redirects/1.15.5: resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} @@ -6425,9 +6379,11 @@ packages: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} dev: true - /get-intrinsic/1.2.2: - resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + /get-intrinsic/1.2.3: + resolution: {integrity: sha512-JIcZczvcMVE7AUOP+X72bh8HqHBRxFdz5PDHYtNG/lE3yk9b3KZBJlwFcTyPYjg3L4RLLmZJzvjxhaZVapxFrQ==} + engines: {node: '>= 0.4'} dependencies: + es-errors: 1.3.0 function-bind: 1.1.2 has-proto: 1.0.1 has-symbols: 1.0.3 @@ -6461,7 +6417,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 /get-value/2.0.6: resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} @@ -6622,7 +6578,7 @@ packages: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.0 + ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 @@ -6636,7 +6592,7 @@ packages: /gopd/1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 /got/9.6.0: resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==} @@ -6722,7 +6678,7 @@ packages: resolution: {integrity: sha512-SVSF7ikuWKhpAW4l4wapAqPPSToJoiNKsbDoUnRrSgwZHH7lH8pbPeQj1aOVYQrbZKhfSVBxVW+Py7vtulRktw==} engines: {node: '>=10'} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 '@types/vinyl': 2.0.7 istextorbinary: 3.3.0 replacestream: 4.0.3 @@ -6807,7 +6763,7 @@ packages: /has-property-descriptors/1.0.1: resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} dependencies: - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 /has-proto/1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} @@ -6817,8 +6773,8 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} - /has-tostringtag/1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + /has-tostringtag/1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 @@ -6957,8 +6913,8 @@ packages: /ieee754/1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - /ignore/5.3.0: - resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} + /ignore/5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} /image-size/0.5.5: @@ -7008,7 +6964,7 @@ packages: resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 hasown: 2.0.0 side-channel: 1.0.4 @@ -7023,10 +6979,6 @@ packages: loose-envify: 1.4.0 dev: true - /inversify/6.0.1: - resolution: {integrity: sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==} - dev: false - /invert-kv/1.0.0: resolution: {integrity: sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==} engines: {node: '>=0.10.0'} @@ -7046,12 +6998,12 @@ packages: dependencies: hasown: 2.0.0 - /is-array-buffer/3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + /is-array-buffer/3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 - get-intrinsic: 1.2.2 - is-typed-array: 1.1.12 + get-intrinsic: 1.2.3 /is-arrayish/0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -7063,7 +7015,7 @@ packages: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /is-bigint/1.0.4: @@ -7090,7 +7042,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 /is-buffer/1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} @@ -7128,7 +7080,7 @@ packages: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 /is-descriptor/0.1.7: resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} @@ -7196,7 +7148,7 @@ packages: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /is-glob/3.1.0: @@ -7233,7 +7185,7 @@ packages: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 /is-number/3.0.0: resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} @@ -7285,7 +7237,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 /is-relative/1.0.0: resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==} @@ -7317,7 +7269,7 @@ packages: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 /is-symbol/1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} @@ -7325,11 +7277,11 @@ packages: dependencies: has-symbols: 1.0.3 - /is-typed-array/1.1.12: - resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + /is-typed-array/1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} dependencies: - which-typed-array: 1.1.13 + which-typed-array: 1.1.14 /is-typedarray/1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -7373,7 +7325,7 @@ packages: resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} dependencies: call-bind: 1.0.5 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 dev: true /is-what/3.14.1: @@ -7507,9 +7459,9 @@ packages: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} dependencies: define-properties: 1.2.1 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.4 + reflect.getprototypeof: 1.0.5 set-function-name: 2.0.1 dev: true @@ -7660,7 +7612,7 @@ packages: jest-validate: 26.6.2 micromatch: 4.0.5 pretty-format: 26.6.2 - ts-node: 10.9.0_vkghqkqmqa7oouldkgme4f7c4i + ts-node: 10.9.0_4lhcgfu2tqlb5z5dwdvf5srjjq transitivePeerDependencies: - bufferutil - canvas @@ -7765,7 +7717,7 @@ packages: '@jest/environment': 26.6.2 '@jest/fake-timers': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 jest-mock: 26.6.2 jest-util: 26.6.2 jsdom: 16.7.0 @@ -7796,7 +7748,7 @@ packages: '@jest/environment': 26.6.2 '@jest/fake-timers': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 jest-mock: 26.6.2 jest-util: 26.6.2 dev: true @@ -7836,7 +7788,7 @@ packages: dependencies: '@jest/types': 26.6.2 '@types/graceful-fs': 4.1.9 - '@types/node': 20.11.6 + '@types/node': 20.11.16 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -7884,7 +7836,7 @@ packages: '@jest/source-map': 26.6.2 '@jest/test-result': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 chalk: 4.1.2 co: 4.6.0 expect: 26.6.2 @@ -7914,7 +7866,7 @@ packages: '@jest/source-map': 26.6.2 '@jest/test-result': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 chalk: 4.1.2 co: 4.6.0 expect: 26.6.2 @@ -8012,7 +7964,7 @@ packages: engines: {node: '>= 10.14.2'} dependencies: '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 dev: true /jest-pnp-resolver/1.2.3_jest-resolve@24.9.0: @@ -8118,7 +8070,7 @@ packages: '@jest/environment': 26.6.2 '@jest/test-result': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 chalk: 4.1.2 emittery: 0.7.2 exit: 0.1.2 @@ -8150,7 +8102,7 @@ packages: '@jest/environment': 26.6.2 '@jest/test-result': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 chalk: 4.1.2 emittery: 0.7.2 exit: 0.1.2 @@ -8295,7 +8247,7 @@ packages: resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==} engines: {node: '>= 10.14.2'} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 graceful-fs: 4.2.11 dev: true @@ -8363,7 +8315,7 @@ packages: engines: {node: '>= 10.14.2'} dependencies: '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 chalk: 4.1.2 graceful-fs: 4.2.11 is-ci: 2.0.0 @@ -8400,7 +8352,7 @@ packages: dependencies: '@jest/test-result': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 20.11.6 + '@types/node': 20.11.16 ansi-escapes: 4.3.2 chalk: 4.1.2 jest-util: 26.6.2 @@ -8419,7 +8371,7 @@ packages: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 merge-stream: 2.0.0 supports-color: 7.2.0 dev: true @@ -8753,7 +8705,7 @@ packages: dependencies: copy-anything: 2.0.6 parse-node-version: 1.0.1 - tslib: 2.3.1 + tslib: 2.6.2 optionalDependencies: errno: 0.1.8 graceful-fs: 4.2.11 @@ -8984,8 +8936,8 @@ packages: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 - /magic-string/0.30.5: - resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} + /magic-string/0.30.6: + resolution: {integrity: sha512-n62qCLbPjNjyo+owKtveQxZFZTBm+Ms6YoGD23Wew6Vw337PElFNifQpknPruVRQV57kVShPnLGo9vWxVhpPvA==} engines: {node: '>=12'} dependencies: '@jridgewell/sourcemap-codec': 1.4.15 @@ -9328,8 +9280,8 @@ packages: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} dev: true - /node-fetch/2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + /node-fetch/2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} peerDependencies: encoding: ^0.1.0 @@ -9528,13 +9480,14 @@ packages: safe-array-concat: 1.1.0 dev: true - /object.groupby/1.0.1: - resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} + /object.groupby/1.0.2: + resolution: {integrity: sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==} dependencies: + array.prototype.filter: 1.0.3 call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - get-intrinsic: 1.2.2 + es-errors: 1.3.0 dev: true /object.hasown/1.1.3: @@ -9755,6 +9708,7 @@ packages: /path-data-parser/0.1.0: resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + dev: true /path-dirname/1.0.2: resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} @@ -9956,12 +9910,14 @@ packages: /points-on-curve/0.2.0: resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + dev: true /points-on-path/0.2.1: resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} dependencies: path-data-parser: 0.1.0 points-on-curve: 0.2.0 + dev: true /posix-character-classes/0.1.1: resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} @@ -10133,7 +10089,7 @@ packages: peerDependencies: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 dependencies: - '@babel/runtime': 7.17.0 + '@babel/runtime': 7.23.9 react: 18.2.0 /react-dom/18.2.0_react@18.2.0: @@ -10145,7 +10101,7 @@ packages: react: 18.2.0 scheduler: 0.23.0 - /react-focus-lock/2.9.7_7kh72gklg5qjlh5zc6s6v3p6v4: + /react-focus-lock/2.9.7_pb7ekkrhicoexndz65hx2mjtey: resolution: {integrity: sha512-EfhX040SELLqnQ9JftqsmQCG49iByg8F5X5m19Er+n371OaETZ35dlNPZrLOOTlnnwD4c2Zv0KDgabDTc7dPHw==} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -10154,14 +10110,14 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.17.0 - '@types/react': 18.2.48 + '@babel/runtime': 7.23.9 + '@types/react': 18.2.53 focus-lock: 1.0.0 prop-types: 15.8.1 react: 18.2.0 react-clientside-effect: 1.2.6_react@18.2.0 - use-callback-ref: 1.3.1_7kh72gklg5qjlh5zc6s6v3p6v4 - use-sidecar: 1.1.2_7kh72gklg5qjlh5zc6s6v3p6v4 + use-callback-ref: 1.3.1_pb7ekkrhicoexndz65hx2mjtey + use-sidecar: 1.1.2_pb7ekkrhicoexndz65hx2mjtey /react-is/16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -10202,7 +10158,7 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' dependencies: - '@babel/runtime': 7.17.0 + '@babel/runtime': 7.23.9 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -10331,14 +10287,15 @@ packages: resolve: 1.22.8 dev: false - /reflect.getprototypeof/1.0.4: - resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} + /reflect.getprototypeof/1.0.5: + resolution: {integrity: sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - get-intrinsic: 1.2.2 + es-errors: 1.3.0 + get-intrinsic: 1.2.3 globalthis: 1.0.3 which-builtin-type: 1.1.3 dev: true @@ -10356,15 +10313,15 @@ packages: /regenerator-runtime/0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: true /regenerator-runtime/0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: true /regenerator-transform/0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} dependencies: - '@babel/runtime': 7.17.0 + '@babel/runtime': 7.23.9 dev: false /regex-not/1.0.2: @@ -10659,6 +10616,7 @@ packages: path-data-parser: 0.1.0 points-on-curve: 0.2.0 points-on-path: 0.2.1 + dev: true /rsvp/4.8.5: resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==} @@ -10678,7 +10636,7 @@ packages: engines: {node: '>=0.4'} dependencies: call-bind: 1.0.5 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 has-symbols: 1.0.3 isarray: 2.0.5 @@ -10693,7 +10651,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 is-regex: 1.1.4 /safe-regex/1.1.0: @@ -10808,7 +10766,7 @@ packages: dependencies: define-data-property: 1.1.1 function-bind: 1.1.2 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 gopd: 1.0.1 has-property-descriptors: 1.0.1 @@ -10882,7 +10840,7 @@ packages: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: call-bind: 1.0.5 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 object-inspect: 1.13.1 /siginfo/2.0.0: @@ -11149,7 +11107,7 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.3 has-symbols: 1.0.3 internal-slot: 1.0.6 regexp.prototype.flags: 1.5.1 @@ -11591,7 +11549,7 @@ packages: yargs-parser: 20.2.9 dev: true - /ts-node/10.9.0_vkghqkqmqa7oouldkgme4f7c4i: + /ts-node/10.9.0_4lhcgfu2tqlb5z5dwdvf5srjjq: resolution: {integrity: sha512-bunW18GUyaCSYRev4DPf4SQpom3pWH29wKl0sDk5zE7ze19RImEVhCW7K4v3hHKkUyfWotU08ToE2RS+Y49aug==} hasBin: true peerDependencies: @@ -11610,7 +11568,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.11.6 + '@types/node': 20.11.16 acorn: 8.11.3 acorn-walk: 8.3.2 arg: 4.1.3 @@ -11637,8 +11595,8 @@ packages: /tslib/1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - /tslib/2.3.1: - resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + /tslib/2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} /tsutils/3.21.0_typescript@4.9.5: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -11721,8 +11679,8 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 - get-intrinsic: 1.2.2 - is-typed-array: 1.1.12 + get-intrinsic: 1.2.3 + is-typed-array: 1.1.13 /typed-array-byte-length/1.0.0: resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} @@ -11731,24 +11689,24 @@ packages: call-bind: 1.0.5 for-each: 0.3.3 has-proto: 1.0.1 - is-typed-array: 1.1.12 + is-typed-array: 1.1.13 /typed-array-byte-offset/1.0.0: resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.5 + available-typed-arrays: 1.0.6 call-bind: 1.0.5 for-each: 0.3.3 has-proto: 1.0.1 - is-typed-array: 1.1.12 + is-typed-array: 1.1.13 /typed-array-length/1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} dependencies: call-bind: 1.0.5 for-each: 0.3.3 - is-typed-array: 1.1.12 + is-typed-array: 1.1.13 /typedarray-to-buffer/3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} @@ -11892,13 +11850,13 @@ packages: engines: {node: '>=4'} dev: false - /update-browserslist-db/1.0.13_browserslist@4.22.2: + /update-browserslist-db/1.0.13_browserslist@4.22.3: resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.22.2 + browserslist: 4.22.3 escalade: 3.1.1 picocolors: 1.0.0 @@ -11925,7 +11883,7 @@ packages: requires-port: 1.0.0 dev: true - /use-callback-ref/1.3.1_7kh72gklg5qjlh5zc6s6v3p6v4: + /use-callback-ref/1.3.1_pb7ekkrhicoexndz65hx2mjtey: resolution: {integrity: sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==} engines: {node: '>=10'} peerDependencies: @@ -11935,11 +11893,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.48 + '@types/react': 18.2.53 react: 18.2.0 - tslib: 2.3.1 + tslib: 2.6.2 - /use-sidecar/1.1.2_7kh72gklg5qjlh5zc6s6v3p6v4: + /use-sidecar/1.1.2_pb7ekkrhicoexndz65hx2mjtey: resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} engines: {node: '>=10'} peerDependencies: @@ -11949,10 +11907,10 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.48 + '@types/react': 18.2.53 detect-node-es: 1.1.0 react: 18.2.0 - tslib: 2.3.1 + tslib: 2.6.2 /use/3.1.1: resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} @@ -12073,7 +12031,7 @@ packages: replace-ext: 1.0.1 dev: false - /vite-node/0.30.1_q4uqpcnw5uitvqeupsvmeecbwq: + /vite-node/0.30.1_trdptilico3zgyulfxor3vizoy: resolution: {integrity: sha512-vTikpU/J7e6LU/8iM3dzBo8ZhEiKZEKRznEMm+mJh95XhWaPrJQraT/QsT2NWmuEf+zgAoMe64PKT7hfZ1Njmg==} engines: {node: '>=v14.18.0'} hasBin: true @@ -12083,7 +12041,7 @@ packages: mlly: 1.5.0 pathe: 1.1.2 picocolors: 1.0.0 - vite: 3.2.6_q4uqpcnw5uitvqeupsvmeecbwq + vite: 3.2.6_trdptilico3zgyulfxor3vizoy transitivePeerDependencies: - '@types/node' - less @@ -12104,7 +12062,7 @@ packages: vite: '*' dependencies: minimatch: 9.0.3 - vite: 3.2.6_2spomixywugicrp5ojnu5wf6qy + vite: 3.2.6_jdocevgq4sbitbjausmg7n6jgy dev: true /vite/3.2.6: @@ -12140,7 +12098,7 @@ packages: fsevents: 2.3.3 dev: true - /vite/3.2.6_2spomixywugicrp5ojnu5wf6qy: + /vite/3.2.6_jdocevgq4sbitbjausmg7n6jgy: resolution: {integrity: sha512-nTXTxYVvaQNLoW5BQ8PNNQ3lPia57gzsQU/Khv+JvzKPku8kNZL6NMUR/qwXhMG6E+g1idqEPanomJ+VZgixEg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -12165,7 +12123,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 esbuild: 0.15.18 less: 4.1.3 postcss: 8.4.21 @@ -12175,7 +12133,7 @@ packages: fsevents: 2.3.3 dev: true - /vite/3.2.6_q4uqpcnw5uitvqeupsvmeecbwq: + /vite/3.2.6_trdptilico3zgyulfxor3vizoy: resolution: {integrity: sha512-nTXTxYVvaQNLoW5BQ8PNNQ3lPia57gzsQU/Khv+JvzKPku8kNZL6NMUR/qwXhMG6E+g1idqEPanomJ+VZgixEg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -12200,7 +12158,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.11.6 + '@types/node': 20.11.16 esbuild: 0.15.18 less: 4.1.3 postcss: 8.4.21 @@ -12244,7 +12202,7 @@ packages: dependencies: '@types/chai': 4.3.11 '@types/chai-subset': 1.3.5 - '@types/node': 20.11.6 + '@types/node': 20.11.16 '@vitest/expect': 0.30.1 '@vitest/runner': 0.30.1 '@vitest/snapshot': 0.30.1 @@ -12257,7 +12215,7 @@ packages: concordance: 5.0.4 debug: 4.3.4 local-pkg: 0.4.3 - magic-string: 0.30.5 + magic-string: 0.30.6 pathe: 1.1.2 picocolors: 1.0.0 source-map: 0.6.1 @@ -12265,8 +12223,8 @@ packages: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.4.0 - vite: 3.2.6_q4uqpcnw5uitvqeupsvmeecbwq - vite-node: 0.30.1_q4uqpcnw5uitvqeupsvmeecbwq + vite: 3.2.6_trdptilico3zgyulfxor3vizoy + vite-node: 0.30.1_trdptilico3zgyulfxor3vizoy why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -12376,7 +12334,7 @@ packages: engines: {node: '>= 0.4'} dependencies: function.prototype.name: 1.1.6 - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 is-async-function: 2.0.0 is-date-object: 1.0.5 is-finalizationregistry: 1.0.2 @@ -12386,7 +12344,7 @@ packages: isarray: 2.0.5 which-boxed-primitive: 1.0.2 which-collection: 1.0.1 - which-typed-array: 1.1.13 + which-typed-array: 1.1.14 dev: true /which-collection/1.0.1: @@ -12406,15 +12364,15 @@ packages: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} dev: true - /which-typed-array/1.1.13: - resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} + /which-typed-array/1.1.14: + resolution: {integrity: sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.5 + available-typed-arrays: 1.0.6 call-bind: 1.0.5 for-each: 0.3.3 gopd: 1.0.1 - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 /which/1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} diff --git a/packages/vmind/package.json b/packages/vmind/package.json index 3ed42b78..14276d6f 100644 --- a/packages/vmind/package.json +++ b/packages/vmind/package.json @@ -81,11 +81,10 @@ "@visactor/vchart": "^1.9.0", "@visactor/vrender-core": "^0.17.19", "@rollup/plugin-dynamic-import-vars": "~2.1.0", - "@ffmpeg/core": "^0.11.0", - "@ffmpeg/ffmpeg": "^0.11.6", "@types/lodash": "4.14.182", "@types/node": "*", - "dotenv": "~16.3.1" + "dotenv": "~16.3.1", + "@ffmpeg/ffmpeg": "^0.11.6" }, "dependencies": { "@visactor/chart-advisor": "0.1.10", diff --git a/packages/vmind/src/chart-to-video/index.ts b/packages/vmind/src/chart-to-video/index.ts index 4b7fce27..c1dc7466 100644 --- a/packages/vmind/src/chart-to-video/index.ts +++ b/packages/vmind/src/chart-to-video/index.ts @@ -22,7 +22,7 @@ export async function _chatToVideoWasm( if (frameArr && frameArr.length) { spec.player && (spec.player.auto = false); } - // defaultTicker.mode = 'manual'; + defaultTicker.mode = 'manual'; spec.width = 720; spec.height = 480; const canvas = document.createElement('canvas'); diff --git a/packages/vmind/src/core/VMind.ts b/packages/vmind/src/core/VMind.ts index b6183aa5..dcb8f11a 100644 --- a/packages/vmind/src/core/VMind.ts +++ b/packages/vmind/src/core/VMind.ts @@ -1,7 +1,6 @@ import { _chatToVideoWasm } from '../chart-to-video'; import { generateChartWithGPT } from '../gpt/chart-generation/NLToChart'; -import { ILLMOptions, TimeType, Model, SimpleFieldInfo, DataItem } from '../typings'; -import type { FFmpeg } from '@ffmpeg/ffmpeg'; +import { ILLMOptions, TimeType, Model, SimpleFieldInfo, DataItem, OuterPackages } from '../typings'; import { parseCSVDataWithGPT } from '../gpt/dataProcess'; import { parseCSVData as parseCSVDataWithRule } from '../common/dataProcess'; import { generateChartWithSkylark } from '../skylark/chart-generation'; @@ -97,32 +96,22 @@ class VMind { return { fieldInfo: [], dataset }; } - async exportVideo( - spec: any, - time: TimeType, - VChart: any, - ffmpeg: FFmpeg, - fetchFile: (data: string | Buffer | Blob | File) => Promise - ) { + async exportVideo(spec: any, time: TimeType, outerPackages: OuterPackages) { + const { VChart, FFmpeg, fetchFile } = outerPackages; const outName = `out`; - await _chatToVideoWasm(VChart, ffmpeg, fetchFile, this._FPS, spec, time, outName); - const data = ffmpeg.FS('readFile', `${outName}.mp4`); + await _chatToVideoWasm(VChart, FFmpeg, fetchFile, this._FPS, spec, time, outName); + const data = FFmpeg.FS('readFile', `${outName}.mp4`); const objUrl = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' })); return objUrl; } - async exportGIF( - spec: any, - time: TimeType, - VChart: any, - ffmpeg: FFmpeg, - fetchFile: (data: string | Buffer | Blob | File) => Promise - ) { + async exportGIF(spec: any, time: TimeType, outerPackages: OuterPackages) { + const { VChart, FFmpeg, fetchFile } = outerPackages; const outName = `out`; - await _chatToVideoWasm(VChart, ffmpeg, fetchFile, this._FPS, spec, time, outName); + await _chatToVideoWasm(VChart, FFmpeg, fetchFile, this._FPS, spec, time, outName); // 调色板 - await ffmpeg.run('-i', `${outName}.mp4`, '-filter_complex', '[0:v] palettegen', 'palette.png'); - await ffmpeg.run( + await FFmpeg.run('-i', `${outName}.mp4`, '-filter_complex', '[0:v] palettegen', 'palette.png'); + await FFmpeg.run( '-i', `${outName}.mp4`, '-i', @@ -131,7 +120,7 @@ class VMind { '[0:v][1:v] paletteuse', 'out.gif' ); - const data = ffmpeg.FS('readFile', 'out.gif'); + const data = FFmpeg.FS('readFile', 'out.gif'); const objUrl = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' })); return objUrl; } diff --git a/packages/vmind/src/typings/index.ts b/packages/vmind/src/typings/index.ts index b2a0cfe1..aa2e8b81 100644 --- a/packages/vmind/src/typings/index.ts +++ b/packages/vmind/src/typings/index.ts @@ -1,3 +1,6 @@ +import type { FFmpeg } from '@ffmpeg/ffmpeg'; +import type { VChart } from '@visactor/vchart'; + export interface ILLMOptions { url?: string; //URL of your LLM service. For gpt, default is openAI API. /** llm request header, which has higher priority */ @@ -80,6 +83,12 @@ export type TimeType = { frameArr: any[]; }; +export type OuterPackages = { + VChart: VChart; + FFmpeg: FFmpeg; + fetchFile: (data: string | Buffer | Blob | File) => Promise; +}; + export enum DataType { INT = 'int', STRING = 'string', From ef4593a862d9c00771ebb247613fdf86426c68eb Mon Sep 17 00:00:00 2001 From: da730 Date: Mon, 5 Feb 2024 14:32:35 +0800 Subject: [PATCH 14/18] feat: update node options while build --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4a571d98..69f606c3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -60,6 +60,7 @@ jobs: env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} NPM_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + NODE_OPTIONS: '--max_old_space_size=4096' run: node common/scripts/install-run-rush.js publish --publish --include-all --tag latest - name: Update shrinkwrap From 18a66612d08d1cd182e20999f514ebdf94b47855 Mon Sep 17 00:00:00 2001 From: da730 Date: Mon, 5 Feb 2024 18:43:58 +0800 Subject: [PATCH 15/18] feat: update export gif and video demo --- .../browser/src/pages/ChartPreview.tsx | 21 +++++++++++++++++-- .../vmind/__tests__/browser/vite.config.ts | 4 ++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/vmind/__tests__/browser/src/pages/ChartPreview.tsx b/packages/vmind/__tests__/browser/src/pages/ChartPreview.tsx index a764c91f..1ac6900f 100644 --- a/packages/vmind/__tests__/browser/src/pages/ChartPreview.tsx +++ b/packages/vmind/__tests__/browser/src/pages/ChartPreview.tsx @@ -3,6 +3,7 @@ import './index.scss'; import { Button, Input, Card, Space, Modal, Spin } from '@arco-design/web-react'; import VChart from '@visactor/vchart'; import VMind from '../../../../src'; +import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'; const TextArea = Input.TextArea; type IPropsType = { @@ -53,7 +54,15 @@ export function ChartPreview(props: IPropsType) { return; } setGenerating(true); - const src = await vmind.exportVideo(spec, time, VChart); + const ffmpeg = createFFmpeg({ + log: true + }); + await ffmpeg.load(); + const src = await vmind.exportVideo(spec, time, { + VChart, + FFmpeg: ffmpeg, + fetchFile + } as any); setSrc(src); setOutType('video'); setGenerating(false); @@ -65,7 +74,15 @@ export function ChartPreview(props: IPropsType) { return; } setGenerating(true); - const src = await vmind.exportGIF(spec, time, VChart); + const ffmpeg = createFFmpeg({ + log: true + }); + await ffmpeg.load(); + const src = await vmind.exportGIF(spec, time, { + VChart, + FFmpeg: ffmpeg, + fetchFile + } as any); setSrc(src); setOutType('gif'); setGenerating(false); diff --git a/packages/vmind/__tests__/browser/vite.config.ts b/packages/vmind/__tests__/browser/vite.config.ts index 845b797d..59c021d9 100644 --- a/packages/vmind/__tests__/browser/vite.config.ts +++ b/packages/vmind/__tests__/browser/vite.config.ts @@ -31,6 +31,10 @@ export default defineConfig(({ mode }) => { server: { host: '0.0.0.0', port: 3100, + headers: { + 'Cross-Origin-Embedder-Policy': 'require-corp', + 'Cross-Origin-Opener-Policy': 'same-origin' + }, ...proxyConfig }, resolve: { From 64d5a76369fc7d271b6b8a8c20dc95bf2c52b51e Mon Sep 17 00:00:00 2001 From: da730 Date: Mon, 5 Feb 2024 21:11:43 +0800 Subject: [PATCH 16/18] feat: add api document --- docs/assets/api/en/VMind_Instance.md | 96 +++++++++++++++++++++++ docs/assets/api/en/dataQuery.md | 81 +++++++++++++++++++ docs/assets/api/en/generateChart.md | 70 +++++++++++++++++ docs/assets/api/en/parseCSVData.md | 61 ++++++++++++++ docs/assets/api/en/parseCSVDataWithLLM.md | 64 +++++++++++++++ docs/assets/api/menu.json | 40 ++++++++++ docs/assets/api/zh/VMind_Instance.md | 96 +++++++++++++++++++++++ docs/assets/api/zh/dataQuery.md | 80 +++++++++++++++++++ docs/assets/api/zh/generateChart.md | 70 +++++++++++++++++ docs/assets/api/zh/parseCSVData.md | 60 ++++++++++++++ docs/assets/api/zh/parseCSVDataWithLLM.md | 63 +++++++++++++++ 11 files changed, 781 insertions(+) create mode 100644 docs/assets/api/en/VMind_Instance.md create mode 100644 docs/assets/api/en/dataQuery.md create mode 100644 docs/assets/api/en/generateChart.md create mode 100644 docs/assets/api/en/parseCSVData.md create mode 100644 docs/assets/api/en/parseCSVDataWithLLM.md create mode 100644 docs/assets/api/menu.json create mode 100644 docs/assets/api/zh/VMind_Instance.md create mode 100644 docs/assets/api/zh/dataQuery.md create mode 100644 docs/assets/api/zh/generateChart.md create mode 100644 docs/assets/api/zh/parseCSVData.md create mode 100644 docs/assets/api/zh/parseCSVDataWithLLM.md diff --git a/docs/assets/api/en/VMind_Instance.md b/docs/assets/api/en/VMind_Instance.md new file mode 100644 index 00000000..80882731 --- /dev/null +++ b/docs/assets/api/en/VMind_Instance.md @@ -0,0 +1,96 @@ +# VMind Instance + +## Interface Description + +The Create VMind Instance interface is used to create a VMind instance, which can be used for intelligent visualization operations. When creating a VMind instance, an options object needs to be passed in as a parameter. This object contains some key information, such as the url of the model, the type of model, and the headers of the LLM service request, etc. + + +## Interface Parameters + +### ILLMOptions + +```ts +export interface ILLMOptions { + url?: string; // URL of the LLM service, default is openAI API + headers?: HeadersInit; // header of the LLM request + method?: 'POST' | 'GET'; // request method, post or get + model?: Model; // model type + max_tokens?: number; // maximum number of tokens for model-generated content + temperature?: number; // temperature of model-generated content + showThoughts?: boolean; // whether to add the model's thinking process to the output results + customRequestFunc?: { + chartAdvisor: RequestFunc; + dataProcess: RequestFunc; + dataQuery: RequestFunc; + }; // custom method for calling the LLM service + [key: string]: any; +} +``` +```ts +type RequestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; +``` + +```ts +export type LLMResponse = { + choices: { + index: number; + message: any; + }[]; + usage: any; + [key: string]: any; +}; +``` + +### url + +The url parameter is used to specify the address of the LLM service api, the default value is https://api.openai.com/v1/chat/completions. During the use of VMind, all places that need to call LLM will send http requests to this url. + +### headers + +The headers parameter is used to specify the http headers when requesting the LLM service. The most common usage is to put your api key in the headers for authentication; of course, you can also put any fields you need in the headers. + +### method + +The method parameter is used to specify the method type when requesting LLM, usually POST. + +### model + +The model parameter is used to specify the type of model. This field will be put into the request body of the LLM service. You can import the Model type from VMind and use it as the value of the model field. + +```ts +export enum Model { + GPT3_5 = 'gpt-3.5-turbo', + GPT4 = 'gpt-4', + SKYLARK = 'skylark-pro', + SKYLARK2 = 'skylark2-pro-4k' +} +``` + +### max_tokens and temperature + +The max_tokens and temperature parameters determine the maximum number of tokens and temperature of the model-generated content, respectively. In VMind, the default values of these two parameters are 2000 and 0, respectively. The effects of other values have not been fully tested, so it is not recommended to modify them. + +### showThoughts + +The showThoughts parameter will affect the prompt that VMind sends to the large language model, determining whether to add the thinking process to the output results when completing tasks such as chart generation, data aggregation, etc. In VMind, showThoughts defaults to true. + +### customRequestFunc + +The customRequestFunc parameter allows users to customize the method of calling LLM in each task. For example, you can request your own LLM service in the form of RPC. + + +## Usage Example + +```ts +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ + model: Model.GPT3_5, //use gpt-3.5-turbo model + headers: { //specify the header when calling the LLM service + Authorization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY + } +}) +``` + +## Related Tutorials +[Create VMind Instance](../guide/Basic_Tutorial/Create_VMind_Instance) diff --git a/docs/assets/api/en/dataQuery.md b/docs/assets/api/en/dataQuery.md new file mode 100644 index 00000000..bf552161 --- /dev/null +++ b/docs/assets/api/en/dataQuery.md @@ -0,0 +1,81 @@ + +# dataQuery + +## Interface Description: +The dataQuery function is a powerful data aggregation tool. It takes three parameters: userPrompt, fieldInfo, and dataset. VMind will write SQL statements according to the user's display intent and execute the query on the dataset. The query results will be stored in the dataset property of the function return value. At the same time, the fields in the query results may change, and the updated field information will also be stored in the fieldInfo property of the return result. + +## Supported Models: +- GPT-3.5 +- GPT-4 + +## Interface Parameters: + +- userPrompt: string +The user's display intent, such as "show the sales of each product". + +- fieldInfo: Array<{fieldName: string, type: string, role: string}> +Information about the dataset fields, including field name, type, and role. + +- dataset: Array<{[key: string]: any}> +The original dataset, which is an array of objects, each object represents a piece of data. + +## Return Value Type: + +- fieldInfo: Array<{fieldName: string, type: string, role: string}> +Updated field information. + +- dataset: Array<{[key: string]: any}> +Query result dataset. + +## Usage Example: + +```ts +import VMind from '@visactor/vmind' + +const sourceDataset = [ +{ +"Product name": "Coke", +"Sales": 2350 +}, +{ +"Product name": "Sprite", +"total_sales": 1056 +}, +{ +"Product name": "Fanta", +"total_sales": 4778 +}, +{ +"Product name": "Mirinda", +"total_sales": 3336 +} +// ...other data +] + +const sourceFieldInfo = [ +{ +"fieldName": "Product name", +"type": "string", +"role": "dimension" +}, +{ +"fieldName": "Sales", +"type": "int", +"role": "measure" +} +] + +const userPrompt=`Show the sales of each product` +const vmind = new VMind(options) + +// Call dataQuery with userPrompt, sourceFieldInfo, and sourceDataset to perform data aggregation +const { fieldInfo, dataset } = vmind.dataQuery(userPrompt, sourceFieldInfo, sourceDataset); +``` + +## Notes: + +- The dataQuery method will pass userPrompt and fieldInfo to the large model to generate SQL, but the detailed data in the dataset will not be passed. +- During the execution of dataQuery, the currently supported SQL keywords are: SELECT, GROUP BY, WHERE, HAVING, ORDER BY, LIMIT. The currently supported aggregation functions are: MAX(), MIN(), SUM(), COUNT(), AVG(), but complex SQL operations such as subqueries, JOIN, conditional statements, etc. are not supported. + +## Related Tutorials +[Data Aggregation](../guide/Basic_Tutorial/Data_Aggregation) diff --git a/docs/assets/api/en/generateChart.md b/docs/assets/api/en/generateChart.md new file mode 100644 index 00000000..d05113b2 --- /dev/null +++ b/docs/assets/api/en/generateChart.md @@ -0,0 +1,70 @@ + +# generateChart + +## Interface Description: +The generateChart function is used for intelligent chart generation. + +## Supported Models: +- GPT-3.5 +- GPT-4 +- skylark2-pro + +## Interface Parameters: + +```typescript +interface GenerateChartParams { +userPrompt: string; +fieldInfo: Array<{ +fieldName: string; +type: string; +role: string; +}>; +dataset: Array>; +enableDataQuery?: boolean; +colorPalette?: Array; +animationDuration?: number; +} +``` + +- userPrompt (string): The visualization intent of the user (what information you want to display with the chart) +- fieldInfo (Array): Information about the fields in the dataset, including field names, types, etc. +- dataset (Array): The dataset used for the chart +- enableDataQuery (boolean, optional): Determines whether to enable data aggregation during chart generation +- colorPalette (Array, optional): Used to set the color palette of the chart +- animationDuration (number, optional): Used to set the duration of the chart animation + +## Return Value Type: + +```typescript +interface GenerateChartResult { +spec: Record; +time: { +totalTime : number; +frameArr: number[]; +}; +} +``` + +- spec (Object): The generated VChart chart spec +- time (number): Duration information of the chart animation, which can be used to export GIFs and videos + +## Usage Example: + +```typescript +import VMind from '@visactor/vmind'; + +const vmind = new VMind(options) +const userPrompt = 'show me the changes in sales rankings of various car brand'; +const colorPalette = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']; + +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset, true, colorPalette); +``` + +## Notes: + +- The generateChart method will pass the userPrompt and fieldInfo to the large language model for chart generation, but the detailed data in the dataset will not be passed. +- In the process of generating the chart, VMind will first use the large language model, according to the userPrompt and fieldInfo, to recommend a suitable chart type. Then, it will map the fields in the fieldInfo to the x-axis, y-axis, color, size and other visual channels of the chart. +- VMind will add an entrance animation to the generated chart by default, so it will also return the duration of the chart animation time. If you want to turn off the chart animation, you can set spec.animation to false. + +## Related Tutorials +[Intelligent Chart Generation](../guide/Basic_Tutorial/Chart_Generation) diff --git a/docs/assets/api/en/parseCSVData.md b/docs/assets/api/en/parseCSVData.md new file mode 100644 index 00000000..38b434cd --- /dev/null +++ b/docs/assets/api/en/parseCSVData.md @@ -0,0 +1,61 @@ + +# parseCSVData + +## Interface Description + +The parseCSVData interface is used to convert CSV strings into the dataset and field information required by VMind. + +## Interface Parameters + +```typescript +parseCSVData(csv: string): { fieldInfo: SimpleFieldInfo[], dataset: any[] } +``` + +- csv: A string type, representing the CSV string to be parsed. + +## Return Value Type + +Returns an object containing two properties: + +- fieldInfo: Type of SimpleFieldInfo[], representing the parsed field information, each element is an object, containing the following properties: + +```bash +- fieldName: string type, representing the field name. +- description: string type, representing the field description, optional. +- type: DataType type, representing the field type, can be "string", "int", "float", "date". +- role: ROLE type, representing the field role, can be "dimension", "measure". +``` + + +- dataset: DataItem type, representing the parsed dataset, each element is an object, the key is the field name, and the value is the corresponding data: +```ts +type DataItem = Record; +``` + +## Usage Example + +```typescript +import VMind from '@visactor/vmind' +const csv=`Product name,region,Sales +Coke,south,2350 +Coke,east,1027 +Coke,west,1027 +Coke,north,1027 +Sprite,south,215 +Sprite,east,654 +Sprite,west,159 +Sprite,north,28 +Fanta,south,345 +Fanta,east,654 +Fanta,west,2100 +Fanta,north,1679 +Mirinda,south,1476 +Mirinda,east,830 +Mirinda,west,532 +Mirinda,north,498` +const vmind = new VMind(options) +const { fieldInfo, dataset } = vmind.parseCSVData(csv); +``` + +## Related Tutorials +[Data Format and Data Processing](../guide/Basic_Tutorial/Chart_Generation) diff --git a/docs/assets/api/en/parseCSVDataWithLLM.md b/docs/assets/api/en/parseCSVDataWithLLM.md new file mode 100644 index 00000000..44ada84c --- /dev/null +++ b/docs/assets/api/en/parseCSVDataWithLLM.md @@ -0,0 +1,64 @@ + +# parseCSVDataWithLLM + +## Interface Description + +The parseCSVDataWithLLM interface is used to pass the first 5 rows of CSV data to the large language model, combined with the user's chart display intention, to obtain the dataset and fieldInfo. + +## Supported Models: +- GPT-3.5 +- GPT-4 + +## Interface Parameters + +```typescript +parseCSVDataWithLLM(csv: string, userPrompt: string): { fieldInfo: SimpleFieldInfo[], dataset: any[] } +``` + +- csv: A string type, representing the CSV string to be parsed. +- userPrompt: A string type, representing the user's chart display intention. + +## Return Value Type + +Returns an object containing two properties: + +- fieldInfo: A SimpleFieldInfo[] type, representing the parsed field information, each element is an object, containing the following properties: +```bash +- fieldName: A string type, representing the field name. +- description: A string type, representing the field description, optional. +- type: A DataType type, representing the field type, can be "string", "int", "float", "date". +- role: A ROLE type, representing the field role, can be "dimension", "measure". +``` + + +- dataset: An any[] type, representing the parsed dataset, each element is an object, the key is the field name, and the value is the corresponding data. + +## Usage Example + +```typescript +import VMind from '@visactor/vmind' +const csv=`Product name,region,Sales +Coke,south,2350 +Coke,east,1027 +Coke,west,1027 +Coke,north,1027 +Sprite,south,215 +Sprite,east,654 +Sprite,west,159 +Sprite,north,28 +Fanta,south,345 +Fanta,east,654 +Fanta,west,2100 +Fanta,north,1679 +Mirinda,south,1476 +Mirinda,east,830 +Mirinda,west,532 +Mirinda,north,498` + +const userPrompt=`Show the sales of each product in different regions` +const vmind = new VMind(options) +const { fieldInfo, dataset } = vmind.parseCSVData(parseCSVDataWithLLM, userPrompt); +``` + +## Related Tutorials +[Data Format and Data Processing](../guide/Basic_Tutorial/Chart_Generation) diff --git a/docs/assets/api/menu.json b/docs/assets/api/menu.json new file mode 100644 index 00000000..e88282c1 --- /dev/null +++ b/docs/assets/api/menu.json @@ -0,0 +1,40 @@ +{ + "menu": "scripts", + "children": [ + { + "path": "VMind_Instance", + "title": { + "zh": "VMind实例", + "en": "VMind Instance" + } + }, + { + "path": "parseCSVData", + "title": { + "zh": "parseCSVData", + "en": "parseCSVData" + } + }, + { + "path": "parseCSVDataWithLLM", + "title": { + "zh": "parseCSVDataWithLLM", + "en": "parseCSVDataWithLLM" + } + }, + { + "path": "dataQuery", + "title": { + "zh": "dataQuery", + "en": "dataQuery" + } + }, + { + "path": "generateChart", + "title": { + "zh": "generateChart", + "en": "generateChart" + } + } + ] +} \ No newline at end of file diff --git a/docs/assets/api/zh/VMind_Instance.md b/docs/assets/api/zh/VMind_Instance.md new file mode 100644 index 00000000..856865a4 --- /dev/null +++ b/docs/assets/api/zh/VMind_Instance.md @@ -0,0 +1,96 @@ +# VMind实例 + +## 接口描述 + +创建VMind实例接口用于创建一个VMind实例,该实例可以用于进行智能可视化操作。在创建VMind实例时,需要传入一个options对象作为参数,该对象中包含了一些关键的信息,例如模型的url,模型类型,以及LLM服务请求的headers等。 + + +## 接口参数 + +### ILLMOptions + +```ts +export interface ILLMOptions { + url?: string; // LLM服务的URL,默认为openAI API + headers?: HeadersInit; // LLM请求的header + method?: 'POST' | 'GET'; // 请求方法,post或get + model?: Model; // 模型类型 + max_tokens?: number; // 模型生成内容的最大token数量 + temperature?: number; // 模型生成内容的temperature + showThoughts?: boolean; // 是否将模型的思考过程添加到输出结果中 + customRequestFunc?: { + chartAdvisor: RequestFunc; + dataProcess: RequestFunc; + dataQuery: RequestFunc; + }; // 自定义LLM服务的调用方法 + [key: string]: any; +} +``` +```ts +type RequestFunc = (prompt: string, userMessage: string, options: ILLMOptions | undefined) => Promise; +``` + +```ts +export type LLMResponse = { + choices: { + index: number; + message: any; + }[]; + usage: any; + [key: string]: any; +}; +``` + +### url + +url参数用于指定LLM服务api的地址,默认值是https://api.openai.com/v1/chat/completions。在使用VMind的过程中,所有需要调用LLM的地方都会向这个url发送http请求。 + +### headers + +headers参数用于指定请求LLM服务时的http headers。最常见的用法是将你的api key放入headers中用作鉴权;当然,你也可以将任何你需要的字段放入headers中。 + +### method + +method参数用于指定请求LLM时的方法类型,通常为POST。 + +### model + +model参数用于指定模型种类。这个字段将被放入LLM服务的请求体中。你可以从VMind中引入Model类型并用作model字段的值。 + +```ts +export enum Model { + GPT3_5 = 'gpt-3.5-turbo', + GPT4 = 'gpt-4', + SKYLARK = 'skylark-pro', + SKYLARK2 = 'skylark2-pro-4k' +} +``` + +### max_tokens和temperature + +max_tokens和temperature参数分别决定模型生成内容的最大token数量和temperature。在VMind中,这两个参数的默认值分别是2000和0,对于其他值的效果未经过充分测试,因此不建议修改。 + +### showThoughts + +showThoughts参数将影响VMind传给大语言模型的prompt,决定其在完成图表生成、数据聚合等任务时,是否将思考过程添加到输出结果中。在VMind中,showThoughts默认为true。 + +### customRequestFunc + +customRequestFunc参数允许用户自定义在每种任务中调用LLM的方法。例如,你可以通过RPC的形式请求你自己的LLM服务。 + + +## 使用示例 + +```ts +import VMind, { Model } from '@visactor/vmind' + +const vmind = new VMind({ + model: Model.GPT3_5, //使用gpt-3.5-turbo模型 + headers: { //指定调用LLM服务时的header + Autho rization: `Bearer ${OPENAI_API_KEY}` //Your OPENAI_API_KEY +} +}) +``` + +## 相关教程 +[创建VMind实例](../guide/Basic_Tutorial/Create_VMind_Instance) diff --git a/docs/assets/api/zh/dataQuery.md b/docs/assets/api/zh/dataQuery.md new file mode 100644 index 00000000..f2c64ee3 --- /dev/null +++ b/docs/assets/api/zh/dataQuery.md @@ -0,0 +1,80 @@ +# dataQuery + +## 接口描述: +dataQuery函数是一个强大的数据聚合工具,它接收三个参数:用户展示意图userPrompt,数据集字段信息fieldInfo和原始数据集dataset。VMind会根据用户的展示意图,编写SQL语句并对dataset执行查询,查询结果会被储存在函数返回值的dataset属性中;同时,查询结果中的字段可能会发生变化,更新后的字段信息也会被储存在返回结果的fieldInfo属性中。 + +## 支持模型: +- GPT-3.5 +- GPT-4 + +## 接口参数: + +- userPrompt: string +用户的展示意图,例如“展示各商品销售额”。 + +- fieldInfo: Array<{fieldName: string, type: string, role: string}> +数据集字段信息,包含字段名称、类型和角色。 + +- dataset: Array<{[key: string]: any}> +原始数据集,是一个对象数组,每个对象代表一条数据。 + +## 返回值类型: + +- fieldInfo: Array<{fieldName: string, type: string, role: string}> +更新后的字段信息。 + +- dataset: Array<{[key: string]: any}> +查询结果数据集。 + +## 使用示例: + +```ts +import VMind from '@visactor/vmind' + +const sourceDataset = [ + { + "Product name": "Coke", + "Sales": 2350 + }, + { + "Product name": "Sprite", + "total_sales": 1056 + }, + { + "Product name": "Fanta", + "total_sales": 4778 + }, + { + "Product name": "Mirinda", + "total_sales": 3336 + } +// ...其他数据 +] + +const sourceFieldInfo = [ + { + "fieldName": "Product name", + "type": "string", + "role": "dimension" + }, + { + "fieldName": "Sales", + "type": "int", + "role": "measure" + } +] + +const userPrompt=`展示各商品销售额` +const vmind = new VMind(options) + +//调用dataQuery传入userPrompt,sourceFieldInfo和sourceDataset,执行数据聚合 +const { fieldInfo, dataset } = vmind.dataQuery(userPrompt, sourceFieldInfo, sourceDataset); +``` + +## 注意事项: + +- dataQuery方法会将userPrompt和fieldInfo传递给大模型用于生成SQL,dataset中的明细数据并不会被传递。 +- dataQuery执行过程中,目前支持的SQL关键词有:SELECT, GROUP BY, WHERE, HAVING, ORDER BY, LIMIT。目前支持的聚合函数有:MAX(), MIN(), SUM(), COUNT(), AVG(),但不支持子查询、JOIN、条件语句等复杂的SQL操作。 + +## 相关教程 +[数据聚合](../guide/Basic_Tutorial/Data_Aggregation) diff --git a/docs/assets/api/zh/generateChart.md b/docs/assets/api/zh/generateChart.md new file mode 100644 index 00000000..fd31f6b1 --- /dev/null +++ b/docs/assets/api/zh/generateChart.md @@ -0,0 +1,70 @@ + +# generateChart + +## 接口描述: +generateChart函数用于图表智能生成。 + +## 支持模型: +- GPT-3.5 +- GPT-4 +- skylark2-pro + +## 接口参数: + +```typescript +interface GenerateChartParams { + userPrompt: string; + fieldInfo: Array<{ + fieldName: string; + type: string; + role: string; + }>; + dataset: Array>; + enableDataQuery?: boolean; + colorPalette?: Array; + animationDuration?: number; +} +``` + +- userPrompt (string): 用户的可视化意图(你想用图表展示什么信息) +- fieldInfo (Array): 数据集中字段的信息,包括字段名称,类型等 +- dataset (Array): 用于图表的数据集 +- enableDataQuery (boolean, 可选): 决定是否在图表生成过程中开启数据聚合 +- colorPalette (Array, 可选): 用于设置图表的调色板 +- animationDuration (number, 可选): 用于设置图表动画的播放持续时间 + +## 返回值类型: + +```typescript +interface GenerateChartResult { + spec: Record; + time: { + totalTime : number; + frameArr: number[]; + }; +} +``` + +- spec (Object): 生成的VChart图表spec +- time (number): 图表动画的时长信息,可用于导出GIF和视频 + +## 使用示例: + +```typescript +import VMind from '@visactor/vmind'; + +const vmind = new VMind(options) +const userPrompt = 'show me the changes in sales rankings of various car brand'; +const colorPalette = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']; + +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset, true, colorPalette); +``` + +## 注意事项: + +- generateChart方法会将userPrompt和fieldInfo传递给大语言模型用于生成图表,但是dataset中的详细数据并不会被传递。 +- 在生成图表的过程中,VMind首先会利用大语言模型,根据userPrompt和fieldInfo,推荐一个适合的图表类型。然后,它会将fieldInfo中的字段映射到图表的x轴、y轴、颜色、尺寸等视觉通道上。 +- VMind默认会为生成的图表添加入场动画,因此它还会返回图表动画的时长time。如果你想关闭图表动画,可以将spec.animation设为false。 + +## 相关教程 +[图表智能生成](../guide/Basic_Tutorial/Chart_Generation) diff --git a/docs/assets/api/zh/parseCSVData.md b/docs/assets/api/zh/parseCSVData.md new file mode 100644 index 00000000..a5b5690b --- /dev/null +++ b/docs/assets/api/zh/parseCSVData.md @@ -0,0 +1,60 @@ +# parseCSVData + +## 接口描述 + +parseCSVData接口用于将CSV字符串转换为VMind所需的数据集(dataset)和字段信息(fieldInfo)。 + +## 接口参数 + +```typescript +parseCSVData(csv: string): { fieldInfo: SimpleFieldInfo[], dataset: any[] } +``` + +- csv: string类型,表示需要解析的CSV字符串。 + +## 返回值类型 + +返回一个对象,包含两个属性: + +- fieldInfo: SimpleFieldInfo[]类型,表示解析后的字段信息,每个元素是一个对象,包含以下属性: + +```bash +- fieldName: string类型,表示字段名称。 +- description: string类型,表示字段描述,可选。 +- type: DataType类型,表示字段类型,可为"string"、"int"、"float"、"date"。 +- role: ROLE类型,表示字段角色,可为"dimension"、"measure"。 +``` + + +- dataset: DataItem类型,表示解析后的数据集,每个元素是一个对象,键为字段名称,值为对应的数据: +```ts +type DataItem = Record; +``` + +## 使用示例 + +```typescript +import VMind from '@visactor/vmind' +const csv=`Product name,region,Sales +Coke,south,2350 +Coke,east,1027 +Coke,west,1027 +Coke,north,1027 +Sprite,south,215 +Sprite,east,654 +Sprite,west,159 +Sprite,north,28 +Fanta,south,345 +Fanta,east,654 +Fanta,west,2100 +Fanta,north,1679 +Mirinda,south,1476 +Mirinda,east,830 +Mirinda,west,532 +Mirinda,north,498` +const vmind = new VMind(options) +const { fieldInfo, dataset } = vmind.parseCSVData(csv); +``` + +## 相关教程 +[数据格式与数据处理](../guide/Basic_Tutorial/Chart_Generation) diff --git a/docs/assets/api/zh/parseCSVDataWithLLM.md b/docs/assets/api/zh/parseCSVDataWithLLM.md new file mode 100644 index 00000000..778fe152 --- /dev/null +++ b/docs/assets/api/zh/parseCSVDataWithLLM.md @@ -0,0 +1,63 @@ +# parseCSVDataWithLLM + +## 接口描述 + +parseCSVDataWithLLM接口用于将CSV数据取前5行传递给大语言模型,结合用户的图表展示意图,获得dataset和fieldInfo。 + +## 支持模型: +- GPT-3.5 +- GPT-4 + +## 接口参数 + +```typescript +parseCSVDataWithLLM(csv: string, userPrompt: string): { fieldInfo: SimpleFieldInfo[], dataset: any[] } +``` + +- csv: string类型,表示需要解析的CSV字符串。 +- userPrompt: string类型,表示用户的图表展示意图。 + +## 返回值类型 + +返回一个对象,包含两个属性: + +- fieldInfo: SimpleFieldInfo[]类型,表示解析后的字段信息,每个元素是一个对象,包含以下属性: +```bash +- fieldName: string类型,表示字段名称。 +- description: string类型,表示字段描述,可选。 +- type: DataType类型,表示字段类型,可为"string"、"int"、"float"、"date"。 +- role: ROLE类型,表示字段角色,可为"dimension"、"measure"。 +``` + + +- dataset: any[]类型,表示解析后的数据集,每个元素是一个对象,键为字段名称,值为对应的数据。 + +## 使用示例 + +```typescript +import VMind from '@visactor/vmind' +const csv=`Product name,region,Sales +Coke,south,2350 +Coke,east,1027 +Coke,west,1027 +Coke,north,1027 +Sprite,south,215 +Sprite,east,654 +Sprite,west,159 +Sprite,north,28 +Fanta,south,345 +Fanta,east,654 +Fanta,west,2100 +Fanta,north,1679 +Mirinda,south,1476 +Mirinda,east,830 +Mirinda,west,532 +Mirinda,north,498` + +const userPrompt=`展示各商品在不同区域销售额` +const vmind = new VMind(options) +const { fieldInfo, dataset } = vmind.parseCSVData(parseCSVDataWithLLM, userPrompt); +``` + +## 相关教程 +[数据格式与数据处理](../guide/Basic_Tutorial/Chart_Generation) From ab1e49f00c37440e60ff915039b8f93631a58609 Mon Sep 17 00:00:00 2001 From: da730 Date: Mon, 5 Feb 2024 21:15:18 +0800 Subject: [PATCH 17/18] feat: remove example page --- docs/menu.json | 4 ---- docs/src/app.tsx | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/menu.json b/docs/menu.json index 42ac91a0..1a2846cc 100644 --- a/docs/menu.json +++ b/docs/menu.json @@ -6,9 +6,5 @@ { "menu": "api", "type": "markdown" - }, - { - "menu": "examples", - "type": "markdown" } ] \ No newline at end of file diff --git a/docs/src/app.tsx b/docs/src/app.tsx index e42c0f9b..419d1604 100644 --- a/docs/src/app.tsx +++ b/docs/src/app.tsx @@ -33,7 +33,7 @@ const menuRoutes: RouteObject[] = menu.map(menuItem => { const router = createBrowserRouter([ { path: '/', - element: + element: }, ...menuRoutes ]); From b2a544b0e6ed1f5c608f1da6c157e94369efbde8 Mon Sep 17 00:00:00 2001 From: da730 Date: Mon, 5 Feb 2024 21:31:39 +0800 Subject: [PATCH 18/18] feat: change describe --- README.md | 14 +- .../en/Basic_Tutorial/Data_Aggregation.md | 12 +- .../guide/en/Basic_Tutorial/Data_Process.md | 4 +- docs/assets/guide/en/Getting_Started.md | 42 ++--- .../guide/zh/Basic_Tutorial/Data_Process.md | 4 +- docs/assets/guide/zh/Getting_Started.md | 8 +- packages/vmind/README.md | 14 +- packages/vmind/docs/bar-eng.gif | Bin 431325 -> 0 bytes packages/vmind/docs/bar.gif | Bin 456275 -> 0 bytes packages/vmind/docs/getting-started.md | 148 ------------------ packages/vmind/docs/line-eng.gif | Bin 169352 -> 0 bytes packages/vmind/docs/line.gif | Bin 201178 -> 0 bytes packages/vmind/readme-zh.md | 14 +- readme-zh.md | 14 +- 14 files changed, 63 insertions(+), 211 deletions(-) delete mode 100644 packages/vmind/docs/bar-eng.gif delete mode 100644 packages/vmind/docs/bar.gif delete mode 100644 packages/vmind/docs/getting-started.md delete mode 100644 packages/vmind/docs/line-eng.gif delete mode 100644 packages/vmind/docs/line.gif diff --git a/README.md b/README.md index 361459cf..f5c1e9c5 100644 --- a/README.md +++ b/README.md @@ -136,9 +136,9 @@ const { fieldInfo, dataset } = await vmind.parseCSVDataWithLLM(csv, userInput); We want to show "the changes in sales rankings of various car brands". Call the generateChart method and pass the data and display content description directly to VMind: ```typescript -const describe = 'show me the changes in sales rankings of various car brand'; +const userPrompt = 'show me the changes in sales rankings of various car brand'; //Call the chart generation interface to get spec and chart animation duration -const { spec, time } = await vmind.generateChart(describe, fieldInfo, dataset); +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` In this way, we get the VChart spec of the corresponding dynamic chart. We can render the chart based on this spec: @@ -161,19 +161,19 @@ Thanks to the capabilities of the large language model, users can describe more Users can specify different theme styles (currently only gpt chart generation supports this feature). For example, users can specify to generate a tech-style chart: ```typescript -//describe can be in both Chinese and English +//userPrompt can be in both Chinese and English //Specify to generate a tech-style chart -const describe = 'show me the changes in sales rankings of various car brand,tech style'; -const { spec, time } = await vmind.generateChart(describe, fieldInfo, dataset); +const userPrompt = 'show me the changes in sales rankings of various car brand,tech style'; +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` You can also specify the chart type, field mapping, etc. supported by VMind. For example: ```typescript //Specify to generate a line chart, with car manufacturers as the x-axis -const describe = +const userPrompt = 'show me the changes in sales rankings of various car brands,tech style.Using a line chart, Manufacturer makes the x-axis'; -const { spec, time } = await(vmind.generateChart(csvData, describe, dataset)); +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` #### Customizing LLM Request Method diff --git a/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md b/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md index 6f6017ea..0ff29b45 100644 --- a/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md +++ b/docs/assets/guide/en/Basic_Tutorial/Data_Aggregation.md @@ -181,11 +181,11 @@ const sourceFieldInfo = [ } ] -const describe=`Show the sales of each product` +const userPrompt=`Show the sales of each product` const vmind = new VMind(options) -// Call dataQuery with describe, sourceFieldInfo, and sourceDataset to perform data aggregation -const { fieldInfo, dataset } = vmind.dataQuery(describe, sourceFieldInfo, sourceDataset); +// Call dataQuery with userPrompt, sourceFieldInfo, and sourceDataset to perform data aggregation +const { fieldInfo, dataset } = vmind.dataQuery(userPrompt, sourceFieldInfo, sourceDataset); ``` In this example, the dataset returned by the dataQuery function is as follows: @@ -361,11 +361,11 @@ const sourceFieldInfo = [ Suppose we want to show the top three products in terms of sales in the north region, we can do this: ```ts -const describe = `Show me the top three products in terms of sales in the north region` +const userPrompt = `Show me the top three products in terms of sales in the north region` const vmind = new VMind(options) -// Call the dataQuery method, pass in describe, sourceFieldInfo, and sourceDataset to perform data aggregation -const { fieldInfo, dataset } = vmind.dataQuery(describe, sourceFieldInfo, sourceDataset); +// Call the dataQuery method, pass in userPrompt, sourceFieldInfo, and sourceDataset to perform data aggregation +const { fieldInfo, dataset } = vmind.dataQuery(userPrompt, sourceFieldInfo, sourceDataset); ``` During the execution of the dataQuery method, the following SQL statement will be generated: diff --git a/docs/assets/guide/en/Basic_Tutorial/Data_Process.md b/docs/assets/guide/en/Basic_Tutorial/Data_Process.md index 99b5b0ec..75e403fd 100644 --- a/docs/assets/guide/en/Basic_Tutorial/Data_Process.md +++ b/docs/assets/guide/en/Basic_Tutorial/Data_Process.md @@ -221,8 +221,8 @@ Mirinda,east,830 Mirinda,west,532 Mirinda,north,498` -const describe=`Show the sales of each product in different regions` +const userPrompt=`Show the sales of each product in different regions` const vmind = new VMind(options) -const { fieldInfo, dataset } = vmind.parseCSVData(parseCSVDataWithLLM, describe); +const { fieldInfo, dataset } = vmind.parseCSVData(csv, userPrompt); ``` In this example, the returned dataset and fieldInfo are the same as the product sales dataset in the previous chapter. diff --git a/docs/assets/guide/en/Getting_Started.md b/docs/assets/guide/en/Getting_Started.md index 01d037e5..7cc03e5e 100644 --- a/docs/assets/guide/en/Getting_Started.md +++ b/docs/assets/guide/en/Getting_Started.md @@ -66,23 +66,23 @@ And to generate a chart with VMind, you only need to: For example, we want to use the following product sales data to show the sales of various products in different regions: | Product Name | region | Sales | -| -------- | ------ | ------ | -| Cola | south | 2350 | -| Cola | east | 1027 | -| Cola | west | 1027 | -| Cola | north | 1027 | -| Sprite | south | 215 | -| Sprite | east | 654 | -| Sprite | west | 159 | -| Sprite | north | 28 | -| Fanta | south | 345 | -| Fanta | east | 654 | -| Fanta | west | 2100 | -| Fanta | north | 1679 | -| Red Bull | south | 1476 | -| Red Bull | east | 830 | -| Red Bull | west | 532 | -| Red Bull | north | 498 | +| ------------ | ------ | ----- | +| Cola | south | 2350 | +| Cola | east | 1027 | +| Cola | west | 1027 | +| Cola | north | 1027 | +| Sprite | south | 215 | +| Sprite | east | 654 | +| Sprite | west | 159 | +| Sprite | north | 28 | +| Fanta | south | 345 | +| Fanta | east | 654 | +| Fanta | west | 2100 | +| Fanta | north | 1679 | +| Red Bull | south | 1476 | +| Red Bull | east | 830 | +| Red Bull | west | 532 | +| Red Bull | north | 498 | In order to use csv data in the subsequent process, you need to call the data processing method, extract the field information in the data, and convert it into a structured dataset. VMind provides methods based on rules and large models to obtain field information: ```ts @@ -111,9 +111,9 @@ const { fieldInfo, dataset } = await vmind.parseCSVDataWithLLM(csvData, userInpu The content we want to show is "the changes in the sales rankings of various car brands". Call the generateChart method and pass the data and display content description directly to VMind: ```typescript -const describe='show me the changes in sales rankings of various car brand' +const userPrompt='show me the changes in sales rankings of various car brand' //Call the chart generation interface to get spec and chart animation duration -const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` Next, we can use VChart to draw the generated chart. @@ -142,8 +142,8 @@ The generated chart is as follows: We can also make more requests for the chart, for example: ```typescript -const describe = 'Help me show the sales of various products in different regions, use line charts, and use region as the x-axis'; -const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +const userPrompt = 'Help me show the sales of various products in different regions, use line charts, and use region as the x-axis'; +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` The generated chart is as follows: diff --git a/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md b/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md index a7091c6d..bd8eba43 100644 --- a/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md +++ b/docs/assets/guide/zh/Basic_Tutorial/Data_Process.md @@ -215,9 +215,9 @@ Mirinda,east,830 Mirinda,west,532 Mirinda,north,498` -const describe=`展示各商品在不同区域销售额` +const userPrompt=`展示各商品在不同区域销售额` const vmind = new VMind(options) -const { fieldInfo, dataset } = vmind.parseCSVData(parseCSVDataWithLLM, describe); +const { fieldInfo, dataset } = vmind.parseCSVData(csv, userPrompt); ``` 关于VMind实例的创建以及options中的详细配置,可以参见[创建VMind实例](./Create_VMind_Instance.md) diff --git a/docs/assets/guide/zh/Getting_Started.md b/docs/assets/guide/zh/Getting_Started.md index b5bb0bb2..cbcd7cca 100644 --- a/docs/assets/guide/zh/Getting_Started.md +++ b/docs/assets/guide/zh/Getting_Started.md @@ -111,9 +111,9 @@ const { fieldInfo, dataset } = await vmind.parseCSVDataWithLLM(csvData, userInpu 我们想要展示的内容为“各品牌汽车销量排行的变化”。调用generateChart方法,将数据和展示内容描述直接传递给VMind: ```typescript -const describe='show me the changes in sales rankings of various car brand' +const userPrompt='show me the changes in sales rankings of various car brand' //调用图表生成接口,获得spec和图表动画时长 - const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); + const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` 接下来,我们就可以使用 VChart 绘制生成的图表。 @@ -142,8 +142,8 @@ vchart.renderSync(); 我们还可对图表提更多的要求,例如: ```typescript -const describe = '帮我展示不同区域各商品销售额,使用折线图,region做x轴'; -const { spec, time } = await vmind.generateChart(userInput, fieldInfo, dataset); +const userPrompt = '帮我展示不同区域各商品销售额,使用折线图,region做x轴'; +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` 生成的图表如下: diff --git a/packages/vmind/README.md b/packages/vmind/README.md index 361459cf..f5c1e9c5 100644 --- a/packages/vmind/README.md +++ b/packages/vmind/README.md @@ -136,9 +136,9 @@ const { fieldInfo, dataset } = await vmind.parseCSVDataWithLLM(csv, userInput); We want to show "the changes in sales rankings of various car brands". Call the generateChart method and pass the data and display content description directly to VMind: ```typescript -const describe = 'show me the changes in sales rankings of various car brand'; +const userPrompt = 'show me the changes in sales rankings of various car brand'; //Call the chart generation interface to get spec and chart animation duration -const { spec, time } = await vmind.generateChart(describe, fieldInfo, dataset); +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` In this way, we get the VChart spec of the corresponding dynamic chart. We can render the chart based on this spec: @@ -161,19 +161,19 @@ Thanks to the capabilities of the large language model, users can describe more Users can specify different theme styles (currently only gpt chart generation supports this feature). For example, users can specify to generate a tech-style chart: ```typescript -//describe can be in both Chinese and English +//userPrompt can be in both Chinese and English //Specify to generate a tech-style chart -const describe = 'show me the changes in sales rankings of various car brand,tech style'; -const { spec, time } = await vmind.generateChart(describe, fieldInfo, dataset); +const userPrompt = 'show me the changes in sales rankings of various car brand,tech style'; +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` You can also specify the chart type, field mapping, etc. supported by VMind. For example: ```typescript //Specify to generate a line chart, with car manufacturers as the x-axis -const describe = +const userPrompt = 'show me the changes in sales rankings of various car brands,tech style.Using a line chart, Manufacturer makes the x-axis'; -const { spec, time } = await(vmind.generateChart(csvData, describe, dataset)); +const { spec, time } = await vmind.generateChart(userPrompt, fieldInfo, dataset); ``` #### Customizing LLM Request Method diff --git a/packages/vmind/docs/bar-eng.gif b/packages/vmind/docs/bar-eng.gif deleted file mode 100644 index 9a63900f0154778a0e38f24a3a50a6a03f04e280..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 431325 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�)h#+>_EVSU?5ih~z$MrjR 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�T7G0HJI#Aj&DB#;S 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Ę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%0Au!=s)o`-2A!MrfKm7`$f& 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∈(>QjwNSltA6$-;Pz4!XU#ZalZ+x zN62W1^3&b*XFz8OX!H}EggToDSWuCS{cCuIR>4|Wn)^6Lr07`fGDH{$B)o;l0728|=$e|^_i;M(Z| zHF!ZKQ;|HBSTqGCXkC6QLoeWh3I^rQDM4!L$K7uD(M>iH+WP@k8JV=Fp)tkoHTzO` zMDrboJ9StllCI&}2ZcBLdSfJyD;6Tr7Grf`4D+?g_M}r`wl^gRUVg?%WeUANEz{F} zFQZ5d(%AHm$!Xi=B0H9yX|@qb@_|8&@Maf9hKPW40B1L>sc!)$evq9-AWRjh0Pf4P zTNbDvzb{)EVO1Kq3|So_k0Eo>S`Dpzgob#UqC<^A5@#rM5e&+K0>TN(6$fyqa(0I8 z+aE|#*^hNR#=r|j>^^>S#b*TFC2Oc2A$l}fL&eIZs2BmjK-b|!j2>$Y7k9v(q&_WH zv5#WYcKNtZZSRZwO8$nksII2x7DrGMp5Fo0ywsH8Ve;_dXA43jE5byKrPha-)nYNAkXkf7 z41%Lsv&`{aBF|;U_uwNJLk6GMs>K#{gN&OEbo)A!de(`oUC}_85KWaeHj^zoc@p>H zw$8X8TAKcZ@#T*mt?O)F@nplXb;^9teklnROnxM3lBo*eP@>y2CN*0N?J0DG{90QF zBH$ovq3f`j%L^QtL%o^y`gqo*au@t=q$uX*8S=_7!?;wS)zks4|jP0d>?q2eXQvG_|k%Vjg#d3@xp-*VCnjdmA7 zv6Z&Vqfu_q-R}v^wrM%Yz`|f(6Y*NZbl6;UpB{0>nDBxd>2jG493ygox3s+o1fcK> zh5mO9qn6*HfQbK7hcd!Hn3dY8s%BeP-1na~4ErKvSpAiX)!SC-)yZU!fn1Bbr6z#d zD9s&RRd(2+h#KL(;!XzvlCOr#Ktsh5bY?Ys+(Eh7W}F+FL1KUUkRu5_R-yuD^fUSLGT?R$E;#>blFn zdH+o9dSZ6M|8OU7?ZgFwne(x~;+c8dF~@$s@x$!Nbh#?%{yi^DOskAVIj$W&6(N3Y zY*QFY8dVgfeC^ZQ7(=-}xzj3*O(&hT9`S z^5PBa?SD-t+-TA-U(gDdyrnuicQ9YVJ(&l)u_4$l{MnadQ3J) z&)m1DcaK^XyVxSzmr?&i!;&_2o2mNYhjtx2ypI~C0R?&qHSCQfyHQpEw?nh zYlQtD;yI#9@PIlLD-XTcb+^ayGJ+4ldqj z`>st!p>p2ct?KgNJ|z+;(waE6G5bV>VLacn{oc+ORnZ9mp6k>RD1At37fM9f);0Ku zzLIS>9J*8N@2|kyu1GLBs@?WovxrEi$CJ&dkiQ#S1-2*`-DkjsZiu7!F0~z~6&0rH z`5@|f3AH5t?-uo3DXN)tK-XGn1j5x65QC}4n%4;NUSdj{tz;J=BXcEg999(rs_>uNEIMk1N)t=gfPGx$a;({YXy#@*1HOwaId` z=G~a++>&*TN2WGM!IapNPsE*~kB@4IDt4gURbaZguOc;R@~EO>-^m!0z?G~>v3{Mq zxF<>pJF}y2oYmWZk_QKVTZvg0D-|Wo9%g`7vcEgOH+WKE<7Igl^RA(Icj$3I-t=f( zGBcdA!;$bq-L6;$?TyYUw`1BbE0`|M5REkK4@$T}8itBiTa%wEu1*#wb5Uj^z5S^V zkCsAS-lpdQpDCX?T4wyU!qu=k*ev&;i=kWBz(@9lodL#8Dq3_Q1Y78YR#^H4WlfJ^0h3-L*2o zTS5DAvv0S)vmHM~8!e9=#P#f`R)1XWus6rP>(Ek}z$*k;0F4{*JCxunJ>DsmW=u-} zaU{4{Y1b5##QR2tRED-)@Uwb2v2-mKO)>H%*gt3yP9>!u`*h*z;KVzh@JSzNCI)z_t55>;+9LN=8rZN{ut@`E`njiu%?-~AeEovDga!UU!cyIP~6cAbN zlvQO%n_0gn=B)Lo9jc2xG4vi-rnd*qGw81aj>yL!kK6mTOPKrWz5186`ruXH#NZpl zGSdM!)@79AqlP|gmbjO2vSEpIaUE2{vd^5Cy^~atNyl6{i4r199~>?1wS!Eg1}Q69 z5ejkW1_Dn!pMnBcSy6^0cab2k15(nq0N~pkli!3=h8fXTu=Epf)4>AXkg4th0+E=1 zmjVl67fvm4v5&&!HAiA_PIkj6#BNYkA^ww>oyetwDCJc;-OAa0lS7+n71|y`kwGG= zj?a5jXEk4plj<88ln+#_Mx`{OQvy;#xyM+L0POM|WL;eQ0cRx^8mZ7IhJ76EDO$ph z5yL5gh6j9jE&QFjM#?JF_fqG`Ya7*m5d*mem3joi&ZH}DQ()iASQch`h@aqU`NA)u z8_Xf6OPfU!96#y)&edjnZAOL+%Tcbx8A#N1*bEwwUT#d+DDpohwJ$MXV-lU$k5mvV z>`iLT<$H5`D4q#`Op|^rozy&Zdf%nI&%a;Uwf+0y+Ja&|4SC;yNtj6{s@^j zk0fd_OGWa&*llll@y>j8&r?~E019Qy`|m?`j?284*@glAA5P>vgXY{ z-@Nw+y+(tPyXkJR{skN3-TRm=wFpF1hT_=A5Qrk{zU1{z|J@%gcwj4G0eMn?{K=`G zo$vg<#w=1sHEILGy+Xd;;r}#)Cx5A*`%4M{3~Oz2)}K2q2}2yiZmQYTS-sR72Lx^f7{bc}_Dput$2GS%$kB175(LuKmydQ%shS>RUCblga&|-ox zNdx5t)7U|R5LRg|2%_##Q)5tcVDUBM0SX>tgy$z;+zf9$G1wzDh@oWd9VM2hQ# z^FQmpZ3z~Q2E;Sb4v=vc9mpbK-02t$L0}g*Ohh3fhK9Xh8|wKf#L*n)VI$|FZf?1P zakqufL`Q-Q!OP|Fcm|}zmkZO;(`8Zbu;Br`nF#*r6Osv#$;M}+fnamki-bAYB!%Lq z^+0UlS`3X7Hhm@nBt%kYqTQkat0+K{469Le?)Dou!aJeGKtHLd;{LcuwOCC$5E}qj zs|7Fb0bG>e26LT_l$gxun5=-vGh9@De^`+k?B^AWwu^Yz7h+TnOL7d+3JLblqTFei zOep$BbOOc=ou3)nmKj_a5RGP_@0i2!I`iGv5S{N8h4NVmi-8 zW0#N{YT+X4uo4}mM1_+B;CoGm111UJEa9a&;Z6XGuZI&S!JC>5!>1GLr{mqZXt5;b zVkX2|3t}~a4gP1|<^zCLy-(N)=Q{^P~fw+%%L?+R>O42u=dEla)|usKRu@QqmZdj%1+CNCuEm2HFiJ zLyxb6;w*9d59`8*H)RrxFd}Mj_-q=|2-w6HYBop^zk8Lb9i@kS{xW|n4Un~{*0o3qX6XwWWMk(R}$mF_;uh@4Js@y6^_$N-JN z>R*{V$Z+YS?Cz8B!S1X9QHpI$!XXO+Klh?}!wwc1mt**9O_*=(Xc8Ck8mk&ihi4f95(IToIopRq$RHp1uyxW##h)?3|OilR7zB7I20|&U@WF ztP%LzJ7cUOe+LyM6w89NbBKDZ)n*eU8?kXcLxY(wJINAx6pl11R6GZZTbjhi02(xu zEG<`q4#;UBH6~eQj}RaujaZkZTLL)nXD*D2H(nL(8Yup1alnoY8;ln{2rJo#FWy9s z9UC(?H5;l-xU6WHgF^sGzxYanH%yAfZ@J16G|3KD3IYRKh0$ zOYxQmnv~$HvA_XG7|S_gQvzUUWf!Dlt_8vxi%9HZ0{=pVOxI82l_S(*^&|AkuT_E= zPU#^rRsf5H3AqdTzQ@dJ&n8uZW8UieoD^CU-Y}HVwN}hMX$bAXQ0|tDH3s zNHepV$BWW*s>rrg&5p3jBU6wHf>Y(Fsq+3=;v)|U@0DfLmzFzgMrTVP~0WYze2q2N!FiN8aVj=a|wMJ}| z5w~`a+nv5I@Ps1)+Erci{)`?Q1q_Ob0N~5<8fhkCF1ALrss@__ck5Lze|LONtgUbd zI+;kJR+LR0Fg9K@?^rjtUjH&1ai@}9dkj&_JD|7MDY*oB17)|X&Kp*ly{qs=RoFJn zhEWbN5eeCd`GFcTwHPzyqT_QHZ*&i0pLQu`8|uTS990ik!F!oVO9BE(zj3&#Mq;qK zZXDRN-q8Qqdymz<<4(Zx0pK|ZO2Q5IX78$G-Je=lRcsXlxs?d~J#13rbfoj~s(TRY z{t12^N(Dk>a<1#c2fCZUE-yFt2CEUk^Gva|73>=a%(uXLKKJ0`2wBG6HdS^1B(eRk zo9ecpP9AtnvW zL_D`5B&+P?$F2{zwn7S_XL!V>o$Sb+g@}5;cF49JyXc4^Auy!7wa40tOvKg8`S>Nr zw<`D2^?-@3F#bo~-ynF>NwqNpB=?JLL4Z|T5YJmV3$HtZG~ngI=GXcFk?S+zQ-NmO zt!{0*{L}|yEkMo$wJ4&)?!cT(S0%O;orxe)`M-Etqty_0)4{*C?n>8-sutjsTirui zt5%)mfOZddcVPu7ZSVx=+gt~U!&yeRinVn~_;#%wyeK^ZYfh-vUIkU?unG-SF~ZJE z*9mYts_qBcOmx5yh?m)gG3usG^c-{UJtSTGM#e2$KsEhLii@-8wgI5N4iI4X2y4O? z1UD4zax||T@H2o<#=~!_;Onxg!SO)a4Oj&RNeqOB?CvwpZ5XE5vJX6xBUap3dN2u2 zx&f!isw%L-+IWDvj!>WsvNeffFoOBIBg_D9yx#*6+I=m%BYitDU7dFPHS)5dUKvi- zhU#VxVlz-EL5G!XACnajo750^cAc;FfUnf>Mc*AKtl|D4pU*=>GuD9WvjI1E#7hGh zwuB`X5o6XwB!4ED^<+T5mS2UxEd#)9!zj7-M?O37B%pXN7rB`5u}xLV5*8)HE%AWp z*J5o3_u3MG+y?LPm9#4c{OhE=cV^Re0r>Mnqs1dvhzL>Epw>2c`!<;1K|$o6Y#Q>BlRfSeOf`{bqo+dR*ZA4AExp2Sh%Wiq@>7ye2I z=1A}={lEfAWRVUm+P+v`6b6%?LmXj8ltj553@mn665#*EHRz4F2owO?|BYS6UtzHe zyQ5$w%Utt1cN13#aG2=-CwCEd6&i*9Wmgp*JWZ>=J(xjq>oTSp0spY88a?HA%MRxn zgyQ8KcZh?LrYRa}I+rV+mElhq=UE;j9ZWuUSEIM`-rV7uQ{63|Dvg@f$2}iqy9_qo zd3~QYJ&}vGW|C1a^T73P0&#n%) zHLrZ;7F!kk>lz&Uhh1%N{kbs7&s{bj{%3`B<{x&oqkZG&;`HD@uE9SWYb$f_o^U|O)~ynAr-7C8wjb)yh#twfmeIPTc4kp3X^c}&$%IUp~y1gcf?qMsxqE` z?0cBR9v3|WJS|8p+yomPV#9PJ_>4MdxWHU+2g^jid@BzvpyeFmT;} zOX!V`N3I2Q;=sFt0M*KwqWC>u_$#FU%{6%KOT{TPiH!_R5bWs|H(^ztt27~TWU9Vd z@D?AG<8SM6qvpivHz`#=1~e+ark&%~_SE3t3E%1XQdPMs?o)LKqP&*JHwbT3RxP!| zNMp`>4VW;Owu5uu1Rl|78aWl@Q}xA8ajp?vH|TTYHcV!={oJ+;x2#%{VS=IHNLX-! zrm;midTHys&B>`>7DA!Wb1q#EzLj0 z1_Z$X*X3uzM+NR%%SVvh*Fu_L<7i5dEXv~5^08BpamMuL043Z>#m$QGBmg&qK3Nns zTeN_Uk-zSFUP>dLm(lk{r)~s$)$C_f>pTa${r6&z(_3-37p z3PPKfru$RkEQe)(U2=g?y9(r;Q`KBY@A4WGj<)*0c~Kb3+k7!d_t(n314bDM9l<^; z-=?e1oR+8m-e8@?jXu#x4fqXQdpJNxMiM6(x#D956tr5zWLRp1F;%UQ3r>tsp*6puL6`3DSvOfGEKox z9!ci!zYoMBV~kysZ67>;AA%8Iq@+6J?4u3^3$4Gp)~Q7OQ=sLvD~6teKht*!>;@_q#O&)haL zJU6M%?tkQIBuOHHr6pj*7O=`TjY+uO*z&Bn4C19$hN7?YV?K|`Sb9y(kMU$i-asr} z6Mc(8uj^3FIZ{?lG2_&@!r|5RqcvhxiDoa(`A9#%7WY)6;9(%Q@ojosaueRqr>c4W zX-SQ!x6a77w$&Ft3+-#4sunta|Cn3o1hATm9F(N*Vi&Zfdhvna-ucCD*i3V&N9=^} zQm@q6>ZOOW{_{(Hr2qY;)x1ByJV@@-Tp8N+(s$*t&gbftVS}IZD^DocZL3^U$@8lt zghy2kq9gptSkQzd$9f9sbTv>8D*@%B-|Ws`eRkOF@%P|Uu3vYJdZf5qeSYR_`_=Ie zX+nF(Y5wg$UOGH;*&BH2Gw;s#w;zHP)+Qm-jRP-2k$>MzhRX=|ih}KT0xri3oNAg( zG~3tgpC*%_`yuAyA(zh?n}u6G6m2$JpUjHNZ@HKwb`%Ag8n|s3vpR)yHFA3P*%COC zejCQ_bHh&aIhpo2qb>nn&-~rZsjW-xOIksTjV6iQ)zQxnTfYx^@C?8anV#UE_bU{c z3!QPb?W;2@$73`G1;miQ9wTeHzm^6M^47nbP=ppUI{$osvS-DL1deTiCkYH_eQUul zVTT;vG4~KYi1$}ssw;dk@n&^}X$+<)hGEXa=+j83ci8>#gHlr|F>@T27$zpc2-D1E z3Am0A-9`NnO@(EFC|r!K|x zqdtlHzcN0Xt(tY+w{*9z$B@^1ZRXJHGd^E3tsU%-3x$$Mp#vfkph{DJr!4c|$4Q;HP&9NsWTqymV6RehWs`*9 zcblIrGAZHuiE%EEylMA)XLo}zt46BY(m7X)yMW~elq^~ zaUkK8b)JHaethJwr|Ah7N<^kV*#zlXhMa+l_uEKXZt)x~k+&X|GW>M(^~a|W`zfA5bKf-Xya1+hZdbn?ob5pkO>DJQ^hSTFj0=V;DP8<5% zjvsgL$z}Ln4%!xb>%;x7I}W3_oHX}E-)?$xEB%U3!ke80`t74d7XqG{zSUB{-~PV{ zLhU@G7zL-X`=nTaP=|Q2!@yJUb zYmMi6D}!!7->4{QYW+vCfgN5#B@hj9$xX|d^jB7p&TCSH2> zx$p2J`a3`zu?MS%va_wj3Q##W%(ob6v#V4Z;T<+)s?2(I zFZ}RxfIJmIY173S!3)@s_ze0;MySA2=o1ig4!{JN5mx~xBGu?%wPY~9 zD+B@PPI7(3jIg(B|X59g!i zd=gWga5FhGI@27MmJCx@0JpC3N6kQKY~)ry#LAgii2e^f=|e|pjKs!{U8|82rLo|; zOmuTOv0VqQH;>~Ro;#qpPBo%A9ko>j-YgXdB5pnECv=&^Y=`*TnYd>T#C~&lyy=$Y z6rT)>e-{n3kKG!B5}+vzU)9Mc$rl1*E7oG$97HYs5|LBDdZyA^X`(RwB4V$hTTSjS#GLqqp-m>lz=?BxV$iQd-dLjU`^2=5z6(up^G$K0vk~+CATkEU zPgBhnW6fB}+I~qOGimdKq>X^{%D)mW@W@FJD+TNVk&8%?y5yYXi zocp*;!5F~uxhUATtAl%~M< zy-`Yh+b1(enN_sm1w3T4T=+?8AO^QyP5dc|3lRUu!Pt$RvpPiAo{(fQ2?FNdPo@k*7JoI83&N&}>=g-Z9%m0bid4cnT7EU+e!iPFB4Y*~?V4BwhNVywN|}3 zcV3kaXi!lfHIRSS^E4LoWLY&fKHQ)V#Br}_vHjp6#_sj-hNhSdKT`iT-ZLETsG$zj;~>&aIm#`b9h!$><|olr@afy$O19ANj>U zx=!hP^c(UUg02J6LR{c=P~!5Q0<&2F$-QR!DoM=p?x@Fr5q)4v7NtiTQZGcD6zmtG zl?X9mBC~O1yq7aE*bzVY-FJ}h7quayttR<{&|nPE2g>#NRYQDDCjYzwcMDIa2nezJ zpp%cI+mgf`(7v3~Ns?Wv|A+K7W{WTPx! zrN;gv2)zS^GoR_5=O%Kv5BN`-!N5y{g1TxU!0%Ly z>oL-Hbo9pP+cu~2SfCt_+{7J@*!JAMefUrw$MMY=UI7uYH6NZL@rhxt;8$MlsNcD- zGF*nW^OWH0p>*S2nf*Nsy5ikg(&PkVbwmW%R;WWyju-^r^`mk*|09asE}xE6g&y;n*|HNMOrbqG&KI$V3R* zPT+F=gxsc2-4S~z^g)+~3>y9%^mm#Pf?S7^{B36%?b!i;GMw)etJ#Gwx~&IfiL@PIN~Xghl(UnAoJzKkot z{s`azq$zdxTj4K7`!IUqXtM3eSI&D0GxBybkP_58u&3Y$EYhx1+V+HJ=#I z5egIeF!=dj=@&LFBA=xDZdy$I1yFTAn7qXcJz3;8<%G>iG%{Xr@=Y=eUj^eQ>+z-B zCHaeZ#fx8)NEfQ#Aos57G_Dvtm_`+Zpug@$W%KsIN~iYD*AQp7A=ou5=Vwgoe4i4j z0Fhk_FKO1C?-nK@Iv3Ne->n|HxOl+=877=WV?u%=OD8UVr)Kq`IM~X?@1)H?Ht$~+ zNx-omk4vD@2UtH6kp_*^XjfoGZ+D?`4clIHLCdcjq5*m$tKd{5==St`0&qp0@b%4t zFcoN6Oy5aH&V5^pf3nKt3GAE%d1I+5vzV;TjO@-|Sp|JKTYMP}pSAiud+~dD!FqWu zZaouFWdG3cwDVp-nZhey#nBI1b(ccGEiB>{E?@q;DlD~1*}jS*46bU;t!W{ww;*l~ zE~MnG#qri|x&BGG_-7XjwTlU=^I$no7A_^Gute|g2VNRya_TmW&!HJ*9bGT$TtDHt zzODw=x}x+>^VasGj;~Pku5JJdU>D^kT1ehB({{=@^8Y3X4Hwio_+i?Q1mQ52mJ}+z z1c6dhVVP1U5j_YZrr{`a#K_W7>qbkaw$DRB$%g1*vfi%V7$SsX`iUR>M-X~D8S#RS zP_b}P@m^m)_ROK)Q$=@On}to1KmVrV>r`Xz+hm|h=2@a*%oS=vH8Y!}P=01LuuC&A6sY!Un@tW_r18=*z z*YvUbC)lSu<(+!Ya^ObV)WFrb?mhuAk|2LN*k%37m*?vFbooNsAcK4)Fba2h%jbyQ zkFEME{JL1gEoaiymO><+{aTvp79l+7LMk*g{Kk?wfFIWwr!rnnLY!3G^ik7HK77$= zQrQ`mVjizH86oLD$u<$$A8%wLW(re)xkIMf2gFZ!+7*f$2lz#Z{Eel9H!tn5s86!C z^kv~8kZuquMmfCmI|f%6uDsx}+@ZWOc(L;@ja6^Cwc;okrJ16`2GB||$`7D!=bj|8 zc2bYApldn8RAlds6*R$oSKR^qg`S;<4Y$;DK;jvLA$E?I60ik{F|XyR;C4jMDhy+! zIJ&oF#}X4nn7>I!Z1#R^c=E?s>HuVCrgAJ=+0^j)=pJP?R;rzSOpmbsI`i0Z>-8q_ z6g_g6a@x_OYLi-gL1?1`fe2qZeEOg1U{MQFKfmCU6Es|f%VW%wb5pL6u*9oZ?6EKA zR*(X_3|~55dHnUrIC`8F5n*p}8WDZ{HI;Qt-+rn1h2sX`Agl{~D^A!KlE!jyJ1vzy z~@5weqE$$Q4tPR|s^sg8S?gZqRE zGOat%6z5xSCRRuX#bDrR+`CBq3(Z@isiYQcEOokt2TGp4b$l2%5i3vQgyU2*r)j-> zt*eKgDu@1b^9+e0Le%J-SRUHmmm7w&UY~-L>q+fbo*mvU7m4TW2|Co^-I4%*(7H0?8dI+bu`qMIl8jTvRIT4+SP#tm1|bkkF85*E%@ zlAAM+(sk4^lBz+t^iv;PI?-fpB?#u0?RF_KzdW|F{PKW|(N(Sb{aC;F>$;z%~3+rpi_5~9n z1Hj$^yL~KEFteM2IswNZ7D%k{)0(H7MX{q5$@hCsYsulP-n(4dUod}rkot>x{DNnC zUrDM~TC?>Tt)z4);LNTD2i2y+#g2PTMM(XlB$B;0GZjUORC^z-obL6WuO#A6$Z0mtypJP4 z{6|Uj!fX0gzAjzqy52X3JR}99?#YCJUmPR_PogJ27Md+#n#s@7ldX50{Q!z+^8dXO zVNzE*lK(NDc1+_lC&@vJ#oz3vz4`=Lfx2+kX=2%jbl7_Grm%AlF>X^`?vjP(-WwDE z>4fK(`i3ubCz1f_(jeK!cIxw{4ErPt)uVJ{L?+%dhJzGQ_x@5*{&d#MYp(j4&0a4D z9^)ZjNu;+`om-MJtoNNYEo`u;gF0-uI(8({@S$RmZ+*}3-Ab>iRHa)5$D_4Q7GGp&OfZk{Qv($aYna;5|!k;^!!>2-zia8s5;&e!TA;Ur4=t;RVS zRL_L|Lf7(u&s?L8wK|#RU_iaOan`P`o z8bbD_le)wS4T<~gZd6`p+dl9$f8(%bP90W#JXp)# zS7TE@;=Y6o(XiEee_+%$`wVi(Yw4C&zxXw`h5?toyx3dsp9JT8=Y%+cz0(m`?&O3M zr|swT^{8?kAGqro-5HI;h6jrMj(JFbOjiqT?1@V9G5=5=C_6cnciQgve0IuT%P)|M zX_rq`uJ(=W>(_=`q~e4fTUH7;#^&GU-H|!8VCsLSXAg^KYj8Q?hXqs8z1}Eb`J&F@ z_2pN`uDO5=9`*VUE4884sScdWk;T~u+O5A5qGaRNLh5RGQf}lK>ed_SzHh^qnwFpE z-~DaP5&w%~eZ$ZR>yJ-wo0S|^>r24l_)f#*v|1wuk4cH7QsxIK#%k0~zU{CN$X#nR zxb9q7Re{N>ji;_=20p@(JcE@sEsrx}Uq@Zd;pasKJQKZ4jf%(Q9uWXc)cV*lwE<`O zuLN{y%yFYFM27?)DL>Q9qT?u)p;DEl&(tG(f;`sqMLHzSi9UIl3kM3Um=0EGJJ}|96GydSJ@L)C?QF17o8xv|l z0`I^=rCsu(OqPuWb4U?t$#fdD@wnxvf~WC=CL82fK1R99v8dVW*s=2ZjHt7bM7@z1 z15tUwzyPy78MS<84giJcgbOYBLv0!kC>z7Ay{yW}D&fVcqWmxxRGbYZ5%TeYrOFE5 z=_qTWykPE_sjT_8;|dXer8pH;C*lhNT+uVvCPB^WJ90S25S$Bs)E6X>C*UX&RVR0WcCx8D_G02*#S}-|B)hn^iaj|MNf@S39V zh@U57(6Ozbwc~VnyL~iX4Rzx#D7|T71w_{6hM1i(!OIKAGP`%fhdv#ZbYbTJ;lx0< z!kM(>^w0xq$I7i24vKUSnG{Fw-${K;Aa=eEe4>?er0R>ZK1YBCUZ?w9o zOcofy{BB+&BnfCi%V~g?^>3w&>UFx7`&?`z8OYIWsC!@-L9jW45deVlZ9cS#WA?<| z;ad%mJWqc3%aNIZ1{I$3XHeRpk~!+9tG^R|sikFnCDOm;V^!FN{J_bno~I2zhrA6q z#*#9gdm4Rh&xU?)#=4RMvd$#?#LG+qJsCfRLy6yFUjCWYV+07`{ZIyTe?Ag;I++ON5Wo51#az+W95zG7;(` zcb1CYbP6vF`UJhETkdBlW-3dOJlxwf+VFR+davA)aYxu?$jrC8l=mMl9{!`8y82Xs zpOCYvkeuJBy@&63u$mL^$jh6|jT-;$uctbU>z}V)tCN;pi8%IWqQtC7B?PcL`%0)_ zUiMA#2Y0oT?~DaD+rwpog29j?NWi=U-U$N)qIBQ{$Ctm~K9&`%LUk)^8vNAABS7Tw z#?V_Y|3F0v_V-@rHST>R3fr3fl6&m#mxFr)=dMhzmtNamI$^#2RxtQS%1Ih{FNr%X z0~2|{jo@uQufZ9$=E$W-{d)ZU3SEh>(BXVj^Su5s-sdEb_1q3fXg+vx^M}VPk3yYC zC3aaz0N2k{_>b=6Kh|Q9S156tqV%UDkNX_}svY(+WHgIJ>yc3T#$ehbmTb>;xrd=j)*iR!kheU7k`TOmPEvsMu4}l?mRSb+9E7j zCuT1ib$;VkB9+g3EbFw@&;si})@yib{oa{Fk-;16#+c63b1 z-2rCEffqT)2G1jAb&y_!L@zGF-N9elEY1cHcM6E(N+vxmja$=6>OjZzjbVw=fj!PK zFD#r8ocOnWkz>yEVk-8XX9AOn!SyM@!I*^%FWF4+z$XSfC*A{ZRSCD{oVDsD;U~uI zItWP$;DRv~rbSi&zjVa_D2;_=4XG4O-4q`>x`1t8$75pN24Kgc=_OQpHa^wl1wES* zqD+Q`%tuYnCy)Wez0K5PQV0orQ2Ar{OQpDzUTIF24yS6bqln<^CZD|xJ7<}GQ7T#{hgSdvN7c`a@d6Ln`)g69z4nI@(8Pk}z;CR39H*ibmM6 zQxkt>*exK;iD`(D`&wrKgmE02lDyTe-J$WpqQOqOiX1pVUFpP!r5Bp;t-kXQ*rDPte13=z? z<4NXQOZ>wq;L&*IQK2kFZSYrS)+|pYSBnHwAuF6AWiMK0Kh4Z8W?{HxDV?V<*`!Ct zURZkqq@XXhSL*&>@L?f!{}>lBjM2$x%G7y)&yE7##fVP7NUJBoKI!IpTIOj{^CYvN zdcw%_>^vV5a@UT0f?j@YQ~b`f?4K%+Oe`O%yFAkDNB!1?R|X)=$OYPg;2+{76SkM^ z|LoFkh?Xy3AU^A4VSbE1%or!xTxc^;m&Ni7@}bl7PUHJ&fHN)FPTok@o@) ze79s$gli<6m{&xfM->%k9RE;FN*WtA73vcmSt zfl208f77d3cd1Ecq2L_Y1*@{HiJE5<;q_wW7vyuKYN4;n72Zr#VOyAc*vt>AIkV*m zVQFNIORcDD^}H&4d9nJ(<(fo%%`WMh!vu&vv*vGLU05GXo~@j$NEBdI!uO@Sm*VYX zfn7YB7(in_rb1OXOoM^P_1wpXOH4(eT95`4QmeIUskc$9tz!YY^JoYC28R~3qkcmi z6P?UK?{oVR|0X2Xmab?TFKE7uuXEkfQDrf(dulL_6)h3sS_74VSS zA`x9sJp^El^uf}n-uwz|wj6HT(kMI$^=1~;Q5q5nO`(K_`_zUMwT5Ia49;mdr}pH6 zbo2QoSasu*gRsZA`z5%%r?3%-0vi-_H7n47$~Yhl53#-u!1G!RBN|wPe7D)!Ih%+g`=hdy^p$l?E3MI&HGei6`Bjncd(p&~%Uq zyY#1Nv7%--m#|AEAi6X1-3;p#l6(B3_&Xm0?17p`b7AK1dp5s6a~fMMji> z5ZBfhcUtlBt^Lxf(b8?=m2kFoo8;BbF*S&;b5k6-X*#<>!L4gf_;gBi) zi?gto+3=I`&rkBTxu~~Uv5~UzKqwb=UIu*+kM@*7$Kf%d%$`tU&-uZoz0`JaY0b~A zH{fA!z*V@Kw4=ifh9Wf=JM!32U+C`=_&`PR@qk9f-Q6e(3#|@OJSSplfOZIaVa@lP z>{c&MQ;_Afy2$i9Uwxjx_56%MPYAasl-^TT*121N(3!{zV1`ispkJI%5~cg&cPqdJ{A>>NXTcft-QDO}IlG znc>;3Axi?hh|^g_LEYk@mIsHIuA(A2s7M;-`_%AF8UoG?*-PxTafaFS!TvrBhitzL zeyDv=9nLZs#LocI47@6yY83@QE)Ak)2E^J1G0VcQwjeTw&tX*Edy%Yq3NJk zCY&L4`YX_dV?u(;+F%^ms70RJ>jSp0Z;?^D?kIzy*PE3u{|ttkXuPp*3^z%DB676T z-S9}9kQ5DqHiih%0EZ#Saa+73wHscqe7~XSLkCg{QvA;zH|tT3Xv)e zNp&Ajw;dl9^L`=%)po`IntXHA1usN+TUZ4Zr2#ug6Uco48te=xBkgX_1`P0093f~6 z9!o@BYnyD{9u;Lxc5F|+`qivPp6Usn>hqqG;V7ok#zKR~LWag(4UL_mBPetP-5rur z6=F{sf6p6wpHVe%kh=e7IF4?N(A6c!|$NJ1v_04D*o2ogvnNbn=KxGbwooB ze}e`Qp+Q869Jmn#ewQOk;ef{wl0azB)_vIDdSh_@K!Mnm+w_pd&YDbiQggiVNfJgn(xj z`~ZZHG{-f>^Lyh7Bp~T1;1W8U?Dnbt`Gn>^ln9=Koc@H!fF#!!B_FsHeO3&Q@Yep=bkZwBTQx-sCCURhB|9OK z#0hshd!&qv~U1}MINU|VG005&yz-E6xV|hP&x&Q7LdkTESXvLnP zC`N#&=B`Xs&k`9c&h!-+`{~P2#F{OB%@86){IGEMtwX{p90EP!17v#Or5G(r1jw3z z&?66#5vN5Z0KyZ1Ko4^vhq=-K1a(iLwi@zvh%1DL@bCJD=W$V70HoSf8PK8jZ_&)14Q0llJog*l?fKzZ;a=Lgnh&m1?hIA zUF(Mh{Ygm#7zMDX2}Y6tT;e*8wQg|@Kv97_BY;4MID^)^B!m=eV`XSViZH75b&vo+ zohd)g-}~WN^JAZ&&IU(7)L0NBB#5>bM1K=7J0rNt{0W2nyz}zsUEa^&!}w*q;H@O! z)}zhnj?E3KV9P5tG*e)aEl?%=Yo00a;F>^HodB9Dn8W+^lcg5bA=p~C`G>w4ds?u( z=6C)*!ScNa{W|cSp#aFRe5c?84&ztw>fhJ`%S8M)ra5y9_-jc`EH_Sw&n>xH+i(p4ep<+?`o^u-(@d<sGa9zXKUd8cakwz~*vr)B553s>}x#1U3p((JBXZqPgNPf7GC>v{Ic z|89r|Q)auw^xyozzjWCBmdp!B(TWm9W2OH+9nSexf2A*5@9F=>5A4+xTc}ri zQ|$F$(2skz-21?`fv5kVpQY-d3W;UAvXKAc2W;9ZW&XntTnG(2ZJfyWv+h6qK-(|h z$MgUAfxo(qerIy^PyXWvw7Z8qo=t%Kfd67qW8QCByVlJ)PE!Jy4nOo!hF6*(lHRvA zZ!DdN`1m>IAM|r@H;y-zIJSEegnmwoexNu12B9C3^Dpf|=!dhg>&;gj2>lE$T%zCI z2?3#>x0q;9Sf5)AE}EGu%Xz+3QJ4zLk7!8Mc}BSS<@vnm{{!gfKf?OO z(!%u1U^-k}zF7YMKv@6A>B>sO*u{#KCsVhUR-SSqLD|Y&`jypx>F{dv@{^_27H*H) z*Z)`i08XFu-_Xzh1%AL{Pt`wR{mS}l@==YAH;yO0H{Lp5s@fQJ^IzF`M~Tw-G4?ad z=GNJZkG3DclyHnEr?2kj{FwBr^?o|8)NAYi-oJ#$-}U~^Nk!HaT8Fs#UeEyOg5okj zTQ`!ALYsm<&$-1h<~O3xK&RRO<({px@%y^*YXcerHbzfBWe670K0`5F8XRdui4$`= zpN!ej{4)``Lx@QK`Kb!Fp*K^f#f{Ub-5UP0)}mh%j}uU+_W#!7Z^Q;*^HlToj7ZGeHtafAR8GFr|EJ)DG_I+u+o(l)8$zJy5ABT;gV5%}u@A^S(% zCJBsqvBYD1!xddHE41kYmJjtnz1%MzbyI(*04>09{mkD`$@Z@!$M|#KW-;Pd#=31%_r{({%@-?IK6IeiclQ;A(@L#6 zETb-=SXg0~KvlrebkF;7XZ;GKpX>DO%b(%9P=8MDSn|;?D?;%JehLcwhb$F^!($%E zoK-p~^}_DS9Gy0|bJtOoNKL={*oOx`S*iB{+KJzi3;YxXTF6$XF8ap2n(qRBZuahL zewF6Qxu70g)}uH|=DQ?$;ed3^peEWOd9cz#_7uied9g05ZBR)zWIRIi;mpJN!MQ^z zQg*%W_~^LIX$hH)Fzu=rd%C)I1g7o_|1|Xda)aF zz-IpNYpJ1YfsgY9o?9GNoUpy=;g=~DtjzyOcf?QjIHSM&qQ!3L$PT3gdANg0<|nQ0 zN9VuhQ#3Ty^>?w`=L|_#Em|-&zig+~>R4j1vT)2;^-V0BiEGpklPbO(S(yGB`{@8o z42c4O18?OU!WX3~DR0V5Hp|7EduU$ zqAuko8jvLLm-j$R95t>uos-5Pcw@G~Wwy}f=dC zpL;&a{V0tx#1q^X?VdKHnY}k~x{1E@Fd69m$o)UY^xrEUYHBkDzWPbTQE8?!vq0~i z3ol>^V=MJ|g1Oj%JLAV3&)^dHnHPsBI;==X_zwGJ4~dpjkUO{PFA}TN?P+ugJUm8l zK^1=0I0ABQ^f6R`y9XXRVbad(LX&DE?A4)s72*Jj5E*)?2d}JJY7^%;LT8+5;!g9vJl}7*}7TAA5BM8Rpyz2&^SOWg=ky z*ZWRR?~f=T>Bh;BcrReGT+ck2Py0{m#_Tb#r7!&n)#%mSov^W-VvYN}Z*n}}mG-5u{(>VF{UKul@Ph7Z< zDR40TxcXAOdQ<1=i&vxe+9GUDW=35%bfw#~FR2$aj_z0>hI<)Y)O0-a?&k2il%Vi( z?Q>FJJ@RI4#MBoFg5>UN;Y=7D%k+>QHP^if%G&uN$JVuSvcWt+JL_@2$c>&Ow znAlhJ;vu)!=*Ku8@9Vx8IUnHERH%4eMud8$gbq%`75P=Ek0tk=swx-`k#Pz*Ej7$l zlFShWh}m!fPKe#Sv0wrvT=oY$+MELwv-0%q*u^F6ZRmVgFq+o=8V7bWHc+urRs>e5&$KeZoqKjy-&6k6cvs2b74wcmAI1I#Dvh;M zkrv4Ly~q5A{5=G7J>l~Y@(`;l%yqY=9~}F=_j9eadzklvm(RSsweVpYV&#mK*Qtpz zn1={+qTsyUk|Ag_uB;@6GsOv2J^1;G!7^9d;Ica}@X1Nu--c^lq89dzM0HcaBpMo2 zbw>c0bl~pClXqKt`4Eh|eNhJ^PU0nKu6!dm;E>=~dx8tOfzo5}Cx;NnS=#Azoc|sg zO7d~A8k48Anhkz%VrzArK0Mu=61h@sR(uY>g2z@}sp!(1S3<#)Z zIe$D1Cl`@)DI)1m)Gg0DuITX7n`pRlWD*N~ZxgLDe>;VYzKn)>qqTQQT$X1>OYr2P z0wiOSH$w>MP&a=Rr7tSjIXZ$76Vw+|z<~O_jz$>A5{W`|otOX%?ETV+^sxxaSWKNx zTvlI91S{MpgD81a0+ibC+JgtTz*@%eWu>uIjS+{V0S^mWZeRTHSPZ2xl59bIA|}~Z z8i*mr^Fj1I(gMIU(}2>5a&%~)=YEe2)XTB>$EE1g(QzUL3I4UwAAa}}>34;Ut4fP3*ckm#BbA#RzNHlL()0~Jn3 zC2{T(e%+UsN)87b4?u@AQw+vaj7}vd z5%~Bm_Tjw5`<#-*A^IYgDK?q+b!jPjzfv5UQfM^nAS*KCabQ9~tfdOTKbK^!l5%z- z>Flp0J33ot9H+yiEpJCiWku>{rM|;pPU&n# zg3JJrdi<1Q7{wwc`M`WyH~T?gW@e^WcEGPxfC`?3X0fCmvc@sRw;`7A@D~e!$_4G} zn7wtUB$QdnmR>-*6x^DU)2Ms@omWmk8Hi!PJbz`Qd4z{^zp|q^p^oC$pJ^GmeaU)v z{OHoj)JgeAzMW}uPZRj(a;$0DjlYs6%V5A_4re^O!!ozaE0@N>A@C1yG_&Ay+A+^= zYUmokg&qm&Xs(|Uuh^6MRYeFzV&!@5T1MmfVu~}#$ z7PojpSQP>z10p8@11kW|P6oC8FcQ9EJo(4>hrV)|62*ncZ+Q^Cd~0&PV>!&4$WT)) z(A-hrrdKfQRY2PS007EI^bI0oQ`yKm5~i>id@epTzwByvS@WltxIC*6HL0juX*x&B*dZLwfmTSxc-AWsGpblBfTZ)GB2+^Oz50#c zrCKq)qau7q?TlWv=WVn>P1!e+Q+aXP`0uN^9?x))R36c*YN!-v33zYHhCvYPGX~W-6A6ugUt;^oS?D zlY_%e4QOxaJ+-5?pQE>zTR$z&21_g7*V>wOalo)P-dYLY*mAldPCP(QC^!muMuoxM zSjejth@jR3l>H~Kw6X8h#<;Y}sI_U9wpFm&zG2&U$h23o+Q6gNh!nt__SA#kZpVRF zR5YtDBfN-6A_)jL>-aH=H*7)hP9RM5MR|9GmTm(b6c$OQ8)*Q$YKp7^P!{psF^q1T z*6z10^%H+OXInZQx0 zm@weP*XJnHSATV&aSPErIKbi?>{^D^+|jI?gxA}9caUJieEmOcUjF3kU*{VtSVsQc zdI{`gg9Tg>-}80`7A&%`JF(d9&i7mWv>>dfH3q?i8B!6FZ37FH!_VAcHe#CT>e8LJ zfO^Kub+?zw-mhND4BeV~6~lf7-+l?(erdu3v4%c zJ!d+Pp4^6E?VMuej0#f+9^{N?4h>)O%X_yU@{A;;J1F6C zVWPtQ{hzJDG57ZsIneDd*e5*OG0ygT4*zs?&SbmcRD0WG*UqUl;y9c#-kURyrj4v6 zjAXY>4Z3THaKTLh1ey_n40-o!UW#@EHxbM!-ySTldauGcafURBmz_CJ!12*1v&yGi zt1#JQ%u)g%y*hn$=ZC)SQGMdAU$z>#w)j(}6B9V2j|YrCYI2}jY>ogM zDm?u$97G8jV0$+sGd-Qgz#K^gjHT>CU`tupmjIq(2>D@WM#5oHOOknjF)73fh-ErFV zXo&1Q>6Y$@p@uWB`V*Q7htE7ZPR|aGDUA1ZL2^DFy1S5(yO81Y8O=ak7Wi^ac2Up{ z`AK8W&*w`?;+LcCi&-ob4EWHyb4gNT$=iJ%?mPeXEY8&@$NzQ?%r~dqDDy(dl2|N& zBjQx(%l+-kFIJ(0ccF4rUmecEBafBQ>d$Yck^D5Ej)0l|yE46s<_N6LYGSJY&h_N1 zF1D{e@zG4Vk^36S+Vgd38n;GwZP`aqZiOzc4i6u_xP7lV;_Ff1UC#AH%~p%^mv4iuh=+J`+ZR5(4*tfJ-{zT;;;LMf2AM$ zmBNEusX^$z{6*#c(A~9;vs%BE^t1RYI*#_!Itd8+3Ogpd$rSukIJs8^+j3scG*J-y zpyN-6+_j#2Te;V^G-xny&RftzYtBO@61K}uZ;vMZOl15#NExx? z?fNtQ0rr@u8P$)+nnBS_XxulGFv{98?~fe!FLxJDn+Li25dxa{3#dFRI?sy91MP!8@gCPRBe6aT zG#g%CADcOcnr^%KGv6~Sd4bXu!N1G=A(#&59P-p@7t;D}37{v4JqE{(s|4lr?jVC3 z*1i~vJJwn3SG8PxTY0kLR!*TK1YX30TJ957rtdP14ETu@2s#uB*=rD3dEf2V_fPsZ zb&i>*{_z7EQv)+mt=E`)-Ts`40qjwe-D$@U{ET=K;f;WLI}CeQf`wDK&+PM z!>m;Qu=WqAm8FJRspG+Sm5tZ09^4VHzZQY8Ew@p`-U!#S)BTdV_6&a{K1M*~io?he zqw`>s2UpM`gc%E#?&J02AkLO;auMO{_Ht46v_6!~JjGHj4GG4mxOz;$TUich`G+? z$h_=E-sOs#9y%@E&QnDt-HMY{O!iNHqKLN}e$w;U+iiV3-L;1m+IX(m)rW7@ysTSb zVxDoWgSYxepAq3<%1``m*vfsz|MDrd$CgZ6P=*(`f)~J}VpoO^eKB|};xw;U5`STq zgn&Oh!dhpXIh(zaviD&aluw!d-e=-kulo;-EI1`AWCd^k%Gvnb(j9=|?8Xt(4?n#9 zng3euFFsky#PxoD@i9uI|4QqfuN{K1!f+EHcq>OI6g2eX*)*uw=rt9njH^Ta-+CdE zV<=yJ!)l1GQU-tobigZXIt@>wLHO__0V+*UffEMH-XNj0>2Qgykk(BaT;Y5tFKp*B z1N9i_5)8y&7we;i=M$jfvsNbRSLOI1&kVV5*^!6pF~6K0+IQ9|z_s&ezb7Oh0%ib2 zh>$PjepdE=L%8>DEm5c{b!UkU1%~XN1>}ej`0Q67p?V5z_gH1ZLFze$%}ywm6(vOF zqGe>{P&3L$;Z!_C#gvwJ9&Kur4@5R*0@^$gfFQGLHH;ns4Y0sU{N`+s zBnG#;FAyA1LJ|ROp37)ktS?S2k`A~PV8^nN}@U6qgF1*AMPBo)Jg6IoY0zLi5I zw@8S?(a_UEtoyr^Nsz69-PR8m9aW6PO7tVH^3KZ@x1%|a%{>kpFFC(@v%}YEkE6G1 zpg0I5<%(4mA7pvGzD$Eik{}m{NJzS#>%{1-TpV5*{k!?3B=nC z9X!e3jD~S|;yC>3XQC4D3FZ*lyWRDmgR3~~xK9`OYV?kU8n!byZ<3TzxmyYQ`K^J1 zK~j1n*s?Zq4PV&{^7&^dieJR&jpohVNo{!Q(THhr8i6oD7>`n zN7IgG%!B~9oC9{Q;`gOqSx(#mYf@aMY3Y5ozo_?GN_LfYBXj9YQqcKK#SO-q!L)Hw zfanBUSm{RIQf=aqcVV(ijH88$h6@%;oBalnehmmUpHxc6%GG zr(GXRPXA2TZrNzNw!0sZ2nEV^{b55_bUSaAHwFp9c(-x2-^Ao3t?j!va8nRzed0Rzi_a9o~JY{ zy^C{wmTT+E3_~?ucsD(Cr#fu3Spxahwsq41(udL`RfC#q7*3ttcxGT!)b)_M8J#Nw zp?>5%lLjZfX`Jg2m?%lo+$M9sYwcOflxr248Zg*-L5Y_ghlf8S_=x~S1ulf!fxehe zQ9|d-A$L4ta~}Ht`E_X~LL*Ot1Bfc8#AxvE?<4Gx&lmb|qvH%n*r>_?%|6Sj9RC_MX4v#SxdD>MtX~-%=8`0QYQ$P)a%}OY^v;N{~fDQ zR4CwDS^PHAdaAl@e|Ai1nvrx>-0TzSTp;Oewno_{ivGM*y@^`Y!_^;?lMQRRuGg4n z=UP@D{8ciLZd$*X?bFGU9jxgRtw4UQSSybETDj!3Tzdt0X-#C7{FwOGtNf^k__#yU zdVepvM1Ad&#AEfk(zf)e=P$H=E{~UJ$GK6TDy}WBjby6aS*y|YpIIN?w_9W5JZW#j zjm~4HhTq<}nHJZ-#b2tr`R=@_)4?&l!`^=5S9kx|cy;Dd+pS4I!CTr>Uiu&b81#{c zpg94p!8fKZ?>TwtL-fmyL&m_AVZijcUAdccKHF7k923*_L!TbjT+lU6yp(uz25K?= zYvE$B5xox0Fl?Ug(@6Zie5ovvG%s~!x?s8fr(OD|5H%6M)tW0qEnoZYH3WR@a((ap zZAtdg*1AYYwg@-l@Zb9OqDi~$p8}_nM7WKYCf9$A+!6fy8-1khcz(w|8jCG|ZSNDQ zGI@&LpXGti?RF}^6JT=>G_*2adgb+xOK~Oi|LRgzAn~V{f+7Ie4*cn3S}^DkUSoUV z+C4$OnLjj~_yHG|BEJ(kD9i868#NF8I`?|we!3_`K-@Wt$T#;{MMtLC@r&B$sXhB&xYICtJ{fwL9&YPBlaSE4j_Ky|rKOAy+Yvg*$-9i%)fWSKI@>(9E z-Y1?K(_yQ(mYQ7|Dpt;h>+M|2nvak6nL8SxdUYnpbu)bbmnK_ZtJnIQHYG;8>Uee+ z$RW6|TirSkE3ziq59i1|C&E=}57v7_aEw+qIcyx^z5jUT3F>(h39GJ1BgaQ563I*@ zmK~saBRkusRIIS9MC$H(5!NfzOr<~K9yS$M%YYIJ#>3N{M2bmoPh0HPdmWvdio3XJ zCgwQtIuUuW)O2T=y^2-D!@pYjY8MucJ;FMw32juIKB#PeyS(Ja^^F4iBIt>?*wG55 zb&*e^3^%Do0KXM!0Vl9dxi6f^w7OB{jW~belJdK+Z^Yoy&nrBBVy#flWf*$G)$`*M z@bb^1kWUZgeAwYChT|t_f|9^FjOCsnVbiR%2z56(wV_dAvFiS&C2y)0t&Z2<@T7oW zaUa1tR)rpl=}y#$?M!gaSKR`I3@~)sMm~k#m$jt#R(b&4P+U1i}+_CxM zYM2!H#x7Rl7J|5^Ng%3Evq}26!e2ukPMC-WRC_UK-r+ zdnWUl8l?}8PXvw?$ijVz;nFrqw`JybekJYw(%pFmPAias={f|ZNm@@1R5+S#Du=C& zG7o?XJpkYsRnieJF_-Y$8@!#~PtzGjoWRv5|WyVL?Mnez26*tr(~g59P}q>w7FLBD_6mw!5Wa zQ0WMM-7MOCUQW>cVtDm6jcbkuv%(qX-O9pD8R|3k)SUT~^QdYcLrA{RZQ9S`Pi+^> zY-VR3WWW_9?W65koXNk%?iRg6-+Zmb8({aIz$VbO)=Qq@E%KGDBeDld`G%wx)d{Tq1vd?!CmjlBa%&VL2aRNm}_ss{qL@ zfAQ+ImKSUE4c(rg)!+)-_-; zrvKz!Zp6#h&vAwqF8Tjmi+=K_83B9_pZxoy@#*&DFZZ6ee|$bx3mQ#B{%)vn(Sj*` zZQp%QZ%+S_eQ~bN0Uyf?%$Dd_76e#3WsRd(@9_R`_L%XyaJ;TBKUV@+9WB4BI@W#& z&I!yU@qYH!Y<$n|@R>hK;!1q@_2W;+^2I1{a~1u4&ppKlH)ZEQXy)F?QNHTldpwDd z;|$nu*gb^gJ*A^}VZH%49j(0wf^+wTtVqBw975=lL*P31Br-xa-i4%u-R&j@6Xx$J zIEMii7xt6}tDx`RCfrkZ*3-<;d3BD@m=dPw9A@Dht`i+PbChOhf!4RUCmZf(+;{NT zp0K0fw_4|LpcHoR23VS*&+0^y=ff{5-+gdWPsTYyIqa@kX}D`?xK$(EDg$;}GV)wT zRG>v=mOBO(m>G6!GG0;&oz~wN2pRdnoMM8QX~Kb{Ax+T<<9%^cV@dDljdRHHG-@ndDzQ|V z4wjYgFXEqu0ISLnVJcX@$rzq>TGxqo9@znQcP*t!P4jVjbl6|zWL+S>=q6e@Gg&zX z)m@sbt`hl-48ZaLEcg?f0X@p2V}04E3_A8c2S=d;^7NCA0rz|5^{YAonen(?m}EJr zWO+=QE++v1P|u>1DFJ9oK-$S)$u-X4;)0AY3DeF2IjeNf+kA&ra73oFv}Y=&AhmTY z)ta3&rJSaC8wQ1-T*e=C_obK? zIqz=g93rOO(T#uqB1btUHe7{}NXq@>mCGdOmf*1q3mLs^)UR+Q5EKJTI#Xi4De;j3 z3uX_%^uIr9@b$nzasn(Fh(LyXW)7NzbZKJLG$jWR`6S3d5ffWM%rjHPmJkXnSXg>Y z?n2&S3>`4zf{k3!@hqg1UJ=N8f#jK5bEJBfl%}c@RF3iH6yvx`@_|4`-~ymiUZAfR z9{}E>lfi(x@Q7aCQPo1L9hp)zWdH==IB*B6q7zxj;~>^Ug&PnERlJ#^)4z8BRItA) z_KeL+%gVXh|G=lY0JIeG(?NbIw~|_tM=rkuE(BX*V3f=aU8EfcVTZ2(v9PYazY$)vQUe0?Q~8cBfkG*Z)v}Y-U-ibBwpH8NUo?D&8}YF(XjlxepwGTZH%m<*15DaxZSDSn5fZoWxg&iw9>0OC(ZnP z8!kqMnKGFm;6;^wdL8%l7_HQZ47+buZz@!LthQe48*as_!9l;#{z^mUL__pI1LaS~ zdHpAsq#wV=;=np?ZQ;p{J55K(Pft>xnpZsCKl8{uq?Skny{__Esa-N_QU~V1ZX?098F**s8wBbEiYkV59#Np$2DEAXfk5KfZ3+> zea)8H_)>i#+CX!K{>~cd79VQe2i~7HDxrO@r6CT7yQtRM-O}Eh-Rj-K9Gq;u^#^Ph znqU2C;+H#u1}xzrhjY|~7_Id_XLn1+DZ)OQ8=GOU9 ztsPAU1_JYnFPF;>woAsgBB%&&Ty=C-m+HeVG_6#h3zhcl_!-v$u4Nn9gQc)A^c(KA zT*H)gC26_2`**XDL8o|7r&Lh)NBwr`sZLp$t|e(K%r_4#We-il%$Q8I*5}a^UDND*#ES=>ZxG&`JM1}CTLr5CHZv&%c_XgR(@XNp%O7~HN zzVNG^Hg5P58X(Dw&AZ)<1qr~1_!swEv3Zk@;s~c zg$wps?$!%^xx<&I@RyhER@Xa@%HhF6u=ZiE7Pq+u*9lHYSA&Hhq4Sf?@ch-`FgJWQ z6Z4QWydv}RyTQu}779(wHzUH`f)Fnrz7W^1pIaQ%H8!;lsaFgcLbHeXD%tO+*mYBE z750uZdSG^XIU2R)+WuVMaMn*uD`_!#8GzZ{`NUG5O&%CdOLhrL{Ze82{Te1{O3~ z7*b!F(qC@3zBQvF(99yWp;rpVwsOx!b@_x38sf*NUhA*C7FZcQY>0Ou4~uBLF>!w* zyo{^|?SKs2x2ZQaRc~zg--Z~zJ@Fp4k@@!2(AyWwZ(UVK4fi>E?0d~`|Jtx_l)5si zlQZrU426wA!MUNEJ0}8c-!xa^vWR02RhV+Z+v>K7AR=(m_K{1~ScChdQftu<)cAh; z(G)|W^aQ~FYQw{!aZTbtZ!i?P?_IveMB&O5+wjeu_wUdQ%&{tL7Uliu_5@i2lg7hO zKDNz&>OC2oGpWolYBdz`2glSSPPqc7jP3*K19d^c&Eme}_2em|73kLc504E7auWa- z4tB_$gY@8hGQcyk-jDOY<;#6P?T(q=Ig>@i2k66{tHw6frxjuWa{~12!)evpX}*!^ z3oQ82fjX=mYr_zqx{ZGjjQf)_{`dU{Z4c;N1Ps;wamaQ8WY=JwoHWLJL8BQ5!x=OQ z(5KJr$bC6iH6x)m`_Xh3mFJHLnf)9ovK9dftU90#Gy!=7L8)`n!P8Ttph-Nr}KMkGUXC%&O z)E_(o2fvP&9DlEi>@jb}?_ax)zUCQa9sv+%4-~zoVRBW5qs$t00MX(5{jr}4_TNQ; zU&>TKar`^7`nzg1&68(4br`J+_TO~ue;8^Va)4Bo^h47uFJ|o952L&|`#g+5&kfnr z5)T3&BYw`7>{};B+f4}HtKJ~mL%jr!GG&ems1S80m@yvaw|L}FJ@R|D1HS^MhY_Kj zh^D+hZ}R@MJvjWe0V6H`h|)Oj%{z>y?q1jW&0hI;!YAGQylJbsibl9Oa&@oO|-8ZSkZ{7W_+BWouwvmydrwqhe(Dh6Gqt zaJPY4IM`r=d9PX)yd?j3gKZ)|48f%ygceU@#P?entV49L?|{)?h?DN2T4{OpC4mZP<+F zwsXRRyTer&>-a3$c0M;*$+NH$0c}Kwn9<3X;h77@O!B7$-Z%!kbw3ToB*78`d%9qNFz!4qH92SDLzn!3+#_8y} ztT?Y{>v}l}4yB!K-e{7ztrJvc|4LJZkRL4T=SOR=bL_Wo@OHm~XOJ!Xw$B zmKZcKiAC|q;f<9`MrEj#N^uHEUClU8L(uYi-@`9zh@QXc1v1q4iks>j!Hn0zR1@PT zj9`fH<>3c{o~_+%!8d<>xN+kq^^1iqCgyg&LrA2wpC!hUvry=ETFR}Dn(rM_PbroZ z{d6+v|NQ3Gp86UDY)mvY-h6RcU*&ey-E_eMuGuhOBBSA57$nmOhq(g>pOPA3h@;<9 zP^r2o`Rcp6_=F(p?G{&hr+9k2_YF%3^&iIN-YTnJ;5IU5#Ne6EOYpbeuNS|ga|+&f zM;P|<3K>Ep_cl=5qjjs;CXAkN>GJJPDy_OF2g)r&P}4fRBs5qG6C8SK{{jimAT>n7 zBc+*!3-aGyuy%cRKr?S|tKAO-BYDT~-YaW<=kGlo%n3iEIgJh2Hh1f{-GS($ADP~N z+NkE&Vvrg;N&*KjeqXu9sUB`uy$rZ$CVAk5V;P9&0vZsAVaNcpgzX~b4AJ2RWw;;n zcj~;`txfMm7vF=@=h=im=cg^Re6Y*o0t|4H8H^KH*9xI{cyylTf8(!&o<#Th4TUe=$Pw_jt7r!D^KhK!wxR3_v8sA?P5q6igx$PV3N6MX7wuDPhmxtEc(>`53h5 zCG$Jg8Xf+90$hG&3FY5Q2lZrPxJR*PNs+*bDayeNmTg(LeMn~{(Kh~P2Vmk&dNMv& z6nSbKuCI>+AyPn?i!OjLL_ljwu;Gr(B-k207&#sc-B8P87qh z&k^=6pdeBuz0_bqdc;78uy6*A@l_T$tcgUUTVr&|XYxfhZw7~+it*LDVu*38F(=2q zWCVc_c2irBM_d7*Sr?T$jpY;YiXIN3B&9XhGSh{)$}>z4+?nX%LIycB3y}AozX)>{ zt;dGAUS&aAQJb8_w3j};=AFu>h0>7ifGia$Obj-DBysIxyYP@)E z9DnLF>z-jx>!lQ_Y;nCau>(ez+K5wy<Sjp=V8rJp)EIVYM&}&Z z1c|Ep3>g1xTJp+OfqN~?SfPCODinn))1-5u< zePGS=e)qCQGIX#)YGeyVtcSM5gO|EByeB7%Y@IK%fM?o(vG$mf95T-(K!x z(dKlORvIRDmm!X8**XN#(Dz++59Z1H{PE;3slTHD;eh^@kP84$nTvzkQPs`iVP{}G zcNt#fWd~2Gk_Rq`8p0evBz?bm_+~^GlL8PTTsl$WYI;jgjKfJW(l2%YwpaES(6r*{ z&9S^fN@%US@Q$P+byooo8Q-!#ntT|p&F1)%MH<3vEHgm|K!COL=A3s`h7p)s#g2qv zloS~fDT;8>lioyHkRd_2kIF2htLRq2YpEaKF68zT`ufE6Uhxl9(h+abkk@4VA@0(@ zZ<;uso(ol`h454#cR4Gyehkt7j{70SY{iJtdu`|akD->2_sspk;WTKkGI>R|^8Zq9 zR2yjb@TvxHB$R!d=t6d%q-8C9(Z{RPvLsf#zr}|jD?v~AcK5w2<~}crHMX(6bB|E^ zeDRy5ff|(2E2ifR|8bB(AIEZncSY#Riegj${Afb><3PT3tjdsD!o!5tTl@>tk?PCZ zi5WB5YcPnCIxUpRZv<>F68ak-T>2h;IdBnnMp=9LTS7B_Zs~I55%{|!9)EZ~!MIY& zWi31_jel_Kjj2(!SLIi`14&^Q+0pMceBN&wZ9iC)`Y%oj>=G0s|QpJeNNtkULp zp3$}S#P|C~^CDf{?4#U8>VDS!(V!$o2A0tYq_$E*cCQQv&<{8NPSIcZo@f7U)w_`S z@)z4Z;*9#HMW_FCmfp9@$fw&H0_gu8TKoxO;GzFuU}gmG|5s@7`Ad8vlvWkJ;jlW8 zAaSki=HS2my#EO;rebtZ>e0kPQ26@K6xV-+7E=yuMF#Us{%>ee=>E`@%jL@d#=ur( zng&7U6kKp3it*gRn~p=tZ&~=un;Kk(JSd;t zeN@2xJR`O9XB_be&Wldb9}|jWeHEPA@~FSTb*iZKfBSi|k6V@@(^(nO;l(FEcWifK zgZp%QpZxsKejfY9NE!r-CrMW-1OIhC6z!j8BsM%iVG9m{;K9&hor0|q_jtF1m}!)+ zevrfh$FTfp6bAo@?_X$fQjkKzp(Uom*_d)U1;g%)G{)k9yCs70pi1lP@ayx+JB{C; zr{Wb3F5WFlxvSuJTWrj^drb2vta&xvITd;R{M}-!i;P3>zpiC@UXKP7hBt4mfhujY zxe=3k4GDJoF5Lo`OE2;(*QcE4Y1jP!?dM5_7YH~mDG7@P4z0M&^+N3jH_NNJ6pmap(9b*kSn>JV2f?psvS^O-K+@9 z?Rr_MZteK?&fxWX?iuZ>!xg0^7bM&{-rIpHt(**fMSZtV>q8r&m1pfiX)XNbdLQrU7Pq&U zNc9`lkD#CL4+6tSwF6R(45^(!n!5N9xVE}Ks%)Tlu05K?_F z%J(nO>{v{g8C<+posk}=FeIwv9&WT_463xOY)?c0?3B^o2(WjUTI z*;RS(6l?4AC1U2U0~_Pr+23C)R(SoNtJzn1)!Smoe4Bbz3rD*$JSzS@+_z%XfR*;U9;L{ZjrT9V>A#X|;e_SfuJ*|D)wuYW7nFr;fTy>xMUI?8+itmWo z1=0j1aPAfS}>vuUE^@D$hFxzwL+_#v#5F#ozN{fBBCdQKC z<*Nh*UG#GGlh=O=aGVl-ii%}%N5hWX%!J<2=5Go9b%Ly|%5RHP2=RUlB1vI~6%rk0 z>W><_1!x8bL{*q=F(Rqof4u6Hu&#Zc9{0SS5?;+$Yi3PMzA0wVEGRxHYh4nEPJ}~^ zWulUjYZ%5MB8VaH4=iC#=BsCK4G#YpVM!*fuA+jGO(sA0(_4Sv#s+T;-jwuA8;BG0 zxMLN5yOxYw z#rXe_IxZCFD6gnYlB^Fosw4?F|G9Nk?D#W{8v4}Buy=rmBSk#bBVblCYL2}8p$}-EeB#U5l z4};w)N#mK8>n{@yD)r8k^4d)pSsG8*)4@Y_n<@=|j z9)IXiWfy&@hjTygdCkK)t@U=L+e@|i zb&u)h*_53>5v`wg{To}#Zim>+APjTv%+ywk=zF&hFRaJ>!U(8DJsBIGu~p1(pSRs( z&m_TpHRC&gX|m6USo`DM#?ED%cLh*hhr#$TP74WaK*l)ygr!$JP!7CoG=m_~IOu&x z%9H-S7az(}n|3NaPlupo7??=l=WD$)ct{Lwm}M_Rt|;_+>k8jWBeJlDazkVs&)jf< zxumIA^k)s7=!y`twOJQ{Ag3HIH#Ps(lL@dGS*}KtIhrgZ#MQl`jT8!)U!=ojrnh4R z0`;lV__lNQ-cp3i+lRe}dbrcYo-aGdf*huIKztk=b%DcwB-isT0zt`mGw`vV5s%Lm zjRn-`3)_?CAE4pq05c+#&7TrRM7rO-jOl*gbT=HvU5PjFWe4gDyK!-6@9kaUer-D2 z097AHo#VK`6vqF9C<}=;;r(!-I@1!oi=(#WVY-*=?9 z88p^BpON7RyjPg}7&u>1@l*=U*4o;g6$A*ryBT#MAYita_Lr!-U>q&s*XQ-1a^15U z1m8}cIRv09$bIF3?&sFoG~C-7DwdlCmwRR~(ga%qdl zQJPel)NiLAhOPYFS4pSiAiYo!JADkCq@A>;8+m=HJk4NwA+0E=NT#zmNs^6dGq z5ZhniPgBT2#1m(w5dPaC#}>3l{XUY)G^*pLWjI4$7=(#NB81j$l+!QI6g|>X_E)6< z05;58DO7*fyE6hfS<^CU3}X=WlZXnzC`E+N_~5@k^G%EJi}Xc!dUsy;y6G2cmws8m zCFHbW#O)H8aPU9%G>j67=Zp#-i1_>S!9(T9Bi#s$lE1rnIF%|MMc|Bz8IK6(jEqVT zg=zcw-SyK}4o^f!6Ai(w6FM~rkmDN-7qz>F2eg`^!o6P(?ZUIiBizJAI9dBiVf8`K8~Iu>DWD;IPEXT z_w*cJLOo8!E6VG)$|I{ZRnIivjfCvzjEpm>2z0vV%!^R2^l&7@>l>zCk61?gBr+ix z*mD`lRvCoTEImY6lk4-A(yWYTct%Fn>F^hqj50&4vIitWX~x+Y0Ra%9o(MuEF;FBR z;Qx(F^_x&bvo07@?D&||^gAbdCP#^iMe{YkC~(bH`G^F?NrP^7dMsT#k$(S7-XNLY zeH`GzvfOv{SWC}o{Z3Ctg1zu8m@08E9kg0=5uPuUKN9`O#O~k3a3e$yA@gZ4G`I#; zQ>q!@hFS5=ox|vxtV3|)} z14#VGJ1wBRyxWprM*!$4?6fce7Bk?X2^M%DF*-pC-knEL1HsrRjvT0 zWd*^KMF>n$S>|&E4BEr9sKL7YO<7U?Aj2v2tFju@i=*-a5QBMw5F1rN%1^4{fHJ?5 zAi*?1JI<2^^b74Vm7oYJfq7MYq#|7V>e*33<)GBqqBXbo2hxCanM} z?zA9_DODg>=XFCV=>s%icNGhtaI5@qL}O2esbkCLP%7dO;&SG5B}^4lEWpH5&Pb+> z_OE)AS*5Ik`p2*-RW(4xZElnZ52^xR&5MFjac$ z+ac!^#g{4>|GZ*S%T+Rfx>Sq2(U$m@V6v8)b} zv#;BDs$Km50c{OjO)pQgomuCgNt-=^R-Gd7PK_f=job5H3*3~%qSpQ)phYyl#j~cJ z@t8z^L;`i)pnwjsfI4xLI?m4>F2+ct8SMQL&B58`gMfOGV;ZH{O6r^v&F5~Jng&Qd`xt;U3NGu6#UztLW0X+501_*DbF1&lc=5@7v>~!Ul&H1zf*{ zRBf#s4603QUGdg)y#E>R0RA&+^-rUgRNrmWI%g^`YHzb^!uX9o?_g3KpugQ0@Xgw@ z?X1xey?0=Xk7++$9N>Mk-#-p;CboML+e_MpPQ?wKI;I~*Hf_XqMOO@n&{yl2!gW0B zlRgh8ZNp?K%wDHS8G+cB+k-Eqh6Vy#p0xFQ5Z_j04^^sDyT{6Rno6U$`&*00zkwIRbAzmIC@<^G~s7KA%pX{OI&!lZh z^lQ^T*tgNe`*kj+?`{#^G0cyzXV>*yGDLwPjI@A340AilfbWPIm#aU zL_hpFdjPJ{7adq_0P4RuI3X4=BabUk|I&a^-a~CdTYIF4xtxPC!6zfI$0;%^-($l}<07uG%(dbxd z`E(iYIKs2~%Edlf5J8iW*G7@%8oi*>c!N@Rd3X@e; zHKyyHL!r#HV{K!1bEb{r0kOZ+k~x!$aWlkIpI(vZXliDjX-wfy&4yo`#m3Ld*39bM z0uTTXLHd1-98BI5T-u@y3>@+x&vnFqgf6{r!PU`TtnlIcH1re&(}qtUeV$gG)y2+- z?R<(kH79dzqE376b58#gYT#T_`&<=euK4~Cd%#esT94Z)hUt-y{ZD6x_&$wjpr4(Z zpEjObWUGmiPdgNzkLkk zuhXX0StKOL^vi%{0nKFrJ0xERYUs^OOC0)8V;;&pAsjqNy~uiE%SJ1MR_cgl3nnuy ztTbMP{mLdU%|qEWmpa|w7pwPxFR?*>UW{87;$JqiTYel5umCj^L(9@0=yRGYw=N{X zmO5E#wHwJRcM|4g2xM^#+8Rg8BD17tx3qNzEl~AO>Mg^6_4im#8UN~=@bw?b2fK3R z!_s#1aBA@S@AWT#F08pEtRZvPn&Sa+qM-Zk8mQ8;F@7as(NFD=nUsxukFR+rUwx}k z!6y~rCzCdI=on4AI7V6hWgRfX`zC0sDR=AF{jGZm0EmrA{M&cjr`t|#8@-#`b|1}` zK@u4^Gb!77{Gjj(zJ}h^a9Eek*$L~|0eH4B@>|?jw_0-NT65Q$a-r=fTU{NyUAt>N zcH55EKF*mmwWZUNdsnY|PYG6}N>#(OcB_o2-Df{8#TZU=!~|9okEKH-Zj)gDdr zfU+gHCi#sSG=EtaDU6rtHTS-+cToNdgLj_nI^wo@1ZZEHLByH%uiEbmC+;K6ko#5p zQd;PMQ{U|bDCG%2we*DIm@KsBJ8Rxgx6AbOTHn?^zA@o{bnw#}F@fRVZ~x99F!a|J ze_gx0kCEL6`MxFwE!VjdLEX0%$hh4p>oWG;E$^p?)(;PRsIcHKYwRy0>Q=_$?`|1% zU?Pw}{&kh<5KsMfQ)~V2yP24=1EGmS-+~_1Y`~#|IdSi2)8fzM#9i_6KY}E7!)lst zt>fOs-#r4f(pYq$>_Ni#aT4}ujCx$KcMMj1SxB#C@(w>G9)?j9DpgMX8JGJ5g&ZJo zf8KO{Z}0qbdhF-v#Xr0D(9UPVUG~R6w2tqbLiu+dPwX8ZFCGI+hD2c_#5x8yF6`JX zh~N>rdq@$4vNEFWdeg70=qK=L1c9MN5Ce-|%+<}f`hP=)-6uWeovmu5)xG)$DE&kOe_9cX&MrG8?Jqz?Q!6~kA zo*Vx{i#rQ%vp9kQI6aP;CNSi>*-P4-h;Rtq@kIobhIJQ)=C6U!t)dN~kT1kXGA(^lCV*Nn+)9_Q+X0(s)j}Vx$isaM z&uXyg$wR|`eQuT2=W;2m)#v%rf|JPupLxPy&lr|M=`xLlkfK5g=LXj@<{|G=aP(I%kM@x}oX%M0AL$m>V zZ)XhQ1ybR|TG=#BR$9g9ogK7F_=r>YTW>enggx%rxf%U$itD!|0e30Q?Ke3TqxEz4 z7959U2~MD^B?+-7p+jy6TI!Q-^Ms{0uOVdjUy?(8*P30lwka_Bn5r-N>)bVZM|X>2 z*YeF{^CDE;O1~TLPz!(2ZYXahgdUSttJHqBXwY3JWZbF0=ker@5HkT|tM-^ybvNfr zDi1x<%rAJo@RuF80$dm8?bbyn-bNvuvpeHi{rXOzSG6>e99(Nt-1bn=(v$1aNH|f% z*mxV5Pf*=l5B)Lm2cdC5M3U4V@c+1@>Qj8`6=>to$P)37ZT*St^qh2m?uE6y0fLw3 zY#@*)Rt{aE!{=T2k5X%O@GL62O6`f0e+V!CsJ00_^=4J|&WYr7Hh88%df?Le^w&o^ zye$11)gfplT4~|%ccL$VXH2H+-iMd8twRVjp@tj+?@6>f2im6?!!SIvU_`{&jPXN( z;nw~eZAKpomF6gV_K&Xe1(tVoUQv&bd_Nnz*)|_M`~B!L-E~q3@DA%Q&wxSSZ-QdX zmH`$s3@rQ*Co~is!kX+r%Mt-?a~%)mj|(X^R@RfeE+@zzH zY$DZhw?%}RCM@;gEO;gdGacS9$_A?Mykvz2FsBci3^dPudk|CagrQL}OxtD@w$MTH zVR2wdndld%JMb;RfDVOmfO5F@aGh^9x)jqNe~%!{+l2?NL`)`&9cCeZrfXk6dLFIL zDIj=T#l$*E7YauwdR-R+%&!oWI*vuL%z&x>RRDIn#9EA*&~|%G^2S-SJNxT+ldDyZ z$urb8u`?gchVH8ZiL8*XhrL|yJoV+A1S@W%K4AbGPm=Cr>&Wzp3E+)3B5c-=BWdmznE#DfO)y2Gq@fgl9Rk)hN zogI^{aE81xLNl@BNSZ6hHhKq{Hxi^ils==`?xh7R-pGl1m4x6$#cM446jN(s<^ie` zh%Xtl|kpDxNK4?iRR4fVK<%IAoV4>y?VKfZawK#C!{I3K$ zv9&geAErErqxn^E&;Df2MxN_I0VyTAhE8c`SHB2}7=uM00y7otGwYJNE_pnB zk;nT*?8aFbS87+}`HB$fXS2hS=vovz)&kj(-tOWfo8uRKi>ooi35kD{y`&C6+txcm zVY^`DWg-m#;D(wM2-H0UEKb8|(T|f}sISo+|7s$9!qF;@<5%=sCYf<~+S#9Y1`?T$ zdmIP5z_)1{nmI_E20&-p9&Jwgfbcx;ZpU}ea!L%+;Qgq|n@^bB(hGm43BVb#+l~U( z6NZ|P?c;iY(>T;shFPFN9xZAlkDJWUFM=`vFg6nKenHjU4w z=$GF`0^EZvhxrhH8I@RPfSwJjJju5J6!v67*c@;zyrkr~YYL9n^CW0%FX17FuUGBq zTH`3aX}P2y<@TpI%KRs{Acg8H2%}k8#N+R=l#E?YEBq)MR)lUOOM|J^&`m1Iyex8_ z5}9{d1C34eZ-NOX7~q$;@(<%GLiu(q4OT_9o{T=Q+mB78gT4<&dpGF(D0pC?reA&Z zzA=|?D?L)(S(eGaHQ{7il5?`==I z?XQr;jca*)`HB6irdo;K%9=+Ddz#RW#lKs_J^Y6_{I+b!-%r&7kfCP=>naxlo?ycG z4_>t&f606Pmt&Di1;ehG)?5s(ZYwGmE7cruhK84=16LTi(Mq?9K*C9=2GU^^r`k)| zLK=;@q)VDqR!oO!Ci{<|Bp#QGT;GS{QpC`CkpV17_}H)Fd#7a zzoOAbAq-sg#s6zk5a|*GH*WZ!NkP_NGswmNA>C?uPX8@Dzj8Ze@}}Zr{oSdnfvV<} zbB&%WLl#5qo1a_#zHiPCKd%f;Wa5{yB#}uFSmY@QMGU#xwu2ySk~{K2)}f0wBIoe@ z%1pIY1eaQ|X-mV#l*X0}7Td*Mdin0ToIzF-(+bl<53J=l`|G_$Qs{&Cl4Ly8X3}Xs z_vxKC`<7!t--4w6MWbhP6i;GFT`)x9Id7`APDkKx)78;l?rn$1Kf!49*56tFG8n8j zIb*Ri?@cY;!4>gEJe>WI?P-Drmfn9&ZUFOa(ri2{7@QPzy!HbkL4wXvIBY^!M%&umCKR-)2+#k{!-aa?1n;Sej zYWSiYBq`hU=NeBgoO<}E7E#mCYvgiq>%*xBbFX`@yehArcAklmfx(_gnMpZlNu#H4 z_q&&K*;+1nak#zOsUFy2qe}f+eC>0kv0q4dTzVB;mXL!xW( zAFx-7Y+OoZy6;aJNsMk?k9<&Z#MK|`LEAE{RQ)$;%vZ2|DMZQCcVGCygOjB9TM2DT z@0lK`{N~D&eU{KTm)o@IC*aY!_hoEPD`ulLXL*)Gv#ZO)`P-j7=owbrpF#R(JM|&! zeIGh$tO>YNak)#R8BMq;#hrseFnIHoc2~wY-kT>4#v;+peqB5i+9lA)Ac2+v9KvNr zmb?v{YJc)og*LSc(o?++dnXkg&npI|dWn71%zhmuL>>5Im~oLs9Z{ zC4y_U*Lk*b1UAH)bp1WOo~jj!OoY5?;iEiF{lPCFdRI^9(*6ruqeA$iON7!ilg|Zs zk!0spqjjsX#Fj^e@ba1q>Q(!xSI!g(EjFrMF(z0m_ZDGGuNtX#Gry?)ygEl#9JzC@ zDEYC-7apbSL-7`l_uq}&xoSOV;JUz=+1Vy0|Jvvh5ijrDw)*lHSwhvzzb>27fK;+~ zZMI9g>aY^`O7p=(>ZJ$9;{kg*c(q?f<5?r8a}JKzG~QkxkC-mZYa0GDbMsv#ouO7sv-Blpi5 zyPbPiss7V2KLQGY-?nBl`Pe&@QkyOs#pcFs)%Nh9O8#%y#YX)5kxU;6O{vnwuJ(EPvzhwA?a-nDci3O_7W7j$0`G^kp#9-+z7! z5+ye`;B)=8orSbhzxC(!$#(@fIopRj#&ZK#r)#36p9i#+t58mQA5U4_vz{`Z+9^nD z{rOQkp#F|YuCr{7M^TzN$iH{lMIJpBUJZIMy_n;i$caFlwd^q_{|Iq@g1F?l&Hj0W zn#)lJ_qlgEeO&i~sy+mT1|ZNEjys-*sZ7P#o3~9Jmiwx_z^5q~D;T7aQ1&@`D#xzD z>jYI=8n|ZY3E{>6x^oQ*VR+w?TIpBrR5oC0354G-wa zh{++%iQq(K9EnCIU66rQTzSCOXX#lM&g$!h=@#hkM
VO4Kvuf)7A5%h|7vMHEN8_=tbc8`V_;xM3;UUBOpVPpDe+Mu|*(o33P zEANP!@OgXg2a!$}tHwbX2p1jCx&J7jn+3e}DrdvGE5_WInXP)=aiFm_kR*fvhI9l+ z+;>fI%Vau(ur9%T&nxsVA!flI?Kw^Ax3Q49-~95GN}B6GfdXdajl)u%AmsD3&!?HF ziGEh%cDjcwI&++zihbu7!kz{2t_r#M4blf~Cg})GoZ&zX=lMNI|8BD;ueIMer-RVP z9&f-SkKS=5JUmsxJEoIoFG5HAJ^j(m6~wxCS0>}ZD{=Kzq=8Crc!%vB7>SKk>| zO(!@($R{j4>?3o6=c7D6W(xt6xkpXvh^fDyq7v0k`%9y7lpN+uU)4migEoigdp3Q# zj>wIXDj_!mM+%85;6$`Uiz7i>ebocUPhFa5;4R(8M%^ z`GrInWr^X*d!3Ghw8qR{7lH1+{GIPjW9^f-=%UE5XNNtJ>fe}y0g`y$&Im_7brE&v zk8otiS`*WsWt!!0WDY1~Hj%p5`poT)gXXdBRIEQPrms>K?huHmDin*6RypdV8Q0(=goa!80k&al*U zy0j8RxC7GP6CGw5m3R$%cPioyE+&B!USfzAVd3;0M~2~nTZph*$`LVUv9ApgCWh!A z5dcu&NR-e*-w78f2u0w8K$_e?5I`7+g?@{%Ka3lX3WIq;Iwdarzyljt^cV&`XNjK2 z1LKtVd33^W2PSAO{d#)BW>Z2d2EB+uONIi!2~0=W#P1U5J+pX{JmWH!aS4ka4+bF7 zz$A`PJI*k8g+TM19)U;g7@~L9kxWk#p!p0R%@|kl02#|j#-Nue&zFgbqcFAv@9@V> z@W+P{o}7{Q!FvJ#;|qj^VI$;A5$B)0Fr*rKjF4hsD|SLgYCgd+;-#S`^w3JiLN)d?hXqRT3S#XLf8g7D5D)9@qMW&Z>s`+A4!?3AQPts$e(;vG=`2N;< z(wrvoG3{At9Ks=^tMIU}|-J&c^5xS?ex$6z^-mTZ-rUK&@D4tvk?0uLY%Kvo@B z78v!dMr01NX3ohos1jjMpJcjmWoM{JhyTv(dy+k%lG>D!)iS7_F_G2zJ1fvNsSB)D z!jI@uDWQIdyxL}>76Oq2WYOg3{n>ESTFbM#m0SEV z?G2E9;bZ7#GhC_Wf-eQN9}W0n&{|OilEztw8#%L&(Ht@PhS#uwB(ZZa)N&xSJsMEL zNqgc8{D?#b<3e3)^z}zNLBbFg0&po4IAsQ?h^Z+IIjnIJm0RE%vspLGU@DZC0L9r) zxfqWtcIM7Mbd~#Sg&H8zw_xZ!hUi#GoEFwE6*r5lB#9LnuuYW$m={9Fx-g`S7-f|& zK|o~^QUAiw)bWxUG(#~Nk&cE5k?`Keav42Yfi0!9L#12I-~*l`zKj@*Dv``A$RW_N z3PF3{;{9rZx@(b#_@Q1u9_% zuu!6DZNxIZ(<8Tvrmd<1T542?HOw}(6jUC#Du|DvW4iGl8y%n*I9r*8dtHu3y&5km zBO}--_krRv_gTnigLLs&Vz?J(*PRLLD$W9FJ_NT_K^2pj{EBg6DOX)>~!?Mclbh0hy? zsZWRX>9w#;DsTq31Xwqe-pf%K=kve=zT@o+f7;2^t#+m~07T~Xv8}NItq2lo`)oPL znvoco9T{#%23bD**A|VdL+7oU&MY-rEQq07MJDetcjDTiR~qQS>NTMqI)Pf^=^~$H zxMbbYYSP+xwz6rsgO?W-4-#{r-WAt*um!(V(|HivePGl1d`oFejYP9A#lB?ul&4HT zi$pU)qN#6}8*JC)eSsTkmqXHdVmsK|I^tTJK#CnV+_gjhPX|xQqBSFSX16w5X1}El z!#F72*!!4A_ek_N;~4Ju*t_Lu{d4X4=g#(O9rxh^>2%`&Hctrq=U$`i){EP{Z9H$m zk=g$8w;{)!S;MdwKi|ed0R`&K3ME2c{?SX9&jVVSD%#wIeUj+Z?7@dp{ovij>RgG@ zNXL`UO~w^XW;X#1V4&Zm^Ve{*_~)VTt<9P>u$AZmOQ*)f?BRsA;Rn~Sm7aqsyd!qcO&?+<^gjXfixP>;2#F)Hhq!lkf|x!q@u~3=Ph_B^1iK^R*n|o*)6U zzSiR+)cn9bDReY2LgFoC<{R0$2|Tw!SyH zi7HWtr~jd$-tWGCipDbMgBgWJlL9s5o|?#FR?3+|+E&Pq^Ep$dblaxy&rg4qA_aBU&1-Mlv7(Xpx$1CT(u}?5r;?mcrSZVcoeys} zBE97<`xr2t$TyMdKIqQyIXw=@kVePY%sl@4(X0J^c1kYcwo(TVZFWG6N}0n>CJPW@%|602Lb;fC`|u_A8X7X z|6M$e2f*Wiv%U2nZ3St8h1Y-Q=PtrNZb89oiuH>NU!E>(Rxb4B0DU>1_cay||1SL; zr5lR}%mA`j&@y;s1GB@@29ep8$@A@GtmXHKw#_mF1^Os zt-d1sy9u~~Up75~BS;tknf93UsW;GHxVkZv3fzDnjFVkT5REQ&?}z60 zXb_8U5ciXX`S&tA2=IGmwfplfN!uVVCC_ z_;zVSmjFhN_64=X{#@D@rtVGU{(vu`WIFdR?d^NuH_tuzE@*Nf81T)qbC)}DqdQ@v zm+^-d^?RD;rj8a%WIIPAW=Fj9Cn!8a5`lk52Skd@;{N5t1tzWUn^mYAok%NtWHyNo zP8cfGSf=^*omTtjZCRF6ICWC(PeXy<;)y@NhPVsgFR0-9=Y@SAf%UU{3(j`ml5!7% z?2kCAQ6Y;kBgT2A{KMEzW|s%7LY|QN%jky7e|Ws;Qy#1+zMDhu{zlzTpddIOSfm2MfHvnjM>MO5ut+G$7$K<`SXMWn5Xn)vDeE^$3M!@_(YpYg*Tla!t8oP#EO8a($!$sb zpJ;ULJIU+pS_?=^@^o2pqqROkNNBPQ}ia((BA8I~Y4nikkD?DBo~OIu;4Ml3fhc23V(*zSC%gE|*I6!z-p zriD;UI+i?7DaC5;jvIA zpV=iX^Kgr4NpZ0o8u5{0Eq7xV^|%*GA_8%yxwtceZl!-l8>wMdg$dljOvOFSbfU?m zr74l_pWOFFTc(}X>e;n1Un6L&;2zD?St}w(uDR?3_>Z-$>nT6wRXw}t=-zA$z`MEc zm7SIq3}Zqcj$D&YCKPP(j{a0wYY>(ya*xzVRD0a~u}bZ_fSX><^$*t!Y%y{Wadn@M zE{ROeX~|Wjjcg!5KCDlLrsG@S(+BeQX4id4*S@5nZDQ(QIB0IykJ%wyB4}J~&^xc0 zbO|_UewI6YcOn0HYRo|EFWOL_*)#GVx&;`V3|V_p zh6gz`saFim+mH`EZ`1p(rcndsGZs?RnpNRL&}1ywqtci~+avUpyNL{gSXc=S)qJ*- z?M=-oc2K%ED{iBSkwz;0VEyq<3=(|o$efPD3x+B83hIYM1yg$N_uYUc->nI}9JYM= zB_1G=62fluI2v%jXJ*~r zmx9MN2AaFf^y+~Ss2`DxsJoJT(8&j@q9cqd1ncCN=&b8{WJy>Uy25)_r6^u9*O0oC?=G|UVlyjx|WS) z<<$F5UwEGk9zf3^7n=E95#ailjT>rbB&ipUuE%>_P9J7dvOmWDJ+Y4XrMQCCqC!rMQ>97Bt%zQvusfA%GyS)iwJ?N*3} zoARrQVTluLYflkqB`Q+K*aTB^HVzcS^W@Bk{8G0{t`&Py1?sW{l$eoKLpoutKGyOxysV8 zG~olJ7+vppNd{}eDhjFO{i*wLWqHzS_~&+y3-6y-R)ABEcIWGCpHBeAkMD-w2{lP4 z^D{}ft`f16lvizat%d7j2 zw%?y$K<8e+>$$!}nyq;5inIg{f#bt;?h8l0x${F8NF=TTVxvsSeZM*BtH00A0BDHv zXavG8aa%KEpMNK__A-!35Qg=XQ{WrvX>i=Cp6BRm6car^{CzY{^Fgu~M#M3m;NFT% zA~}r_zwDNIHf|Oc6X&JT8qm3BY}8YJh-iOEbf;bQ;Tq#nO(*=Z+m*bhesZ-PD2EH= z%rYn&;h2+MhW31R#22qiAo;@prp(M9dyzhX!nz?RPdzh|CN!K=7H2LWNi7WT|MuPXooTbFVDx0r1A~aUDsw=WMIj@jg$q z#dviDjNo@FvszR$^Sx5GL9&AffMTabrs8B4)GvAu%QPQ5O`ExG?U52ll4E1NB^#$I z>(vuJseBw-f!*T0&Mt$jFP$QB!ry7i`t zt8r}-;FVxaL?Mro$Z{66kL*7lwu{5zY!|w@;1p1bLEevHt(!fXAaj^X#XPT?n3MOY z!7;4KNOVk;qJ=BrbEL&_9f-B`2PdM*I0V(AT^Y^u@mq}V4G8gV^4a(J8c$Oog zx6^(c!tQ_BZG=Gzdj#8#PNLrAbryRPs^sDR2u2A24mbZysH$g^kw>8g$!I0DfcfY_ zgUS}76c6#_ZL21)7gjOfi<@Q`>_^zS0_`wJT#X~ePqd5WfQXojVzSqqTxT|;|7aEe zI~8AzV4~xHO3{H07>i_fRX^g+^oNaDy!)t&gogQw?dIZL6W<%c*{Xj$hWrsj`9g0- z#ne{jEoF2PtC7aW&Q zv)l&rFnm1$$Ht9b>4)r?spl z6#KIEx^l9B1B`MQpw&oBId6j`+FAiYOP^{iZ<|&@oRu;1AAm$4 z0R)Ch!bqro`D%DTw(Pj93#bS zn#2Q$^xm$*ibPN6P%r0DkHJ{?l2A|UkjDhm7gQ|TGQ{24)SXBwKLDmwVq??l0OuW{* zJs{JBQM2ASte17qJ2PB=W=QXB&j^}Z+7SmhH$zAu*DZ9^sc*cs@5M9DvEIJP4f8K0 zeLQ=6ebZw7Gs^v6^-s4=_02l<&-;YJAhhr<8dk)EfD9)v2;4=&>t^5q@c&^2_~!+Va0xiI=B~Z~uptxKti+=s&E4ipHVj%70l2lgoRYFHtrBvJyNm zt*|Uwa@MYd02Y4LhZEJ)0lH5aSOp~@fVcT`W8$$plM|cw?J*1yl2+W(Rx;A1XHBh6 z=^>B^l+4w6v%1RFam{i($)08`qfCFwX!uML`?N0p0UX$_uQAF%Vt5IEysOvDoE;^@ zQzvS+e@wmQILKt$SweAK?zg^rIF%ROiXZgKe7E}e8U?aY8*gEBZba{eDy!uf+C zize|CGIKNJ&;y9QL*I$vg7b9H1>qbT>L~B8DR+Y7Hh~N0_zx?A#L&aal4xfBY`PMT zJmf6ruaRn%6(T^H4uRSGupj8agP(VX1KT$$zD7ayps1_v4c%8H<9}EQ2H6_NXBG_N zBCh&pLt$28KIaIa)v}Y7;OxeBHOaL-bUKMiO+A%r>9zDa@!{4|w$IJq67A1CD|g4z zDMx=FN_)(noXvG#N@^)H1tZl*`@kh7nCWvCwgNm*9Gmk>4S)mN_iVy$xq^_bR9;E@ z!SDE-S1j9k1=aH!@y|i9TT0g%)L zZ50#nIP(=cRM@53F)o}`2@;oAYgdxpjv^CS#9+SSrSSKL4cjv=b^BZSna`Q*r3dSu z&fIY=+54Tp*1`@S)9W|jvs5c*cz$s$)6Iehx`T4kKj>T+Bj{}c2`*(i0e&(MIypom z*1HsL3c6Mk%3b8T6c>DynvW+em-Q3x_dXgB6&Kuix6g97oOnuf)vd~;ymzC=;^LvZ z!<>c_6(e>FVeW0(9M$heXCxX=hB|Kz=WfKkNi8gR|k>X zUz{2#bUv1}7-KGyxLkJhWu`_d?;dl%L3Y?hKPP&iVS(k*8%||GbF^!?b=@0~pY38! zw&%7^mgu0GPEvwjFrUrqdwZ+Z3q^b1FLWra@xA&bx4+iPlYVx-T|7F2s~kQZk^>X| z{w8*6-#_{2vWvi<&5016KYT+T@_!#*aMRh_S(Fd)*;=`u@^{bs?xjYqUmgzryG275 zO+=O*=7R&fm@l1+2@PbIe9~Td!~xJr%p6rs70&hSI(t^^*^3n?ae<{yW0BJUMLA1G^lY=h!=KOX zpzB<2HKx}6KNFyuBS=@9AiL8KBkBqQO zTe5JOIY#@&nWMxgb(+-vEE!+e!Y$D;cvfg51NV83o7)zyikwS_3U&EncWa`&h7;Q& zZk|%H4H`*OPFWB;sx(p)l-%g{9Lqb;-H#hk{JrtIuQ&Iob_eF=U(TGb`+@pZYdEw7 z7vdabbS@+8+>Nu-k5u}kkXjz+$u16g<~eyXxx^2}N?dt%C-bezPe$^S-SaP}eIvHi zelTGFn(x$?Z&xM7M&Ef;q~XJQF(dgSrJ%n!UWdir*jl`S{X#J{@-|0e$;;NL5P)?m z%4MHFx9#N*z~jjBwO6**9cRg90C9yV1VaXHH_OQxIX8>9g<20{o|l}HmE}kt3?vXP zAW)=cjO|pg-UNcxlcXmS3p_<~+AC33S6tFRj=rDSsziReYt6O?pdxg6Yrr3(ctxDu zQ~+O#eK4BAHGTB-MITz*vhySF%Tg{Mi)BfALYmWX@CCu<4VI8LOG3mb_IkL7ecm+} zFZ~YVuDfDDw6;p2DaASP>|+#2nBM8@VmbgG=tXhX+g~>JkaX}>IM1ki5e<9U>38W8 zns5u*E}%W3MBo3>gHWNNQI6-lBs98Zj9p;4)#S_r4*e5QiSA}wfjPV$n2HtH9%a{T z)R%)0I02M8A0wm~8Yv^4pc_;R690uslhK1lD}YIupmS61(Js4N|F5+B5uk(e zl;kntM@fY*Zz$K*^s%2-<}zXn?1U+U$Cag#!Vhr97j56aSUX0$C9*hs>*FAeMdj5G zUGS6}-@s$7H<^-sH_i33hq_MO%^5elqu22XkyZ34!Q<}IIZ=@z{!!&vhqSuSeqJA( zxjQ)-V((mDsOgWNcYl3gm*Bv$_qbEb%{np?IK`OxX~3_txQ@xC(t2+!_gX-yc*@<$ zyzwd!K)?9aOVJ(VL)0C2&kSN)x%ldm=ZaQk<>iQZo@ZX{14UK2>*fny9yRSPmd#3v!KahtJQY9>Lh#| z`q1`6NLb8EXfwwGiJ%ZkBiF;-hkbpQuUaU-ulj!6H15y$Afvjm@za`#Lw|mZfAH$N zIP6xRaA+0faN>*Xf`@yZTAlsJ-|Yjz*g77^`UF+YnZm}MiFFEZOhWxv!=}whj!E_> zo%P>-MD6rnvRl@H8fLTUf!8f`uuFOSqK^mm3^Rp(9T`B0ZjeX})mk1jcg58^^4{)4 ze|M{~r0?EMdtdY}@3dxbtv}eF`ED`2YwQ2_V7saK>EG#TwlJEOFc^dVvM~MUhrGT} znE&Q#h}>@J;RE=XvcKM>_In}0uc69s73;rd_z-kOu)3OWsUGjG@}J@%e+>Zuir=>m zzwb9m@FKn6ab0FmW9Onb#7h=2^41}FgRXwdRRPlfw4urChW<=DWV=`X$9G6a)G*?n zJW`zjTAhAqBk-r8zcQ~zJMAfG|8y@Q@GB2`RvbFH^He4gD{JJ#V}HYdqT0UZXfhgP zl!H>AB9jO~GHSsq+kQ3_jrOTPmz<|p76aj4qyq@RyZ0b5SW7J!B>LRiQQdO{-a_aA z35ux#CAc$Kr9<1}9ZoI>3_PHLRNhdkQBasY&Zkq^cjx#wcK!f0OyyK)&kc$S4?2|M zO?rSezZm+2#-Km;|V^ukLsjEJXe5l zgU~VS$j|RtP;9Ii1T&Hxje5rn0?hl?&<>Hce~JmILj~=r;1eo(J^D8h+9gDv*JGI` zK<|k$;2Kk@WehSV=KUbk`>7N8XP`O~kfRWL#5ne74WqbvY|k1qJB|gCJdR`MH!}+B zX%AF8P!B`Kpc3BUJn0c>^ayRfxIqxq55>Y0T^@av1@31|WrBI^qLJYtP)&6CUqAJB0(4s>K*G ztdWX*$~uuZy5w)=KD%%$9$6aiUX$o?DZ2-EFkiqyLB%#Zd z@eGw9!p%1_|Kcx0dfC}@?%Nsa#B{!}^n?eXP#AWM?lFM)vr2q!@W=_CWp=70z}tw75{F_4 zO!=-%3iwwSYVqg2;5RgUf@F$jx1598>ju6|dx=bYwFr*~ncay2BHvz%)keU!dE6Sn zNCi3|{7VA<;#jsHo-vE`>Z4JLgKfsGWYj~?*E%MduMVDMw#P?waOJv&V&{x~r07Y<`l|-tnAypI#VIfc?1 zL}`}5nQ3@+9T8YtczvcYkH6H(3k3rCfI?BFMt)UZX?ISVaS~7q6#vZ2-sZ<=(D6G` z_zZhI4;2_l24MR?3?(RED!+BGhEay81QJq0K`3mY#ONm@$9PKUyOaWx(rdR%UDflW zyDQB0a`JN#1aG`jcdnP$8+h-%(<`g2FTMYuQvS2iUhP-j7 zQh6DD&A#%MW#ttr!xaKTZ>#dbLq6RT5tFwo@-(U%j8VBkrRB+`m9-VK5)kYdXzIqJ zV%|teCwuXY z0kbveC2H1>m!PNFkhmY5x<)}~FMZ1<`1jva>2kj#$shuGQsh#cC z@K4v<>-BG)C*ImhK^I*yFl8a6$&kF?{4>8x&k}VnzoV+TgJ-(K->&80M8wmAs!-R? zl8DYy!Jc3{M6@8@vG;9teGj!DEBXXFF_pnsup>RS_4FF115Q)}iR(t)N$cfIMPNvBI`Tar6Aj(aX!4ewa z|I@$Oi`pp|I29XtP~UwZGYAfLgH*6R=e8+t-3qQnO{`Bng2MMp?2j+(#U;b!qSDJqLW63w< zk}ktN*RczCN4&kq3JS+03kQ{%-`$MpkGwqo=JF_#?bGvy@%lgLt8|q7p!R0fr=E8u zcpXMA=`oMbpSsLZ%EU3vSTN`0=kpC?UUxpXOm)^0huF
    $~5uln;=(-+fldD4QK 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