From b7a4e30cf630e3084bec2e3370b1be476d9e3e04 Mon Sep 17 00:00:00 2001 From: cxf <839989072@qq.com> Date: Sat, 12 Jul 2025 17:05:25 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=BF=E6=9D=BE=E5=A4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/README.md | 1 + .../README_声源定位系统.md | 216 + .../2025-06-10_08-55-17/details.md | 69 + .../2025-06-10_08-55-17/diff-details.md | 15 + .../2025-06-10_08-55-17/diff.csv | 2 + .../2025-06-10_08-55-17/diff.md | 19 + .../2025-06-10_08-55-17/diff.txt | 22 + .../2025-06-10_08-55-17/results.csv | 56 + .../2025-06-10_08-55-17/results.json | 1 + .../2025-06-10_08-55-17/results.md | 50 + .../2025-06-10_08-55-17/results.txt | 107 + .../audio-classification/.gitignore | 296 + .../audio-classification/LICENSE | 201 + .../audio-classification/README.md | 373 + .../audio-classification/README_en.md | 275 + .../audio-classification-platform/README.md | 136 + .../backend/app.py | 350 + .../backend/config.py | 39 + .../backend/requirements.txt | 7 + .../frontend/index.html | 26 + .../frontend/package.json | 24 + .../frontend/src/App.vue | 106 + .../frontend/src/components/AudioRecorder.vue | 690 + .../src/components/AudioRecorder_new.vue | 1020 + .../frontend/src/components/AudioUpload.vue | 714 + .../frontend/src/components/HistoryList.vue | 616 + .../src/components/PredictionResult.vue | 941 + .../frontend/src/main.js | 18 + .../frontend/src/router/index.js | 17 + .../frontend/src/utils/api.js | 213 + .../frontend/src/views/HomePage.vue | 841 + .../frontend/vite.config.js | 33 + .../frontend/yarn.lock | 1092 + .../audio-classification-platform/start.bat | 24 + .../audio-classification-platform/start.sh | 36 + .../configs/augmentation.yml | 46 + .../audio-classification/configs/cam++.yml | 80 + .../configs/ecapa_tdnn.yml | 80 + .../audio-classification/configs/eres2net.yml | 80 + .../audio-classification/configs/panns.yml | 80 + .../audio-classification/configs/res2net.yml | 80 + .../configs/resnet_se.yml | 80 + .../audio-classification/configs/tdnn.yml | 80 + .../audio-classification/create_data.py | 99 + .../docs/images/image1.png | Bin 0 -> 69600 bytes .../audio-classification/docs/images/log.jpg | Bin 0 -> 117637 bytes .../audio-classification/eval.py | 26 + .../audio-classification/extract_features.py | 19 + .../audio-classification/infer.py | 23 + .../audio-classification/infer_record.py | 58 + .../audio-classification/macls/__init__.py | 1 + .../macls/data_utils/__init__.py | 0 .../macls/data_utils/collate_fn.py | 23 + .../macls/data_utils/featurizer.py | 132 + .../macls/data_utils/reader.py | 157 + .../macls/metric/__init__.py | 0 .../macls/metric/metrics.py | 12 + .../macls/optimizer/__init__.py | 32 + .../macls/optimizer/scheduler.py | 48 + .../audio-classification/macls/predict.py | 177 + .../audio-classification/macls/trainer.py | 456 + .../macls/utils/__init__.py | 0 .../macls/utils/checkpoint.py | 162 + .../macls/utils/record.py | 31 + .../audio-classification/macls/utils/utils.py | 131 + .../audio-classification/record_audio.py | 14 + .../audio-classification/requirements.txt | 17 + .../audio-classification/setup.py | 54 + .../tools/download_language_data.sh | 29 + .../audio-classification/train.py | 30 + src/声源定位代码/back-code/README.md | 421 + .../back-code/development_board.py | 3309 +++ src/声源定位代码/back-code/pc_server.py | 2078 ++ src/声源定位代码/config.ini | 35 + .../front-code/sound-vue-frontend/.gitignore | 52 + .../front-code/sound-vue-frontend/README.md | 38 + .../front-code/sound-vue-frontend/index.html | 13 + .../sound-vue-frontend/package-lock.json | 19934 ++++++++++++++++ .../sound-vue-frontend/package.json | 38 + .../front-code/sound-vue-frontend/src/App.vue | 344 + .../sound-vue-frontend/src/assets/main.css | 19 + .../src/components/SourceDataService.js | 11 + .../front-code/sound-vue-frontend/src/main.js | 8 + .../sound-vue-frontend/vue.config.js | 13 + .../mic-code/Maix/Maix_config.c | 423 + .../mic-code/Maix/Maix_fft.c | 195 + .../mic-code/Maix/Maix_fpioa.c | 395 + .../mic-code/Maix/Maix_gpio.c | 587 + .../mic-code/Maix/Maix_i2s.c | 371 + .../mic-code/Maix/Maix_kpu.c | 1840 ++ .../mic-code/Maix/Maix_kpu_classifier.c | 290 + .../mic-code/Maix/Maix_mic_array.c | 286 + .../mic-code/Maix/Maix_utils.c | 86 + .../mic-code/Maix/include/Maix_config.h | 5 + .../mic-code/Maix/include/Maix_i2s.h | 23 + .../mic-code/Maix/include/Maix_kpu.h | 25 + .../mic-code/Maix/include/modMaix.h | 31 + .../mic-code/Maix/include/py_cpufreq.h | 11 + .../mic-code/Maix/modMaix.c | 46 + .../mic-code/Maix/py_cpufreq.c | 136 + .../mic-code/init-code/main.py | 259 + .../mic-code/init-code/main_raw.py | 38 + .../mic-code/init-code/tcp_listen.py | 27 + .../mic-code/init-code/test_send.py | 89 + .../mic-code/init-code/wifi_connection.py | 110 + src/声源定位代码/mic-code/sound_map.py | 113 + .../mic-code/sound_map_wifi.py | 114 + .../Linux_SDK/.vscode/settings.json | 3 + .../Linux_SDK/demo/.idea/.gitignore | 8 + .../Linux_SDK/demo/.idea/demo.iml | 9 + .../inspectionProfiles/Project_Default.xml | 6 + .../Linux_SDK/demo/.idea/misc.xml | 6 + .../Linux_SDK/demo/.idea/modules.xml | 8 + .../Linux_SDK/demo/.idea/vcs.xml | 6 + .../2025-06-10_08-55-17/details.md | 69 + .../2025-06-10_08-55-17/diff-details.md | 15 + .../2025-06-10_08-55-17/diff.csv | 2 + .../2025-06-10_08-55-17/diff.md | 19 + .../2025-06-10_08-55-17/diff.txt | 22 + .../2025-06-10_08-55-17/results.csv | 56 + .../2025-06-10_08-55-17/results.json | 1 + .../2025-06-10_08-55-17/results.md | 50 + .../2025-06-10_08-55-17/results.txt | 107 + .../demo/audio-classification/.gitignore | 296 + .../demo/audio-classification/LICENSE | 201 + .../demo/audio-classification/README.md | 373 + .../demo/audio-classification/README_en.md | 275 + .../audio-classification-platform/README.md | 136 + .../backend/app.py | 350 + .../backend/config.py | 39 + .../backend/requirements.txt | 7 + .../frontend/index.html | 26 + .../frontend/package.json | 24 + .../frontend/src/App.vue | 106 + .../frontend/src/components/AudioRecorder.vue | 743 + .../src/components/AudioRecorder_new.vue | 1076 + .../frontend/src/components/AudioUpload.vue | 741 + .../frontend/src/components/HistoryList.vue | 635 + .../src/components/PredictionResult.vue | 995 + .../frontend/src/main.js | 18 + .../frontend/src/router/index.js | 17 + .../frontend/src/utils/api.js | 213 + .../frontend/src/views/HomePage.vue | 841 + .../frontend/vite.config.js | 33 + .../frontend/yarn.lock | 1092 + .../audio-classification-platform/start.bat | 24 + .../audio-classification-platform/start.sh | 36 + .../configs/augmentation.yml | 46 + .../audio-classification/configs/cam++.yml | 80 + .../configs/ecapa_tdnn.yml | 80 + .../audio-classification/configs/eres2net.yml | 80 + .../audio-classification/configs/panns.yml | 80 + .../audio-classification/configs/res2net.yml | 80 + .../configs/resnet_se.yml | 80 + .../audio-classification/configs/tdnn.yml | 80 + .../demo/audio-classification/create_data.py | 99 + .../docs/images/image1.png | Bin 0 -> 69600 bytes .../audio-classification/docs/images/log.jpg | Bin 0 -> 117637 bytes .../demo/audio-classification/eval.py | 26 + .../audio-classification/extract_features.py | 19 + .../demo/audio-classification/infer.py | 23 + .../demo/audio-classification/infer_record.py | 58 + .../audio-classification/macls/__init__.py | 1 + .../macls/data_utils/__init__.py | 0 .../macls/data_utils/collate_fn.py | 23 + .../macls/data_utils/featurizer.py | 132 + .../macls/data_utils/reader.py | 157 + .../macls/metric/__init__.py | 0 .../macls/metric/metrics.py | 12 + .../macls/optimizer/__init__.py | 32 + .../macls/optimizer/scheduler.py | 48 + .../audio-classification/macls/predict.py | 177 + .../audio-classification/macls/trainer.py | 456 + .../macls/utils/__init__.py | 0 .../macls/utils/checkpoint.py | 162 + .../macls/utils/record.py | 31 + .../audio-classification/macls/utils/utils.py | 131 + .../demo/audio-classification/record_audio.py | 14 + .../audio-classification/requirements.txt | 17 + .../demo/audio-classification/setup.py | 54 + .../tools/download_language_data.sh | 29 + .../demo/audio-classification/train.py | 30 + .../Linux_SDK/demo/database/README.md | 298 + .../Linux_SDK/demo/database/config.py | 432 + .../demo/database/create_tables_simple.sql | 102 + .../database/create_tables_simple_mysql.sql | 99 + .../Linux_SDK/demo/database/db_utils.py | 553 + .../Linux_SDK/demo/database/init_database.py | 317 + .../Linux_SDK/demo/database/requirements.txt | 34 + .../Linux_SDK/demo/database/setup_database.py | 226 + .../demo/demo_for_qt/FFVideoFormatConvert.cpp | 165 + .../demo/demo_for_qt/FFVideoFormatConvert.h | 40 + .../Linux_SDK/demo/demo_for_qt/MapWidget.cpp | 305 + .../Linux_SDK/demo/demo_for_qt/MapWidget.h | 62 + .../demo/demo_for_qt/QtCameraCapture.cpp | 99 + .../demo/demo_for_qt/QtCameraCapture.h | 116 + .../Linux_SDK/demo/demo_for_qt/README.md | 128 + .../demo/demo_for_qt/RecordingFlash_32x32.png | Bin 0 -> 526 bytes .../demo/demo_for_qt/ShaderSourceCode.h | 86 + .../demo/demo_for_qt/VLKVideoWidget.cpp | 826 + .../demo/demo_for_qt/VLKVideoWidget.h | 137 + .../demo/demo_for_qt/VideoObjNetwork.cpp | 519 + .../demo/demo_for_qt/VideoObjNetwork.h | 318 + .../demo/demo_for_qt/VideoObjUSBCamera.cpp | 294 + .../demo/demo_for_qt/VideoObjUSBCamera.h | 48 + .../demo/demo_for_qt/circle_empty_48x48.png | Bin 0 -> 1164 bytes .../demo_for_qt/circle_selected_32x32.png | Bin 0 -> 939 bytes .../demo/demo_for_qt/demo_for_qt.pro | 142 + .../demo/demo_for_qt/demo_for_qt.pro.user | 189 + .../image/RecordingFlash_32x32.png | Bin 0 -> 1755 bytes .../demo_for_qt/image/circle_empty_48x48.png | Bin 0 -> 870 bytes .../image/circle_selected_32x32.png | Bin 0 -> 1144 bytes .../demo/demo_for_qt/imagepreviewdialog.cpp | 71 + .../demo/demo_for_qt/imagepreviewdialog.h | 38 + .../Linux_SDK/demo/demo_for_qt/main.cpp | 39 + .../Linux_SDK/demo/demo_for_qt/qml/Map.qml | 330 + .../demo/demo_for_qt/qml/TargetMarker.qml | 94 + .../Linux_SDK/demo/demo_for_qt/res.qrc | 9 + .../Linux_SDK/demo/demo_for_qt/widget.cpp | 2009 ++ .../Linux_SDK/demo/demo_for_qt/widget.cpp.new | 1268 + .../Linux_SDK/demo/demo_for_qt/widget.h | 756 + .../Linux_SDK/demo/demo_for_qt/widget.ui | 1511 ++ .../demo/demo_for_qt/widget_new.ui.h | 1259 + .../Linux_SDK/demo/gold_eyes/.gitignore | 71 + .../Linux_SDK/demo/gold_eyes/src/flask_app.py | 101 + .../Linux_SDK/demo/gold_eyes/src/main.py | 259 + .../src/sound-vue-frontend/.gitignore | 52 + .../src/sound-vue-frontend/README.md | 38 + .../src/sound-vue-frontend/index.html | 13 + .../src/sound-vue-frontend/package-lock.json | 19934 ++++++++++++++++ .../src/sound-vue-frontend/package.json | 38 + .../src/sound-vue-frontend/src/App.vue | 393 + .../sound-vue-frontend/src/assets/main.css | 19 + .../src/components/SourceDataService.js | 11 + .../src/sound-vue-frontend/src/main.js | 8 + .../src/sound-vue-frontend/vue.config.js | 13 + .../demo/identification system/CMakeLists.txt | 38 + .../demo/identification system/README.md | 164 + .../src/image_processor.cpp | 286 + .../src/image_processor.h | 54 + .../demo/identification system/src/main.cpp | 216 + .../identification system/src/zhipu_api.cpp | 288 + .../identification system/src/zhipu_api.h | 48 + .../demo/move_control_tcp/CMakeLists.txt | 12 + .../Linux_SDK/demo/move_control_tcp/README.md | 87 + .../demo/move_control_tcp/compile.sh | 13 + .../demo/move_control_tcp/tcp_client.cpp | 94 + .../Linux_SDK/demo/workproject/CMakeLists.txt | 28 + .../Linux_SDK/demo/workproject/README.md | 93 + .../Linux_SDK/demo/workproject/build.sh | 48 + .../demo/workproject/include/mavlink_client.h | 84 + .../Linux_SDK/demo/workproject/run.sh | 60 + .../Linux_SDK/demo/workproject/src/main.cpp | 137 + .../demo/workproject/src/mavlink_client.cpp | 361 + .../demo/workproject/使用说明.md | 138 + .../Linux_SDK/doc/ViewLinkSDK.chm | Bin 0 -> 655818 bytes .../Linux_SDK/inc/ViewLink.h | 840 + 257 files changed, 90775 insertions(+) create mode 100644 src/README.md create mode 100644 src/声源定位代码/README_声源定位系统.md create mode 100644 src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/details.md create mode 100644 src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff-details.md create mode 100644 src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.csv create mode 100644 src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.md create mode 100644 src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.txt create mode 100644 src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.csv create mode 100644 src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.json create mode 100644 src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.md create mode 100644 src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.txt create mode 100644 src/声源定位代码/audio-classification/.gitignore create mode 100644 src/声源定位代码/audio-classification/LICENSE create mode 100644 src/声源定位代码/audio-classification/README.md create mode 100644 src/声源定位代码/audio-classification/README_en.md create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/README.md create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/backend/app.py create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/backend/config.py create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/backend/requirements.txt create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/index.html create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/package.json create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/App.vue create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder.vue create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioUpload.vue create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/HistoryList.vue create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/PredictionResult.vue create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/main.js create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/router/index.js create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/utils/api.js create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/views/HomePage.vue create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/vite.config.js create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/frontend/yarn.lock create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/start.bat create mode 100644 src/声源定位代码/audio-classification/audio-classification-platform/start.sh create mode 100644 src/声源定位代码/audio-classification/configs/augmentation.yml create mode 100644 src/声源定位代码/audio-classification/configs/cam++.yml create mode 100644 src/声源定位代码/audio-classification/configs/ecapa_tdnn.yml create mode 100644 src/声源定位代码/audio-classification/configs/eres2net.yml create mode 100644 src/声源定位代码/audio-classification/configs/panns.yml create mode 100644 src/声源定位代码/audio-classification/configs/res2net.yml create mode 100644 src/声源定位代码/audio-classification/configs/resnet_se.yml create mode 100644 src/声源定位代码/audio-classification/configs/tdnn.yml create mode 100644 src/声源定位代码/audio-classification/create_data.py create mode 100644 src/声源定位代码/audio-classification/docs/images/image1.png create mode 100644 src/声源定位代码/audio-classification/docs/images/log.jpg create mode 100644 src/声源定位代码/audio-classification/eval.py create mode 100644 src/声源定位代码/audio-classification/extract_features.py create mode 100644 src/声源定位代码/audio-classification/infer.py create mode 100644 src/声源定位代码/audio-classification/infer_record.py create mode 100644 src/声源定位代码/audio-classification/macls/__init__.py create mode 100644 src/声源定位代码/audio-classification/macls/data_utils/__init__.py create mode 100644 src/声源定位代码/audio-classification/macls/data_utils/collate_fn.py create mode 100644 src/声源定位代码/audio-classification/macls/data_utils/featurizer.py create mode 100644 src/声源定位代码/audio-classification/macls/data_utils/reader.py create mode 100644 src/声源定位代码/audio-classification/macls/metric/__init__.py create mode 100644 src/声源定位代码/audio-classification/macls/metric/metrics.py create mode 100644 src/声源定位代码/audio-classification/macls/optimizer/__init__.py create mode 100644 src/声源定位代码/audio-classification/macls/optimizer/scheduler.py create mode 100644 src/声源定位代码/audio-classification/macls/predict.py create mode 100644 src/声源定位代码/audio-classification/macls/trainer.py create mode 100644 src/声源定位代码/audio-classification/macls/utils/__init__.py create mode 100644 src/声源定位代码/audio-classification/macls/utils/checkpoint.py create mode 100644 src/声源定位代码/audio-classification/macls/utils/record.py create mode 100644 src/声源定位代码/audio-classification/macls/utils/utils.py create mode 100644 src/声源定位代码/audio-classification/record_audio.py create mode 100644 src/声源定位代码/audio-classification/requirements.txt create mode 100644 src/声源定位代码/audio-classification/setup.py create mode 100644 src/声源定位代码/audio-classification/tools/download_language_data.sh create mode 100644 src/声源定位代码/audio-classification/train.py create mode 100644 src/声源定位代码/back-code/README.md create mode 100644 src/声源定位代码/back-code/development_board.py create mode 100644 src/声源定位代码/back-code/pc_server.py create mode 100644 src/声源定位代码/config.ini create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/.gitignore create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/README.md create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/index.html create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/package-lock.json create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/package.json create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/src/App.vue create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/src/assets/main.css create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/src/components/SourceDataService.js create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/src/main.js create mode 100644 src/声源定位代码/front-code/sound-vue-frontend/vue.config.js create mode 100644 src/声源定位代码/mic-code/Maix/Maix_config.c create mode 100644 src/声源定位代码/mic-code/Maix/Maix_fft.c create mode 100644 src/声源定位代码/mic-code/Maix/Maix_fpioa.c create mode 100644 src/声源定位代码/mic-code/Maix/Maix_gpio.c create mode 100644 src/声源定位代码/mic-code/Maix/Maix_i2s.c create mode 100644 src/声源定位代码/mic-code/Maix/Maix_kpu.c create mode 100644 src/声源定位代码/mic-code/Maix/Maix_kpu_classifier.c create mode 100644 src/声源定位代码/mic-code/Maix/Maix_mic_array.c create mode 100644 src/声源定位代码/mic-code/Maix/Maix_utils.c create mode 100644 src/声源定位代码/mic-code/Maix/include/Maix_config.h create mode 100644 src/声源定位代码/mic-code/Maix/include/Maix_i2s.h create mode 100644 src/声源定位代码/mic-code/Maix/include/Maix_kpu.h create mode 100644 src/声源定位代码/mic-code/Maix/include/modMaix.h create mode 100644 src/声源定位代码/mic-code/Maix/include/py_cpufreq.h create mode 100644 src/声源定位代码/mic-code/Maix/modMaix.c create mode 100644 src/声源定位代码/mic-code/Maix/py_cpufreq.c create mode 100644 src/声源定位代码/mic-code/init-code/main.py create mode 100644 src/声源定位代码/mic-code/init-code/main_raw.py create mode 100644 src/声源定位代码/mic-code/init-code/tcp_listen.py create mode 100644 src/声源定位代码/mic-code/init-code/test_send.py create mode 100644 src/声源定位代码/mic-code/init-code/wifi_connection.py create mode 100644 src/声源定位代码/mic-code/sound_map.py create mode 100644 src/声源定位代码/mic-code/sound_map_wifi.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/.vscode/settings.json create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/.gitignore create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/demo.iml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/inspectionProfiles/Project_Default.xml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/misc.xml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/modules.xml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/vcs.xml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/details.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff-details.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.csv create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.txt create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.csv create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.json create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.txt create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.gitignore create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/LICENSE create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/README.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/README_en.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/README.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/app.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/config.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/requirements.txt create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/index.html create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/package.json create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/App.vue create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder.vue create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioUpload.vue create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/HistoryList.vue create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/PredictionResult.vue create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/main.js create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/router/index.js create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/utils/api.js create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/views/HomePage.vue create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/vite.config.js create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/yarn.lock create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/start.bat create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/start.sh create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/augmentation.yml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/cam++.yml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/ecapa_tdnn.yml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/eres2net.yml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/panns.yml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/res2net.yml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/resnet_se.yml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/tdnn.yml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/create_data.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/docs/images/image1.png create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/docs/images/log.jpg create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/eval.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/extract_features.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/infer.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/infer_record.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/__init__.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/__init__.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/collate_fn.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/featurizer.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/reader.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/metric/__init__.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/metric/metrics.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/optimizer/__init__.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/optimizer/scheduler.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/predict.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/trainer.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/__init__.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/checkpoint.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/record.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/utils.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/record_audio.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/requirements.txt create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/setup.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/tools/download_language_data.sh create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/train.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/README.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/config.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/create_tables_simple.sql create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/create_tables_simple_mysql.sql create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/db_utils.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/init_database.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/requirements.txt create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/setup_database.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/FFVideoFormatConvert.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/FFVideoFormatConvert.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/MapWidget.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/MapWidget.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/QtCameraCapture.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/QtCameraCapture.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/README.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/RecordingFlash_32x32.png create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/ShaderSourceCode.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VLKVideoWidget.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VLKVideoWidget.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjNetwork.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjNetwork.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjUSBCamera.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjUSBCamera.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/circle_empty_48x48.png create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/circle_selected_32x32.png create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/demo_for_qt.pro create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/demo_for_qt.pro.user create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/image/RecordingFlash_32x32.png create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/image/circle_empty_48x48.png create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/image/circle_selected_32x32.png create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/imagepreviewdialog.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/imagepreviewdialog.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/main.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/qml/Map.qml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/qml/TargetMarker.qml create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/res.qrc create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.cpp.new create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.ui create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget_new.ui.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/.gitignore create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/flask_app.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/main.py create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/.gitignore create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/README.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/index.html create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/package-lock.json create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/package.json create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/App.vue create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/assets/main.css create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/components/SourceDataService.js create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/main.js create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/vue.config.js create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/CMakeLists.txt create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/README.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/image_processor.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/image_processor.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/main.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/zhipu_api.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/zhipu_api.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/CMakeLists.txt create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/README.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/compile.sh create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/tcp_client.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/CMakeLists.txt create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/README.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/build.sh create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/include/mavlink_client.h create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/run.sh create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/src/main.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/src/mavlink_client.cpp create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/使用说明.md create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/doc/ViewLinkSDK.chm create mode 100644 src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/inc/ViewLink.h diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..c5715d2 --- /dev/null +++ b/src/README.md @@ -0,0 +1 @@ +# 这是一个src \ No newline at end of file diff --git a/src/声源定位代码/README_声源定位系统.md b/src/声源定位代码/README_声源定位系统.md new file mode 100644 index 0000000..d599298 --- /dev/null +++ b/src/声源定位代码/README_声源定位系统.md @@ -0,0 +1,216 @@ +# 声源定位系统使用说明 + +## 系统概述 + +本系统由开发板端和PC端组成,实现声源定位和枪声识别功能。 + +### 工作流程 + +1. **开发板端**:开机后进入录音状态,持续录音并发送给PC端 +2. **PC端**:接收音频数据,使用audio-classification进行枪声识别 +3. **模式切换**:当识别到枪声时,PC端发送指令给开发板切换到定位模式 +4. **声源定位**:开发板在定位模式下实时发送声源定位数据给PC端 +5. **可视化**:PC端实时显示声源定位地图 + +## 文件说明 + +### 开发板端文件 +- `development_board_simple.py` - 简化版开发板端主程序(推荐使用) +- `development_board.py` - 完整版开发板端主程序 + +### PC端文件 +- `pc_server.py` - PC端服务器程序 + +## 配置说明 + +### 开发板端配置 + +在 `development_board_simple.py` 中修改以下配置: + +```python +# WiFi配置 +WIFI_SSID = "junzekeki" # 替换为你的WiFi SSID +WIFI_PASSWD = "234567890l" # 替换为你的WiFi密码 + +# PC端配置 +PC_IP = "192.168.1.100" # PC端IP地址,需要根据实际情况修改 +PC_PORT_AUDIO = 12346 # 音频传输端口 +PC_PORT_CMD = 12347 # 指令传输端口 +PC_PORT_LOCATION = 12348 # 定位数据传输端口 +``` + +### PC端配置 + +在 `pc_server.py` 中修改以下配置: + +```python +# 网络配置 +HOST = "0.0.0.0" # 监听所有网络接口 +PORT_AUDIO = 12346 # 音频接收端口 +PORT_CMD = 12347 # 指令发送端口 +PORT_LOCATION = 12348 # 定位数据接收端口 + +# 枪声识别配置 +GUNSHOT_THRESHOLD = 0.7 # 枪声识别阈值 +RECOGNITION_INTERVAL = 3.0 # 识别间隔(秒) +``` + +## 使用步骤 + +### 1. 环境准备 + +#### PC端环境 +```bash +# 安装依赖 +pip install numpy matplotlib soundfile librosa + +# 如果使用audio-classification +cd audio-classification +pip install -r requirements.txt +``` + +#### 开发板端环境 +确保开发板已安装以下模块: +- `fpioa_manager` +- `Maix` +- `board` +- `network` +- `socket` +- `machine` + +### 2. 网络配置 + +1. 确保开发板和PC在同一个WiFi网络下 +2. 获取PC的IP地址(Windows: `ipconfig`, Linux/Mac: `ifconfig`) +3. 修改开发板端代码中的 `PC_IP` 为PC的实际IP地址 + +### 3. 启动系统 + +#### 启动PC端服务器 +```bash +python pc_server.py +``` + +#### 启动开发板端 +将 `development_board_simple.py` 上传到开发板并运行: +```bash +python development_board_simple.py +``` + +### 4. 系统运行 + +1. **初始化阶段**: + - 开发板自动连接WiFi + - 建立与PC端的Socket连接 + - 进入录音模式 + +2. **录音模式**: + - 开发板持续录音并发送音频数据 + - PC端接收音频并进行枪声识别 + - 控制台显示识别结果 + +3. **定位模式**: + - 当检测到枪声时,PC端发送"START_LOCATION"指令 + - 开发板切换到定位模式 + - 实时发送声源定位数据 + - PC端显示实时定位地图 + +4. **模式切换**: + - 可通过关闭程序或发送"STOP_LOCATION"指令返回录音模式 + +## 通信协议 + +### 音频数据传输 +- 端口:12346 +- 格式:原始音频字节流(16位,16kHz,单声道) + +### 指令传输 +- 端口:12347 +- 格式:UTF-8字符串 +- 指令: + - `START_LOCATION` - 切换到定位模式 + - `STOP_LOCATION` - 切换到录音模式 + +### 定位数据传输 +- 端口:12348 +- 格式:`X,Y,强度,角度`(CSV格式) +- 示例:`1.234,2.345,3.456,45.67` + +## 故障排除 + +### 常见问题 + +1. **WiFi连接失败** + - 检查WiFi SSID和密码是否正确 + - 确保WiFi信号强度足够 + - 检查开发板WiFi模块是否正常 + +2. **Socket连接失败** + - 检查PC IP地址是否正确 + - 确保防火墙未阻止端口 + - 检查网络连接是否正常 + +3. **音频识别失败** + - 检查audio-classification模型是否正确安装 + - 确认模型文件路径是否正确 + - 检查音频数据格式是否符合要求 + +4. **定位数据异常** + - 检查麦克风阵列连接 + - 确认麦克风阵列初始化是否成功 + - 检查环境噪声是否过大 + +### 调试方法 + +1. **查看控制台输出** + - 开发板端和PC端都会输出详细的运行日志 + - 根据日志信息定位问题 + +2. **网络测试** + - 使用ping命令测试网络连通性 + - 使用telnet测试端口是否开放 + +3. **音频测试** + - 使用现有音频文件测试识别功能 + - 检查音频数据是否正确接收 + +## 扩展功能 + +### 自定义音频识别 +可以修改PC端代码,使用其他音频分类模型或自定义识别逻辑。 + +### 数据记录 +可以添加数据记录功能,保存音频文件和定位数据。 + +### 多设备支持 +可以扩展支持多个开发板同时工作。 + +### 远程控制 +可以添加Web界面进行远程控制和监控。 + +## 注意事项 + +1. **安全考虑** + - 本系统仅用于测试和演示 + - 请勿用于实际的安全监控场景 + - 注意保护个人隐私 + +2. **性能优化** + - 根据实际需求调整识别间隔 + - 优化网络传输参数 + - 考虑使用更高效的音频编码 + +3. **硬件要求** + - 开发板需要支持WiFi和麦克风阵列 + - PC端需要足够的计算能力进行音频识别 + - 建议使用有线网络连接以提高稳定性 + +## 技术支持 + +如有问题,请检查: +1. 代码配置是否正确 +2. 网络连接是否正常 +3. 硬件连接是否牢固 +4. 依赖库是否正确安装 + +更多技术细节请参考项目中的其他文档和代码注释。 \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/details.md b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/details.md new file mode 100644 index 0000000..f1a1fd9 --- /dev/null +++ b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/details.md @@ -0,0 +1,69 @@ +# Details + +Date : 2025-06-10 08:55:17 + +Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master + +Total : 54 files, 6851 codes, 838 comments, 1201 blanks, all 8890 lines + +[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md) + +## Files +| filename | language | code | comment | blank | total | +| :--- | :--- | ---: | ---: | ---: | ---: | +| [README.md](/README.md) | Markdown | 302 | 0 | 72 | 374 | +| [README\_en.md](/README_en.md) | Markdown | 231 | 0 | 45 | 276 | +| [audio-classification-platform/README.md](/audio-classification-platform/README.md) | Markdown | 96 | 0 | 41 | 137 | +| [audio-classification-platform/backend/app.py](/audio-classification-platform/backend/app.py) | Python | 255 | 35 | 61 | 351 | +| [audio-classification-platform/backend/config.py](/audio-classification-platform/backend/config.py) | Python | 22 | 8 | 10 | 40 | +| [audio-classification-platform/backend/requirements.txt](/audio-classification-platform/backend/requirements.txt) | pip requirements | 7 | 0 | 1 | 8 | +| [audio-classification-platform/frontend/index.html](/audio-classification-platform/frontend/index.html) | HTML | 25 | 0 | 2 | 27 | +| [audio-classification-platform/frontend/package.json](/audio-classification-platform/frontend/package.json) | JSON | 24 | 0 | 1 | 25 | +| [audio-classification-platform/frontend/src/App.vue](/audio-classification-platform/frontend/src/App.vue) | Vue | 88 | 5 | 14 | 107 | +| [audio-classification-platform/frontend/src/components/AudioRecorder.vue](/audio-classification-platform/frontend/src/components/AudioRecorder.vue) | Vue | 551 | 38 | 102 | 691 | +| [audio-classification-platform/frontend/src/components/AudioRecorder\_new.vue](/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue) | Vue | 811 | 48 | 162 | 1,021 | +| [audio-classification-platform/frontend/src/components/AudioUpload.vue](/audio-classification-platform/frontend/src/components/AudioUpload.vue) | Vue | 580 | 28 | 107 | 715 | +| [audio-classification-platform/frontend/src/components/HistoryList.vue](/audio-classification-platform/frontend/src/components/HistoryList.vue) | Vue | 513 | 25 | 79 | 617 | +| [audio-classification-platform/frontend/src/components/PredictionResult.vue](/audio-classification-platform/frontend/src/components/PredictionResult.vue) | Vue | 803 | 22 | 117 | 942 | +| [audio-classification-platform/frontend/src/main.js](/audio-classification-platform/frontend/src/main.js) | JavaScript | 13 | 1 | 5 | 19 | +| [audio-classification-platform/frontend/src/router/index.js](/audio-classification-platform/frontend/src/router/index.js) | JavaScript | 14 | 0 | 4 | 18 | +| [audio-classification-platform/frontend/src/utils/api.js](/audio-classification-platform/frontend/src/utils/api.js) | JavaScript | 156 | 25 | 33 | 214 | +| [audio-classification-platform/frontend/src/views/HomePage.vue](/audio-classification-platform/frontend/src/views/HomePage.vue) | Vue | 692 | 40 | 110 | 842 | +| [audio-classification-platform/frontend/vite.config.js](/audio-classification-platform/frontend/vite.config.js) | JavaScript | 32 | 0 | 2 | 34 | +| [audio-classification-platform/start.bat](/audio-classification-platform/start.bat) | Batch | 20 | 0 | 5 | 25 | +| [audio-classification-platform/start.sh](/audio-classification-platform/start.sh) | Shell Script | 26 | 3 | 8 | 37 | +| [configs/augmentation.yml](/configs/augmentation.yml) | YAML | 21 | 21 | 5 | 47 | +| [configs/cam++.yml](/configs/cam++.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/ecapa\_tdnn.yml](/configs/ecapa_tdnn.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/eres2net.yml](/configs/eres2net.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/panns.yml](/configs/panns.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/res2net.yml](/configs/res2net.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/resnet\_se.yml](/configs/resnet_se.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/tdnn.yml](/configs/tdnn.yml) | YAML | 43 | 33 | 5 | 81 | +| [create\_data.py](/create_data.py) | Python | 75 | 9 | 16 | 100 | +| [eval.py](/eval.py) | Python | 20 | 2 | 5 | 27 | +| [extract\_features.py](/extract_features.py) | Python | 13 | 2 | 5 | 20 | +| [infer.py](/infer.py) | Python | 17 | 1 | 6 | 24 | +| [infer\_record.py](/infer_record.py) | Python | 40 | 7 | 12 | 59 | +| [macls/\_\_init\_\_.py](/macls/__init__.py) | Python | 1 | 0 | 1 | 2 | +| [macls/data\_utils/\_\_init\_\_.py](/macls/data_utils/__init__.py) | Python | 0 | 0 | 1 | 1 | +| [macls/data\_utils/collate\_fn.py](/macls/data_utils/collate_fn.py) | Python | 17 | 4 | 3 | 24 | +| [macls/data\_utils/featurizer.py](/macls/data_utils/featurizer.py) | Python | 88 | 36 | 9 | 133 | +| [macls/data\_utils/reader.py](/macls/data_utils/reader.py) | Python | 114 | 33 | 11 | 158 | +| [macls/metric/\_\_init\_\_.py](/macls/metric/__init__.py) | Python | 0 | 0 | 1 | 1 | +| [macls/metric/metrics.py](/macls/metric/metrics.py) | Python | 9 | 1 | 3 | 13 | +| [macls/optimizer/\_\_init\_\_.py](/macls/optimizer/__init__.py) | Python | 26 | 0 | 7 | 33 | +| [macls/optimizer/scheduler.py](/macls/optimizer/scheduler.py) | Python | 42 | 0 | 7 | 49 | +| [macls/predict.py](/macls/predict.py) | Python | 124 | 47 | 7 | 178 | +| [macls/trainer.py](/macls/trainer.py) | Python | 338 | 99 | 20 | 457 | +| [macls/utils/\_\_init\_\_.py](/macls/utils/__init__.py) | Python | 0 | 0 | 1 | 1 | +| [macls/utils/checkpoint.py](/macls/utils/checkpoint.py) | Python | 113 | 40 | 10 | 163 | +| [macls/utils/record.py](/macls/utils/record.py) | Python | 18 | 8 | 6 | 32 | +| [macls/utils/utils.py](/macls/utils/utils.py) | Python | 99 | 16 | 17 | 132 | +| [record\_audio.py](/record_audio.py) | Python | 10 | 0 | 5 | 15 | +| [requirements.txt](/requirements.txt) | pip requirements | 17 | 0 | 1 | 18 | +| [setup.py](/setup.py) | Python | 43 | 1 | 11 | 55 | +| [tools/download\_language\_data.sh](/tools/download_language_data.sh) | Shell Script | 19 | 1 | 10 | 30 | +| [train.py](/train.py) | Python | 25 | 1 | 5 | 31 | + +[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md) \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff-details.md b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff-details.md new file mode 100644 index 0000000..55f2906 --- /dev/null +++ b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff-details.md @@ -0,0 +1,15 @@ +# Diff Details + +Date : 2025-06-10 08:55:17 + +Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master + +Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines + +[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details + +## Files +| filename | language | code | comment | blank | total | +| :--- | :--- | ---: | ---: | ---: | ---: | + +[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.csv b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.csv new file mode 100644 index 0000000..b7d8d75 --- /dev/null +++ b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.csv @@ -0,0 +1,2 @@ +"filename", "language", "", "comment", "blank", "total" +"Total", "-", , 0, 0, 0 \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.md b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.md new file mode 100644 index 0000000..0cab177 --- /dev/null +++ b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.md @@ -0,0 +1,19 @@ +# Diff Summary + +Date : 2025-06-10 08:55:17 + +Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master + +Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines + +[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md) + +## Languages +| language | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | + +## Directories +| path | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | + +[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md) \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.txt b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.txt new file mode 100644 index 0000000..b332216 --- /dev/null +++ b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.txt @@ -0,0 +1,22 @@ +Date : 2025-06-10 08:55:17 +Directory : e:\pycharm_projects\AudioClassification-Pytorch-master +Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines + +Languages ++----------+------------+------------+------------+------------+------------+ +| language | files | code | comment | blank | total | ++----------+------------+------------+------------+------------+------------+ ++----------+------------+------------+------------+------------+------------+ + +Directories ++------+------------+------------+------------+------------+------------+ +| path | files | code | comment | blank | total | ++------+------------+------------+------------+------------+------------+ ++------+------------+------------+------------+------------+------------+ + +Files ++----------+----------+------------+------------+------------+------------+ +| filename | language | code | comment | blank | total | ++----------+----------+------------+------------+------------+------------+ +| Total | | 0 | 0 | 0 | 0 | ++----------+----------+------------+------------+------------+------------+ \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.csv b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.csv new file mode 100644 index 0000000..6cde0c8 --- /dev/null +++ b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.csv @@ -0,0 +1,56 @@ +"filename", "language", "Python", "pip requirements", "Markdown", "Shell Script", "YAML", "Batch", "JavaScript", "Vue", "JSON", "HTML", "comment", "blank", "total" +"e:\pycharm_projects\AudioClassification-Pytorch-master\README.md", "Markdown", 0, 0, 302, 0, 0, 0, 0, 0, 0, 0, 0, 72, 374 +"e:\pycharm_projects\AudioClassification-Pytorch-master\README_en.md", "Markdown", 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 0, 45, 276 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\README.md", "Markdown", 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 41, 137 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\app.py", "Python", 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 61, 351 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\config.py", "Python", 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 40 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\requirements.txt", "pip requirements", 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 8 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\index.html", "HTML", 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 2, 27 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\package.json", "JSON", 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 1, 25 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\App.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 5, 14, 107 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 551, 0, 0, 38, 102, 691 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder_new.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 811, 0, 0, 48, 162, 1021 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioUpload.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 580, 0, 0, 28, 107, 715 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\HistoryList.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 513, 0, 0, 25, 79, 617 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\PredictionResult.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 803, 0, 0, 22, 117, 942 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\main.js", "JavaScript", 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 1, 5, 19 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\router\index.js", "JavaScript", 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 4, 18 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\utils\api.js", "JavaScript", 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 25, 33, 214 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\views\HomePage.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 692, 0, 0, 40, 110, 842 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\vite.config.js", "JavaScript", 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 2, 34 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.bat", "Batch", 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 5, 25 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.sh", "Shell Script", 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 3, 8, 37 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\augmentation.yml", "YAML", 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 21, 5, 47 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\cam++.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\ecapa_tdnn.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\eres2net.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\panns.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\res2net.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\resnet_se.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\tdnn.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\create_data.py", "Python", 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 16, 100 +"e:\pycharm_projects\AudioClassification-Pytorch-master\eval.py", "Python", 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 27 +"e:\pycharm_projects\AudioClassification-Pytorch-master\extract_features.py", "Python", 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 20 +"e:\pycharm_projects\AudioClassification-Pytorch-master\infer.py", "Python", 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 24 +"e:\pycharm_projects\AudioClassification-Pytorch-master\infer_record.py", "Python", 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 12, 59 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\__init__.py", "Python", 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\__init__.py", "Python", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\collate_fn.py", "Python", 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 3, 24 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\featurizer.py", "Python", 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 9, 133 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\reader.py", "Python", 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 11, 158 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\__init__.py", "Python", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\metrics.py", "Python", 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 13 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\__init__.py", "Python", 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 33 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\scheduler.py", "Python", 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 49 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\predict.py", "Python", 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 7, 178 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\trainer.py", "Python", 338, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 20, 457 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\__init__.py", "Python", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\checkpoint.py", "Python", 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 10, 163 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\record.py", "Python", 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 6, 32 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\utils.py", "Python", 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 132 +"e:\pycharm_projects\AudioClassification-Pytorch-master\record_audio.py", "Python", 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 15 +"e:\pycharm_projects\AudioClassification-Pytorch-master\requirements.txt", "pip requirements", 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 18 +"e:\pycharm_projects\AudioClassification-Pytorch-master\setup.py", "Python", 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11, 55 +"e:\pycharm_projects\AudioClassification-Pytorch-master\tools\download_language_data.sh", "Shell Script", 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 1, 10, 30 +"e:\pycharm_projects\AudioClassification-Pytorch-master\train.py", "Python", 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 31 +"Total", "-", 1509, 24, 629, 45, 322, 20, 215, 4038, 24, 25, 838, 1201, 8890 \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.json b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.json new file mode 100644 index 0000000..922a690 --- /dev/null +++ b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.json @@ -0,0 +1 @@ +{"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/record_audio.py":{"language":"Python","code":10,"comment":0,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/train.py":{"language":"Python","code":25,"comment":1,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/setup.py":{"language":"Python","code":43,"comment":1,"blank":11},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/requirements.txt":{"language":"pip requirements","code":17,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/README_en.md":{"language":"Markdown","code":231,"comment":0,"blank":45},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/tools/download_language_data.sh":{"language":"Shell Script","code":19,"comment":1,"blank":10},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/infer.py":{"language":"Python","code":17,"comment":1,"blank":6},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/infer_record.py":{"language":"Python","code":40,"comment":7,"blank":12},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/__init__.py":{"language":"Python","code":1,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/extract_features.py":{"language":"Python","code":13,"comment":2,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/README.md":{"language":"Markdown","code":302,"comment":0,"blank":72},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/create_data.py":{"language":"Python","code":75,"comment":9,"blank":16},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/trainer.py":{"language":"Python","code":338,"comment":99,"blank":20},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/optimizer/__init__.py":{"language":"Python","code":26,"comment":0,"blank":7},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/optimizer/scheduler.py":{"language":"Python","code":42,"comment":0,"blank":7},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/predict.py":{"language":"Python","code":124,"comment":47,"blank":7},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/eval.py":{"language":"Python","code":20,"comment":2,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/tdnn.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/resnet_se.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/panns.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/res2net.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/ecapa_tdnn.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/cam%2B%2B.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/eres2net.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/utils/utils.py":{"language":"Python","code":99,"comment":16,"blank":17},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/metric/metrics.py":{"language":"Python","code":9,"comment":1,"blank":3},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/augmentation.yml":{"language":"YAML","code":21,"comment":21,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/utils/__init__.py":{"language":"Python","code":0,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/utils/record.py":{"language":"Python","code":18,"comment":8,"blank":6},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/metric/__init__.py":{"language":"Python","code":0,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/utils/checkpoint.py":{"language":"Python","code":113,"comment":40,"blank":10},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/start.sh":{"language":"Shell Script","code":26,"comment":3,"blank":8},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/start.bat":{"language":"Batch","code":20,"comment":0,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/README.md":{"language":"Markdown","code":96,"comment":0,"blank":41},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/data_utils/reader.py":{"language":"Python","code":114,"comment":33,"blank":11},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/data_utils/featurizer.py":{"language":"Python","code":88,"comment":36,"blank":9},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/vite.config.js":{"language":"JavaScript","code":32,"comment":0,"blank":2},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/data_utils/collate_fn.py":{"language":"Python","code":17,"comment":4,"blank":3},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/data_utils/__init__.py":{"language":"Python","code":0,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/main.js":{"language":"JavaScript","code":13,"comment":1,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/views/HomePage.vue":{"language":"Vue","code":692,"comment":40,"blank":110},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/backend/config.py":{"language":"Python","code":22,"comment":8,"blank":10},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/App.vue":{"language":"Vue","code":88,"comment":5,"blank":14},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/package.json":{"language":"JSON","code":24,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/index.html":{"language":"HTML","code":25,"comment":0,"blank":2},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/backend/requirements.txt":{"language":"pip requirements","code":7,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/HistoryList.vue":{"language":"Vue","code":513,"comment":25,"blank":79},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/AudioUpload.vue":{"language":"Vue","code":580,"comment":28,"blank":107},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/backend/app.py":{"language":"Python","code":255,"comment":35,"blank":61},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/PredictionResult.vue":{"language":"Vue","code":803,"comment":22,"blank":117},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue":{"language":"Vue","code":811,"comment":48,"blank":162},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/utils/api.js":{"language":"JavaScript","code":156,"comment":25,"blank":33},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/router/index.js":{"language":"JavaScript","code":14,"comment":0,"blank":4},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/AudioRecorder.vue":{"language":"Vue","code":551,"comment":38,"blank":102}} \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.md b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.md new file mode 100644 index 0000000..ac3e4e6 --- /dev/null +++ b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.md @@ -0,0 +1,50 @@ +# Summary + +Date : 2025-06-10 08:55:17 + +Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master + +Total : 54 files, 6851 codes, 838 comments, 1201 blanks, all 8890 lines + +Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md) + +## Languages +| language | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | +| Vue | 7 | 4,038 | 206 | 691 | 4,935 | +| Python | 25 | 1,509 | 350 | 240 | 2,099 | +| Markdown | 3 | 629 | 0 | 158 | 787 | +| YAML | 8 | 322 | 252 | 40 | 614 | +| JavaScript | 4 | 215 | 26 | 44 | 285 | +| Shell Script | 2 | 45 | 4 | 18 | 67 | +| HTML | 1 | 25 | 0 | 2 | 27 | +| pip requirements | 2 | 24 | 0 | 2 | 26 | +| JSON | 1 | 24 | 0 | 1 | 25 | +| Batch | 1 | 20 | 0 | 5 | 25 | + +## Directories +| path | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | +| . | 54 | 6,851 | 838 | 1,201 | 8,890 | +| . (Files) | 11 | 793 | 23 | 183 | 999 | +| audio-classification-platform | 19 | 4,728 | 278 | 864 | 5,870 | +| audio-classification-platform (Files) | 3 | 142 | 3 | 54 | 199 | +| audio-classification-platform\\backend | 3 | 284 | 43 | 72 | 399 | +| audio-classification-platform\\frontend | 13 | 4,302 | 232 | 738 | 5,272 | +| audio-classification-platform\\frontend (Files) | 3 | 81 | 0 | 5 | 86 | +| audio-classification-platform\\frontend\\src | 10 | 4,221 | 232 | 733 | 5,186 | +| audio-classification-platform\\frontend\\src (Files) | 2 | 101 | 6 | 19 | 126 | +| audio-classification-platform\\frontend\\src\\components | 5 | 3,258 | 161 | 567 | 3,986 | +| audio-classification-platform\\frontend\\src\\router | 1 | 14 | 0 | 4 | 18 | +| audio-classification-platform\\frontend\\src\\utils | 1 | 156 | 25 | 33 | 214 | +| audio-classification-platform\\frontend\\src\\views | 1 | 692 | 40 | 110 | 842 | +| configs | 8 | 322 | 252 | 40 | 614 | +| macls | 15 | 989 | 284 | 104 | 1,377 | +| macls (Files) | 3 | 463 | 146 | 28 | 637 | +| macls\\data_utils | 4 | 219 | 73 | 24 | 316 | +| macls\\metric | 2 | 9 | 1 | 4 | 14 | +| macls\\optimizer | 2 | 68 | 0 | 14 | 82 | +| macls\\utils | 4 | 230 | 64 | 34 | 328 | +| tools | 1 | 19 | 1 | 10 | 30 | + +Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md) \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.txt b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.txt new file mode 100644 index 0000000..8367acc --- /dev/null +++ b/src/声源定位代码/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.txt @@ -0,0 +1,107 @@ +Date : 2025-06-10 08:55:17 +Directory : e:\pycharm_projects\AudioClassification-Pytorch-master +Total : 54 files, 6851 codes, 838 comments, 1201 blanks, all 8890 lines + +Languages ++------------------+------------+------------+------------+------------+------------+ +| language | files | code | comment | blank | total | ++------------------+------------+------------+------------+------------+------------+ +| Vue | 7 | 4,038 | 206 | 691 | 4,935 | +| Python | 25 | 1,509 | 350 | 240 | 2,099 | +| Markdown | 3 | 629 | 0 | 158 | 787 | +| YAML | 8 | 322 | 252 | 40 | 614 | +| JavaScript | 4 | 215 | 26 | 44 | 285 | +| Shell Script | 2 | 45 | 4 | 18 | 67 | +| HTML | 1 | 25 | 0 | 2 | 27 | +| pip requirements | 2 | 24 | 0 | 2 | 26 | +| JSON | 1 | 24 | 0 | 1 | 25 | +| Batch | 1 | 20 | 0 | 5 | 25 | ++------------------+------------+------------+------------+------------+------------+ + +Directories ++------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+ +| path | files | code | comment | blank | total | ++------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+ +| . | 54 | 6,851 | 838 | 1,201 | 8,890 | +| . (Files) | 11 | 793 | 23 | 183 | 999 | +| audio-classification-platform | 19 | 4,728 | 278 | 864 | 5,870 | +| audio-classification-platform (Files) | 3 | 142 | 3 | 54 | 199 | +| audio-classification-platform\backend | 3 | 284 | 43 | 72 | 399 | +| audio-classification-platform\frontend | 13 | 4,302 | 232 | 738 | 5,272 | +| audio-classification-platform\frontend (Files) | 3 | 81 | 0 | 5 | 86 | +| audio-classification-platform\frontend\src | 10 | 4,221 | 232 | 733 | 5,186 | +| audio-classification-platform\frontend\src (Files) | 2 | 101 | 6 | 19 | 126 | +| audio-classification-platform\frontend\src\components | 5 | 3,258 | 161 | 567 | 3,986 | +| audio-classification-platform\frontend\src\router | 1 | 14 | 0 | 4 | 18 | +| audio-classification-platform\frontend\src\utils | 1 | 156 | 25 | 33 | 214 | +| audio-classification-platform\frontend\src\views | 1 | 692 | 40 | 110 | 842 | +| configs | 8 | 322 | 252 | 40 | 614 | +| macls | 15 | 989 | 284 | 104 | 1,377 | +| macls (Files) | 3 | 463 | 146 | 28 | 637 | +| macls\data_utils | 4 | 219 | 73 | 24 | 316 | +| macls\metric | 2 | 9 | 1 | 4 | 14 | +| macls\optimizer | 2 | 68 | 0 | 14 | 82 | +| macls\utils | 4 | 230 | 64 | 34 | 328 | +| tools | 1 | 19 | 1 | 10 | 30 | ++------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+ + +Files ++------------------------------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+ +| filename | language | code | comment | blank | total | ++------------------------------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+ +| e:\pycharm_projects\AudioClassification-Pytorch-master\README.md | Markdown | 302 | 0 | 72 | 374 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\README_en.md | Markdown | 231 | 0 | 45 | 276 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\README.md | Markdown | 96 | 0 | 41 | 137 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\app.py | Python | 255 | 35 | 61 | 351 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\config.py | Python | 22 | 8 | 10 | 40 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\requirements.txt | pip requirements | 7 | 0 | 1 | 8 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\index.html | HTML | 25 | 0 | 2 | 27 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\package.json | JSON | 24 | 0 | 1 | 25 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\App.vue | Vue | 88 | 5 | 14 | 107 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder.vue | Vue | 551 | 38 | 102 | 691 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder_new.vue | Vue | 811 | 48 | 162 | 1,021 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioUpload.vue | Vue | 580 | 28 | 107 | 715 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\HistoryList.vue | Vue | 513 | 25 | 79 | 617 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\PredictionResult.vue | Vue | 803 | 22 | 117 | 942 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\main.js | JavaScript | 13 | 1 | 5 | 19 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\router\index.js | JavaScript | 14 | 0 | 4 | 18 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\utils\api.js | JavaScript | 156 | 25 | 33 | 214 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\views\HomePage.vue | Vue | 692 | 40 | 110 | 842 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\vite.config.js | JavaScript | 32 | 0 | 2 | 34 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.bat | Batch | 20 | 0 | 5 | 25 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.sh | Shell Script | 26 | 3 | 8 | 37 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\augmentation.yml | YAML | 21 | 21 | 5 | 47 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\cam++.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\ecapa_tdnn.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\eres2net.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\panns.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\res2net.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\resnet_se.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\tdnn.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\create_data.py | Python | 75 | 9 | 16 | 100 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\eval.py | Python | 20 | 2 | 5 | 27 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\extract_features.py | Python | 13 | 2 | 5 | 20 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\infer.py | Python | 17 | 1 | 6 | 24 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\infer_record.py | Python | 40 | 7 | 12 | 59 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\__init__.py | Python | 1 | 0 | 1 | 2 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\__init__.py | Python | 0 | 0 | 1 | 1 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\collate_fn.py | Python | 17 | 4 | 3 | 24 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\featurizer.py | Python | 88 | 36 | 9 | 133 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\reader.py | Python | 114 | 33 | 11 | 158 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\__init__.py | Python | 0 | 0 | 1 | 1 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\metrics.py | Python | 9 | 1 | 3 | 13 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\__init__.py | Python | 26 | 0 | 7 | 33 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\scheduler.py | Python | 42 | 0 | 7 | 49 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\predict.py | Python | 124 | 47 | 7 | 178 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\trainer.py | Python | 338 | 99 | 20 | 457 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\__init__.py | Python | 0 | 0 | 1 | 1 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\checkpoint.py | Python | 113 | 40 | 10 | 163 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\record.py | Python | 18 | 8 | 6 | 32 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\utils.py | Python | 99 | 16 | 17 | 132 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\record_audio.py | Python | 10 | 0 | 5 | 15 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\requirements.txt | pip requirements | 17 | 0 | 1 | 18 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\setup.py | Python | 43 | 1 | 11 | 55 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\tools\download_language_data.sh | Shell Script | 19 | 1 | 10 | 30 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\train.py | Python | 25 | 1 | 5 | 31 | +| Total | | 6,851 | 838 | 1,201 | 8,890 | ++------------------------------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+ \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/.gitignore b/src/声源定位代码/audio-classification/.gitignore new file mode 100644 index 0000000..92da7e3 --- /dev/null +++ b/src/声源定位代码/audio-classification/.gitignore @@ -0,0 +1,296 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST +macls.egg-info/ + +# PyInstaller +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django/Flask stuff +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal +instance/ +.webassets-cache + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +Pipfile.lock + +# PEP 582 +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# Node.js dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +package-lock.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage +.grunt + +# Bower dependency directory +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons +build/Release + +# Dependency directories +jspm_packages/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env.local +.env.production + +# parcel-bundler cache +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt + +# Gatsby files +# Comment in the public line in if your project uses Gatsby +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# Audio Classification specific ignores +# Model files (usually large) +*.pth +*.pt +*.h5 +*.ckpt +*.pb +*.onnx +*.pkl +*.joblib + +# Dataset directories (usually large audio files) +dataset/ +dataset/*/audio/ +dataset/*/wav/ +dataset/*/mp3/ +dataset/*/flac/ +# Uncomment if you want to ignore all audio files +# *.wav +# *.mp3 +# *.flac +# *.ogg +# *.m4a +# *.aac + +# Training artifacts and logs +log/ +logs/ +output/ +outputs/ +uploads/ +results/ +checkpoints/ +models/ +pretrained_models/ +feature_models/ +runs/ +wandb/ +mlruns/ +.mlflow/ + +# Temporary files +temp/ +tmp/ +*.tmp +test*.py + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# IDE files +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Audio processing temporary files +*.spec +*.mfcc +*.mel + +# Frontend build files +audio-classification-platform/frontend/dist/ +audio-classification-platform/frontend/build/ +audio-classification-platform/frontend/.vite/ + +# Uploaded files directory +audio-classification-platform/backend/uploads/ + +# Local development configuration +audio-classification-platform/backend/.env +audio-classification-platform/frontend/.env.local \ No newline at end of file diff --git a/src/声源定位代码/audio-classification/LICENSE b/src/声源定位代码/audio-classification/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/src/声源定位代码/audio-classification/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/声源定位代码/audio-classification/README.md b/src/声源定位代码/audio-classification/README.md new file mode 100644 index 0000000..5e1aa31 --- /dev/null +++ b/src/声源定位代码/audio-classification/README.md @@ -0,0 +1,373 @@ +简体中文 | [English](./README_en.md) + +# 基于Pytorch实现的声音分类系统 + +![python version](https://img.shields.io/badge/python-3.8+-orange.svg) +![GitHub forks](https://img.shields.io/github/forks/yeyupiaoling/AudioClassification-Pytorch) +![GitHub Repo stars](https://img.shields.io/github/stars/yeyupiaoling/AudioClassification-Pytorch) +![GitHub](https://img.shields.io/github/license/yeyupiaoling/AudioClassification-Pytorch) +![支持系统](https://img.shields.io/badge/支持系统-Win/Linux/MAC-9cf) + +# 前言 + +本项目是基于Pytorch的声音分类项目,旨在实现对各种环境声音、动物叫声和语种的识别。项目提供了多种声音分类模型,如EcapaTdnn、PANNS、ResNetSE、CAMPPlus和ERes2Net,以支持不同的应用场景。此外,项目还提供了常用的Urbansound8K数据集测试报告和一些方言数据集的下载和使用例子。用户可以根据自己的需求选择适合的模型和数据集,以实现更准确的声音分类。项目的应用场景广泛,可以用于室外的环境监测、野生动物保护、语音识别等领域。同时,项目也鼓励用户探索更多的使用场景,以推动声音分类技术的发展和应用。 + +**欢迎大家扫码入知识星球或者QQ群讨论,知识星球里面提供项目的模型文件和博主其他相关项目的模型文件,也包括其他一些资源。** + +
+ 知识星球 + QQ群 +
+ + +# 目录 + +- [前言](#前言) +- [项目特性](#项目特性) +- [模型测试表](#模型测试表) +- [安装环境](#安装环境) +- [创建数据](#创建数据) +- [修改预处理方法(可选)](#修改预处理方法可选) +- [提取特征(可选)](#提取特征可选) +- [训练模型](#训练模型) +- [评估模型](#评估模型) +- [预测](#预测) +- [其他功能](#其他功能) + + +# 使用准备 + + - Anaconda 3 + - Python 3.11 + - Pytorch 2.0.1 + - Windows 11 or Ubuntu 22.04 + +# 项目特性 + +1. 支持模型:EcapaTdnn、PANNS、TDNN、Res2Net、ResNetSE、CAMPPlus、ERes2Net +2. 支持池化层:AttentiveStatsPool(ASP)、SelfAttentivePooling(SAP)、TemporalStatisticsPooling(TSP)、TemporalAveragePooling(TAP) +4. 支持预处理方法:MelSpectrogram、Spectrogram、MFCC、Fbank、Wav2vec2.0、WavLM + +**模型论文:** + +- EcapaTdnn:[ECAPA-TDNN: Emphasized Channel Attention, Propagation and Aggregation in TDNN Based Speaker Verification](https://arxiv.org/abs/2005.07143v3) +- PANNS:[PANNs: Large-Scale Pretrained Audio Neural Networks for Audio Pattern Recognition](https://arxiv.org/abs/1912.10211v5) +- TDNN:[Prediction of speech intelligibility with DNN-based performance measures](https://arxiv.org/abs/2203.09148) +- Res2Net:[Res2Net: A New Multi-scale Backbone Architecture](https://arxiv.org/abs/1904.01169) +- ResNetSE:[Squeeze-and-Excitation Networks](https://arxiv.org/abs/1709.01507) +- CAMPPlus:[CAM++: A Fast and Efficient Network for Speaker Verification Using Context-Aware Masking](https://arxiv.org/abs/2303.00332v3) +- ERes2Net:[An Enhanced Res2Net with Local and Global Feature Fusion for Speaker Verification](https://arxiv.org/abs/2305.12838v1) + +# 模型测试表 + +| 模型 | Params(M) | 预处理方法 | 数据集 | 类别数量 | 准确率 | 获取模型 | +|:------------:|:---------:|:-----:|:------------:|:----:|:-------:|:--------:| +| ResNetSE | 7.8 | Flank | UrbanSound8K | 10 | 0.96233 | 加入知识星球获取 | +| ERes2NetV2 | 5.4 | Flank | UrbanSound8K | 10 | 0.95662 | 加入知识星球获取 | +| CAMPPlus | 7.1 | Flank | UrbanSound8K | 10 | 0.95454 | 加入知识星球获取 | +| EcapaTdnn | 6.4 | Flank | UrbanSound8K | 10 | 0.95227 | 加入知识星球获取 | +| ERes2Net | 6.6 | Flank | UrbanSound8K | 10 | 0.94292 | 加入知识星球获取 | +| TDNN | 2.6 | Flank | UrbanSound8K | 10 | 0.93977 | 加入知识星球获取 | +| PANNS(CNN10) | 5.2 | Flank | UrbanSound8K | 10 | 0.92954 | 加入知识星球获取 | +| Res2Net | 5.0 | Flank | UrbanSound8K | 10 | 0.92580 | 加入知识星球获取 | + +**说明:** + +1. 使用的测试集为从数据集中每10条音频取一条,共874条。 + +## 安装环境 + + - 首先安装的是Pytorch的GPU版本,如果已经安装过了,请跳过。 +```shell +conda install pytorch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 pytorch-cuda=11.8 -c pytorch -c nvidia +``` + + - 安装macls库。 + +使用pip安装,命令如下: +```shell +python -m pip install macls -U -i https://pypi.tuna.tsinghua.edu.cn/simple +``` + +**建议源码安装**,源码安装能保证使用最新代码。 +```shell +git clone https://github.com/yeyupiaoling/AudioClassification-Pytorch.git +cd AudioClassification-Pytorch/ +pip install . +``` + +## 创建数据 + +生成数据列表,用于下一步的读取需要,`audio_path`为音频文件路径,用户需要提前把音频数据集存放在`dataset/audio`目录下,每个文件夹存放一个类别的音频数据,每条音频数据长度在3秒以上,如 `dataset/audio/鸟叫声/······`。`audio`是数据列表存放的位置,生成的数据类别的格式为 `音频路径\t音频对应的类别标签`,音频路径和标签用制表符 `\t`分开。读者也可以根据自己存放数据的方式修改以下函数。 + +以Urbansound8K为例,Urbansound8K是目前应用较为广泛的用于自动城市环境声分类研究的公共数据集,包含10个分类:空调声、汽车鸣笛声、儿童玩耍声、狗叫声、钻孔声、引擎空转声、枪声、手提钻、警笛声和街道音乐声。数据集下载地址:[UrbanSound8K.tar.gz](https://aistudio.baidu.com/aistudio/datasetdetail/36625)。以下是针对Urbansound8K生成数据列表的函数。如果读者想使用该数据集,请下载并解压到 `dataset`目录下,把生成数据列表代码改为以下代码。 + +执行`create_data.py`即可生成数据列表,里面提供了生成多种数据集列表方式,具体看代码。 +```shell +python create_data.py +``` + +生成的列表是长这样的,前面是音频的路径,后面是该音频对应的标签,从0开始,路径和标签之间用`\t`隔开。 +```shell +dataset/UrbanSound8K/audio/fold2/104817-4-0-2.wav 4 +dataset/UrbanSound8K/audio/fold9/105029-7-2-5.wav 7 +dataset/UrbanSound8K/audio/fold3/107228-5-0-0.wav 5 +dataset/UrbanSound8K/audio/fold4/109711-3-2-4.wav 3 +``` + +# 修改预处理方法(可选) + +配置文件中默认使用的是Fbank预处理方法,如果要使用其他预处理方法,可以修改配置文件中的安装下面方式修改,具体的值可以根据自己情况修改。如果不清楚如何设置参数,可以直接删除该部分,直接使用默认值。 + +```yaml +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 +``` + +# 提取特征(可选) + +在训练过程中,首先是要读取音频数据,然后提取特征,最后再进行训练。其中读取音频数据、提取特征也是比较消耗时间的,所以我们可以选择提前提取好取特征,训练模型的是就可以直接加载提取好的特征,这样训练速度会更快。这个提取特征是可选择,如果没有提取好的特征,训练模型的时候就会从读取音频数据,然后提取特征开始。提取特征步骤如下: + +1. 执行`extract_features.py`,提取特征,特征会保存在`dataset/features`目录下,并生成新的数据列表`train_list_features.txt`和`test_list_features.txt`。 + +```shell +python extract_features.py --configs=configs/cam++.yml --save_dir=dataset/features +``` + +2. 修改配置文件,将`dataset_conf.train_list`和`dataset_conf.test_list`修改为`train_list_features.txt`和`test_list_features.txt`。 + + +## 训练模型 + +接着就可以开始训练模型了,创建 `train.py`。配置文件里面的参数一般不需要修改,但是这几个是需要根据自己实际的数据集进行调整的,首先最重要的就是分类大小`dataset_conf.num_class`,这个每个数据集的分类大小可能不一样,根据自己的实际情况设定。然后是`dataset_conf.batch_size`,如果是显存不够的话,可以减小这个参数。 + +```shell +# 单卡训练 +CUDA_VISIBLE_DEVICES=0 python train.py +# 多卡训练 +CUDA_VISIBLE_DEVICES=0,1 torchrun --standalone --nnodes=1 --nproc_per_node=2 train.py +``` + +训练输出日志: +``` +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:14 - ----------- 额外配置参数 ----------- +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - configs: configs/ecapa_tdnn.yml +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - local_rank: 0 +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - pretrained_model: None +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - resume_model: None +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - save_model_path: models/ +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - use_gpu: True +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:17 - ------------------------------------------------ +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:19 - ----------- 配置文件参数 ----------- +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:22 - dataset_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - aug_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - noise_aug_prob: 0.2 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - noise_dir: dataset/noise +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - speed_perturb: True +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - volume_aug_prob: 0.2 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - volume_perturb: False +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - dataLoader: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - batch_size: 64 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - num_workers: 4 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - do_vad: False +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - eval_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - batch_size: 1 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - max_duration: 20 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - label_list_path: dataset/label_list.txt +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - max_duration: 3 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - min_duration: 0.5 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - sample_rate: 16000 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - spec_aug_args: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - freq_mask_width: [0, 8] +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - time_mask_width: [0, 10] +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - target_dB: -20 +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - test_list: dataset/test_list.txt +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - train_list: dataset/train_list.txt +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - use_dB_normalization: True +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - use_spec_aug: True +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:22 - model_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - num_class: 10 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - pooling_type: ASP +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:22 - optimizer_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - learning_rate: 0.001 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - optimizer: Adam +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - scheduler: WarmupCosineSchedulerLR +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:25 - scheduler_args: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - max_lr: 0.001 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - min_lr: 1e-05 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - warmup_epoch: 5 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - weight_decay: 1e-06 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:22 - preprocess_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - feature_method: Fbank +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:25 - method_args: +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:27 - num_mel_bins: 80 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:27 - sample_frequency: 16000 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:22 - train_conf: +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:29 - log_interval: 10 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:29 - max_epoch: 30 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:31 - use_model: EcapaTdnn +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:32 - ------------------------------------------------ +[2023-08-07 22:54:22.213166 WARNING] trainer:__init__:67 - Windows系统不支持多线程读取数据,已自动关闭! +========================================================================================== +Layer (type:depth-idx) Output Shape Param # +========================================================================================== +EcapaTdnn [1, 10] -- +├─Conv1dReluBn: 1-1 [1, 512, 98] -- +│ └─Conv1d: 2-1 [1, 512, 98] 204,800 +│ └─BatchNorm1d: 2-2 [1, 512, 98] 1,024 +├─Sequential: 1-2 [1, 512, 98] -- +│ └─Conv1dReluBn: 2-3 [1, 512, 98] -- +│ │ └─Conv1d: 3-1 [1, 512, 98] 262,144 +│ │ └─BatchNorm1d: 3-2 [1, 512, 98] 1,024 +│ └─Res2Conv1dReluBn: 2-4 [1, 512, 98] -- +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +··································· +│ │ └─ModuleList: 3-56 -- (recursive) +│ │ └─ModuleList: 3-55 -- (recursive) +│ │ └─ModuleList: 3-56 -- (recursive) +│ │ └─ModuleList: 3-55 -- (recursive) +│ │ └─ModuleList: 3-56 -- (recursive) +│ └─Conv1dReluBn: 2-13 [1, 512, 98] -- +│ │ └─Conv1d: 3-57 [1, 512, 98] 262,144 +│ │ └─BatchNorm1d: 3-58 [1, 512, 98] 1,024 +│ └─SE_Connect: 2-14 [1, 512, 98] -- +│ │ └─Linear: 3-59 [1, 256] 131,328 +│ │ └─Linear: 3-60 [1, 512] 131,584 +├─Conv1d: 1-5 [1, 1536, 98] 2,360,832 +├─AttentiveStatsPool: 1-6 [1, 3072] -- +│ └─Conv1d: 2-15 [1, 128, 98] 196,736 +│ └─Conv1d: 2-16 [1, 1536, 98] 198,144 +├─BatchNorm1d: 1-7 [1, 3072] 6,144 +├─Linear: 1-8 [1, 192] 590,016 +├─BatchNorm1d: 1-9 [1, 192] 384 +├─Linear: 1-10 [1, 10] 1,930 +========================================================================================== +Total params: 6,188,490 +Trainable params: 6,188,490 +Non-trainable params: 0 +Total mult-adds (M): 470.96 +========================================================================================== +Input size (MB): 0.03 +Forward/backward pass size (MB): 10.28 +Params size (MB): 24.75 +Estimated Total Size (MB): 35.07 +========================================================================================== +[2023-08-07 22:54:26.726095 INFO ] trainer:train:344 - 训练数据:8644 +[2023-08-07 22:54:30.092504 INFO ] trainer:__train_epoch:296 - Train epoch: [1/30], batch: [0/4], loss: 2.57033, accuracy: 0.06250, learning rate: 0.00001000, speed: 19.02 data/sec, eta: 0:06:43 +``` + +**训练可视化:** + +项目的根目录执行下面命令,并网页访问`http://localhost:8040/`,如果是服务器,需要修改`localhost`为服务器的IP地址。 +```shell +visualdl --logdir=log --host=0.0.0.0 +``` + +打开的网页如下: + +
+
+混淆矩阵 +
+ + + +# 评估模型 + +执行下面命令执行评估。 + +```shell +python eval.py --configs=configs/bi_lstm.yml +``` + +评估输出如下: +```shell +[2025-02-03 15:13:25.469242 INFO ] trainer:evaluate:461 - 成功加载模型:models/CAMPPlus_Fbank/best_model/model.pth +100%|██████████████████████████████| 150/150 [00:00<00:00, 1281.96it/s] +评估消耗时间:1s,loss:0.61840,accuracy:0.87333 +``` + +评估会出来输出准确率,还保存了混淆矩阵图片,保存路径`output/images/`,如下。 + +
+
+混淆矩阵 +
+ + +注意:如果类别标签是中文的,需要设置安装字体才能正常显示,一般情况下Windows无需安装,Ubuntu需要安装。如果Windows确实是缺少字体,只需要[字体文件](https://github.com/tracyone/program_font)这里下载`.ttf`格式的文件,复制到`C:\Windows\Fonts`即可。Ubuntu系统操作如下。 + +1. 安装字体 +```shell +git clone https://github.com/tracyone/program_font && cd program_font && ./install.sh +``` + +2. 执行下面Python代码 +```python +import matplotlib +import shutil +import os + +path = matplotlib.matplotlib_fname() +path = path.replace('matplotlibrc', 'fonts/ttf/') +print(path) +shutil.copy('/usr/share/fonts/MyFonts/simhei.ttf', path) +user_dir = os.path.expanduser('~') +shutil.rmtree(f'{user_dir}/.cache/matplotlib', ignore_errors=True) +``` + +# 预测 + +在训练结束之后,我们得到了一个模型参数文件,我们使用这个模型预测音频。 + +```shell +python infer.py --audio_path=dataset/UrbanSound8K/audio/fold5/156634-5-2-5.wav +``` + +# 其他功能 + + - 为了方便读取录制数据和制作数据集,这里提供了录音程序`record_audio.py`,这个用于录制音频,录制的音频采样率为16000,单通道,16bit。 + +```shell +python record_audio.py +``` + + - `infer_record.py`这个程序是用来不断进行录音识别,我们可以大致理解为这个程序在实时录音识别。通过这个应该我们可以做一些比较有趣的事情,比如把麦克风放在小鸟经常来的地方,通过实时录音识别,一旦识别到有鸟叫的声音,如果你的数据集足够强大,有每种鸟叫的声音数据集,这样你还能准确识别是那种鸟叫。如果识别到目标鸟类,就启动程序,例如拍照等等。 + +```shell +python infer_record.py --record_seconds=3 +``` + +## 打赏作者 +
+
+

打赏一块钱支持一下作者

+打赏作者 +
+ +# 参考资料 + +1. https://github.com/PaddlePaddle/PaddleSpeech +2. https://github.com/yeyupiaoling/PaddlePaddle-MobileFaceNets +3. https://github.com/yeyupiaoling/PPASR +4. https://github.com/alibaba-damo-academy/3D-Speaker diff --git a/src/声源定位代码/audio-classification/README_en.md b/src/声源定位代码/audio-classification/README_en.md new file mode 100644 index 0000000..43e1e2a --- /dev/null +++ b/src/声源定位代码/audio-classification/README_en.md @@ -0,0 +1,275 @@ +[简体中文](./README.md) | English + +# Sound classification system implemented in Pytorch + +![python version](https://img.shields.io/badge/python-3.8+-orange.svg) +![GitHub forks](https://img.shields.io/github/forks/yeyupiaoling/AudioClassification-Pytorch) +![GitHub Repo stars](https://img.shields.io/github/stars/yeyupiaoling/AudioClassification-Pytorch) +![GitHub](https://img.shields.io/github/license/yeyupiaoling/AudioClassification-Pytorch) +![支持系统](https://img.shields.io/badge/支持系统-Win/Linux/MAC-9cf) + +**Disclaimer, this document was obtained through machine translation, please check the original document [here](./README.md).** + + +# Introduction + +This project is a sound classification project based on Pytorch, aiming to realize the recognition of various environmental sounds, animal calls and languages. Several sound classification models such as EcapaTdnn, PANNS, ResNetSE, CAMPPlus, and ERes2Net are provided to support different application scenarios. In addition, the project also provides the commonly used Urbansound8K dataset test report and some dialect datasets download and use examples. Users can choose suitable models and datasets according to their needs to achieve more accurate sound classification. The project has a wide range of application scenarios, and can be used in outdoor environmental monitoring, wildlife protection, speech recognition and other fields. At the same time, the project also encourages users to explore more usage scenarios to promote the development and application of sound classification technology. + + +# Environment + + - Anaconda 3 + - Python 3.11 + - Pytorch 2.0.1 + - Windows 11 or Ubuntu 22.04 + +# Project Features + +1. Supporting models: EcapaTdnn、PANNS、TDNN、Res2Net、ResNetSE、CAMPPlus、ERes2Net +2. Supporting pooling: AttentiveStatsPool(ASP)、SelfAttentivePooling(SAP)、TemporalStatisticsPooling(TSP)、TemporalAveragePooling(TAP) +3. Support preprocessing methods: MelSpectrogram、Spectrogram、MFCC、Fbank、Wav2vec2.0、WavLM + +**Model Paper:** + +- EcapaTdnn:[ECAPA-TDNN: Emphasized Channel Attention, Propagation and Aggregation in TDNN Based Speaker Verification](https://arxiv.org/abs/2005.07143v3) +- PANNS:[PANNs: Large-Scale Pretrained Audio Neural Networks for Audio Pattern Recognition](https://arxiv.org/abs/1912.10211v5) +- TDNN:[Prediction of speech intelligibility with DNN-based performance measures](https://arxiv.org/abs/2203.09148) +- Res2Net:[Res2Net: A New Multi-scale Backbone Architecture](https://arxiv.org/abs/1904.01169) +- ResNetSE:[Squeeze-and-Excitation Networks](https://arxiv.org/abs/1709.01507) +- CAMPPlus:[CAM++: A Fast and Efficient Network for Speaker Verification Using Context-Aware Masking](https://arxiv.org/abs/2303.00332v3) +- ERes2Net:[An Enhanced Res2Net with Local and Global Feature Fusion for Speaker Verification](https://arxiv.org/abs/2305.12838v1) + +# Model Test + +| Model | Params(M) | Preprocessing method | Dataset | Number Class | Accuracy | +|:------------:|:---------:|:--------------------:|:------------:|:------------:|:--------:| +| ResNetSE | 7.8 | Flank | UrbanSound8K | 10 | 0.96233 | +| ERes2NetV2 | 5.4 | Flank | UrbanSound8K | 10 | 0.95662 | +| CAMPPlus | 7.1 | Flank | UrbanSound8K | 10 | 0.95454 | +| EcapaTdnn | 6.4 | Flank | UrbanSound8K | 10 | 0.95227 | +| ERes2Net | 6.6 | Flank | UrbanSound8K | 10 | 0.94292 | +| TDNN | 2.6 | Flank | UrbanSound8K | 10 | 0.93977 | +| PANNS(CNN10) | 5.2 | Flank | UrbanSound8K | 10 | 0.92954 | +| Res2Net | 5.0 | Flank | UrbanSound8K | 10 | 0.92580 | + +## Installation Environment + + - The GPU version of Pytorch will be installed first, please skip it if you already have it installed. +```shell +conda install pytorch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 pytorch-cuda=11.8 -c pytorch -c nvidia +``` + + - Install macls. + +Install it using pip with the following command: +```shell +python -m pip install macls -U -i https://pypi.tuna.tsinghua.edu.cn/simple +``` + +**Source installation is recommended**, which ensures that the latest code is used. +```shell +git clone https://github.com/yeyupiaoling/AudioClassification_Pytorch.git +cd AudioClassification_Pytorch/ +python setup.py install +``` + +## Preparing Data + +The `audio_path` is the audio file path. The user needs to store the audio dataset in the `dataset/audio` directory in advance. Each folder stores a category of audio data, and the length of each audio data is more than 3 seconds. For example, `dataset/audio/ bird song /······`. `audio` is where the data list is stored, and the format of the generated data category is`audio_path\tcategory_label_audio`, and the audio path and label are separated by a TAB character `\t`. You can also modify the following functions depending on how you store your data: + +Taking Urbansound8K as an example, it is a widely used public dataset for automatic urban environmental sound classification research. Urbansound8K contains 10 categories: air condition sound, car whistle sound, children playing sound, dog bark, drilling sound, engine idling sound, gun sound, jackdrill, siren sound, and street music sound. Data set download address: [UrbanSound8K](https://zenodo.org/record/1203745/files/UrbanSound8K.tar.gz). Here is the function to generate a list of data for Urbansound8K. If you want to use this dataset, please download and unzip it into the `dataset` directory and change the code to generate the list of data as follows. + +`create_data.py` can be used to generate a list of data sets. There are many ways to generate a list of data sets. +```shell +python create_data.py +``` + +The resulting list looks like this, with the path to the audio followed by the tag for that audio, starting at 0, and separated by `\t`. +```shell +dataset/UrbanSound8K/audio/fold2/104817-4-0-2.wav 4 +dataset/UrbanSound8K/audio/fold9/105029-7-2-5.wav 7 +dataset/UrbanSound8K/audio/fold3/107228-5-0-0.wav 5 +dataset/UrbanSound8K/audio/fold4/109711-3-2-4.wav 3 +``` + +# Change preprocessing methods + +By default, the Fbank preprocessing method is used in the configuration file. If you want to use other preprocessing methods, you can modify the following installation in the configuration file, and the specific value can be modified according to your own situation. If it's not clear how to set the parameters, you can remove that section and just use the default values. + +```yaml +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 +``` + +## 训练 + +Now we can train the model. We will create `train.py`. The parameters in the configuration file generally do not need to be modified, but these few need to be adjusted according to your actual dataset. The first and most important is the class size `dataset_conf.num_class`, which may be different for each dataset. Then there is` dataset_conf.batch_size `, which can be reduced if memory is insufficient. + +```shell +# Single GPU training +CUDA_VISIBLE_DEVICES=0 python train.py +# Multi GPU training +CUDA_VISIBLE_DEVICES=0,1 torchrun --standalone --nnodes=1 --nproc_per_node=2 train.py +``` + +Train log: +``` +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:14 - ----------- 额外配置参数 ----------- +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - configs: configs/ecapa_tdnn.yml +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - local_rank: 0 +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - pretrained_model: None +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - resume_model: None +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - save_model_path: models/ +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - use_gpu: True +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:17 - ------------------------------------------------ +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:19 - ----------- 配置文件参数 ----------- +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:22 - dataset_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - aug_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - noise_aug_prob: 0.2 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - noise_dir: dataset/noise +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - speed_perturb: True +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - volume_aug_prob: 0.2 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - volume_perturb: False +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - dataLoader: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - batch_size: 64 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - num_workers: 4 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - do_vad: False +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - eval_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - batch_size: 1 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - max_duration: 20 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - label_list_path: dataset/label_list.txt +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - max_duration: 3 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - min_duration: 0.5 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - sample_rate: 16000 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - spec_aug_args: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - freq_mask_width: [0, 8] +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - time_mask_width: [0, 10] +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - target_dB: -20 +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - test_list: dataset/test_list.txt +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - train_list: dataset/train_list.txt +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - use_dB_normalization: True +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - use_spec_aug: True +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:22 - model_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - num_class: 10 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - pooling_type: ASP +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:22 - optimizer_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - learning_rate: 0.001 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - optimizer: Adam +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - scheduler: WarmupCosineSchedulerLR +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:25 - scheduler_args: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - max_lr: 0.001 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - min_lr: 1e-05 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - warmup_epoch: 5 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - weight_decay: 1e-06 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:22 - preprocess_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - feature_method: Fbank +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:25 - method_args: +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:27 - num_mel_bins: 80 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:27 - sample_frequency: 16000 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:22 - train_conf: +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:29 - log_interval: 10 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:29 - max_epoch: 30 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:31 - use_model: EcapaTdnn +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:32 - ------------------------------------------------ +[2023-08-07 22:54:22.213166 WARNING] trainer:__init__:67 - Windows系统不支持多线程读取数据,已自动关闭! +========================================================================================== +Layer (type:depth-idx) Output Shape Param # +========================================================================================== +EcapaTdnn [1, 10] -- +├─Conv1dReluBn: 1-1 [1, 512, 98] -- +│ └─Conv1d: 2-1 [1, 512, 98] 204,800 +│ └─BatchNorm1d: 2-2 [1, 512, 98] 1,024 +├─Sequential: 1-2 [1, 512, 98] -- +│ └─Conv1dReluBn: 2-3 [1, 512, 98] -- +│ │ └─Conv1d: 3-1 [1, 512, 98] 262,144 +│ │ └─BatchNorm1d: 3-2 [1, 512, 98] 1,024 +│ └─Res2Conv1dReluBn: 2-4 [1, 512, 98] -- +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +··································· +│ │ └─ModuleList: 3-56 -- (recursive) +│ │ └─ModuleList: 3-55 -- (recursive) +│ │ └─ModuleList: 3-56 -- (recursive) +│ │ └─ModuleList: 3-55 -- (recursive) +│ │ └─ModuleList: 3-56 -- (recursive) +│ └─Conv1dReluBn: 2-13 [1, 512, 98] -- +│ │ └─Conv1d: 3-57 [1, 512, 98] 262,144 +│ │ └─BatchNorm1d: 3-58 [1, 512, 98] 1,024 +│ └─SE_Connect: 2-14 [1, 512, 98] -- +│ │ └─Linear: 3-59 [1, 256] 131,328 +│ │ └─Linear: 3-60 [1, 512] 131,584 +├─Conv1d: 1-5 [1, 1536, 98] 2,360,832 +├─AttentiveStatsPool: 1-6 [1, 3072] -- +│ └─Conv1d: 2-15 [1, 128, 98] 196,736 +│ └─Conv1d: 2-16 [1, 1536, 98] 198,144 +├─BatchNorm1d: 1-7 [1, 3072] 6,144 +├─Linear: 1-8 [1, 192] 590,016 +├─BatchNorm1d: 1-9 [1, 192] 384 +├─Linear: 1-10 [1, 10] 1,930 +========================================================================================== +Total params: 6,188,490 +Trainable params: 6,188,490 +Non-trainable params: 0 +Total mult-adds (M): 470.96 +========================================================================================== +Input size (MB): 0.03 +Forward/backward pass size (MB): 10.28 +Params size (MB): 24.75 +Estimated Total Size (MB): 35.07 +========================================================================================== +[2023-08-07 22:54:26.726095 INFO ] trainer:train:344 - 训练数据:8644 +[2023-08-07 22:54:30.092504 INFO ] trainer:__train_epoch:296 - Train epoch: [1/30], batch: [0/4], loss: 2.57033, accuracy: 0.06250, learning rate: 0.00001000, speed: 19.02 data/sec, eta: 0:06:43 +``` + +# Eval + +At the end of each training round, we can perform an evaluation, which will output the accuracy. We also save the mixture matrix image, and save the path `output/images/` as follows. +![混合矩阵](docs/images/image1.png) + +# Inference + +At the end of the training, we are given a model parameter file, and we use this model to predict the audio. + +```shell +python infer.py --audio_path=dataset/UrbanSound8K/audio/fold5/156634-5-2-5.wav +``` + +# Other Functions + + - In order to read the recorded data and make a dataset easily, we provide the recording program `record_audio.py`, which is used to record audio with a sample rate of 16,000, single channel, 16bit. + +```shell +python record_audio.py +``` + + - `infer_record.py`This program is used to continuously perform recording recognition, and we can roughly understand this program as recording recognition in real time. And this should allow us to do some interesting things, like put a microphone in a place where birds often come, and recognize it by recording it in real time, and once you recognize that there's a bird calling, if your dataset is powerful enough, and you have a dataset of every bird calling, then you can identify exactly which bird is calling. If the target bird is identified, the procedure is initiated, such as taking photos, etc. + +```shell +python infer_record.py --record_seconds=3 +``` + +# Reference + +1. https://github.com/PaddlePaddle/PaddleSpeech +2. https://github.com/yeyupiaoling/PaddlePaddle-MobileFaceNets +3. https://github.com/yeyupiaoling/PPASR +4. https://github.com/alibaba-damo-academy/3D-Speaker diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/README.md b/src/声源定位代码/audio-classification/audio-classification-platform/README.md new file mode 100644 index 0000000..d3ecd35 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/README.md @@ -0,0 +1,136 @@ +# 声纹识别系统 + +这是一个基于深度学习的声纹识别系统,包含Flask后端和Vue前端。 + +## 功能特性 + +- 🎵 支持多种音频格式上传识别 +- 🎤 实时录音识别功能 +- 📊 置信度可视化展示 +- 📱 响应式设计,支持移动端 +- 📝 识别历史记录 +- 📋 结果导出功能 + +## 技术栈 + +### 后端 +- Flask + Flask-CORS +- PyTorch + MAClsPredictor +- librosa + soundfile + +### 前端 +- Vue 3 + Composition API +- Element Plus UI框架 +- Axios HTTP客户端 +- Vite构建工具 + +## 快速开始 + +### 环境要求 + +- Python 3.8+ +- Node.js 16+ +- 已训练好的音频分类模型 + +### 1. 安装后端依赖 + +```bash +cd audio-classification-platform/backend +pip install -r requirements.txt +``` + +### 2. 安装前端依赖 + +```bash +cd audio-classification-platform/frontend +npm install +``` + +### 3. 启动后端服务 + +```bash +cd audio-classification-platform/backend +python app.py +``` + +后端服务将在 http://localhost:5000 启动 + +### 4. 启动前端服务 + +```bash +cd audio-classification-platform/frontend +npm run dev +``` + +前端服务将在 http://localhost:3000 启动 + +## 使用说明 + +1. 打开浏览器访问 http://localhost:3000 +2. 首次使用需要初始化模型(确保模型文件路径正确) +3. 使用文件上传功能或实时录音功能进行音频识别 +4. 查看识别结果和置信度 +5. 可以查看历史识别记录 + +## 配置说明 + +### 后端配置 + +在 `backend/config.py` 中可以配置: + +- 模型路径 +- 上传文件限制 +- GPU使用设置 +- 音频处理参数 + +### 前端配置 + +在 `frontend/vite.config.js` 中可以配置: + +- 开发服务器端口 +- 代理设置 +- 构建选项 + +## API接口 + +- `GET /api/health` - 健康检查 +- `POST /api/init` - 初始化模型 +- `POST /api/upload` - 上传音频文件识别 +- `POST /api/predict` - 录音数据识别 +- `GET /api/labels` - 获取分类标签 +- `GET /api/model/info` - 获取模型信息 + +## 部署 + +### 生产环境构建 + +```bash +# 构建前端 +cd frontend +npm run build + +# 启动后端(推荐使用gunicorn) +cd backend +gunicorn -w 4 -b 0.0.0.0:5000 app:app +``` + +## 故障排除 + +1. **模型初始化失败** + - 检查模型文件路径是否正确 + - 确保配置文件存在 + - 检查GPU驱动(如果使用GPU) + +2. **音频上传失败** + - 检查文件格式是否支持 + - 检查文件大小是否超限 + - 检查网络连接 + +3. **录音功能不可用** + - 检查浏览器麦克风权限 + - 使用HTTPS协议(录音功能需要) + - 检查设备麦克风是否正常 + +## 许可证 + +Apache License 2.0 diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/backend/app.py b/src/声源定位代码/audio-classification/audio-classification-platform/backend/app.py new file mode 100644 index 0000000..d9e1caa --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/backend/app.py @@ -0,0 +1,350 @@ +import os +import sys +import tempfile +import uuid +from datetime import datetime +from flask import Flask, request, jsonify, send_from_directory +from flask_cors import CORS +from werkzeug.utils import secure_filename +import librosa +import soundfile as sf +import numpy as np +from loguru import logger + +# 添加项目根目录到Python路径 +sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) + +from macls.predict import MAClsPredictor + +app = Flask(__name__) +CORS(app) # 允许跨域请求 + +# 配置 +app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # 最大50MB +app.config['UPLOAD_FOLDER'] = 'uploads' +app.config['ALLOWED_EXTENSIONS'] = {'wav', 'mp3', 'flac', 'm4a', 'ogg', 'aac'} + +# 确保上传目录存在 +os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) + +# 全局预测器实例 +predictor = None + +def allowed_file(filename): + """检查文件扩展名是否被允许""" + return '.' in filename and \ + filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS'] + +def convert_audio_format(input_path, target_sample_rate=16000): + """将音频转换为模型需要的格式""" + try: + # 使用librosa加载音频,自动转换采样率 + audio_data, sr = librosa.load(input_path, sr=target_sample_rate) + + # 创建临时文件 + temp_file = tempfile.NamedTemporaryFile(suffix='.wav', delete=False) + temp_path = temp_file.name + temp_file.close() + + # 保存为wav格式 + sf.write(temp_path, audio_data, target_sample_rate) + + return temp_path, audio_data, target_sample_rate + except Exception as e: + logger.error(f"音频格式转换失败: {str(e)}") + raise e + +@app.route('/api/health', methods=['GET']) +def health_check(): + """健康检查接口""" + return jsonify({ + 'status': 'success', + 'message': '服务正常运行', + 'timestamp': datetime.now().isoformat() + }) + +@app.route('/api/init', methods=['POST']) +def init_model(): + """初始化模型""" + global predictor + try: + data = request.get_json() + + # 默认配置路径 + configs = data.get('configs', '../../configs/cam++.yml') + model_path = data.get('model_path', '../../models/CAMPPlus_Fbank/best_model/') + use_gpu = data.get('use_gpu', True) + + # 转换为绝对路径 + configs = os.path.abspath(os.path.join(os.path.dirname(__file__), configs)) + model_path = os.path.abspath(os.path.join(os.path.dirname(__file__), model_path)) + + if not os.path.exists(configs): + return jsonify({ + 'status': 'error', + 'message': f'配置文件不存在: {configs}' + }), 400 + + if not os.path.exists(model_path): + return jsonify({ + 'status': 'error', + 'message': f'模型路径不存在: {model_path}' + }), 400 + + # 初始化预测器 + predictor = MAClsPredictor( + configs=configs, + model_path=model_path, + use_gpu=use_gpu + ) + + logger.info("模型初始化成功") + + return jsonify({ + 'status': 'success', + 'message': '模型初始化成功', + 'config': { + 'configs': configs, + 'model_path': model_path, + 'use_gpu': use_gpu + } + }) + + except Exception as e: + logger.error(f"模型初始化失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'模型初始化失败: {str(e)}' + }), 500 + +@app.route('/api/upload', methods=['POST']) +def upload_and_predict(): + """上传音频文件并进行预测""" + global predictor + + if predictor is None: + return jsonify({ + 'status': 'error', + 'message': '模型未初始化,请先调用 /api/init 接口' + }), 400 + + if 'file' not in request.files: + return jsonify({ + 'status': 'error', + 'message': '没有上传文件' + }), 400 + + file = request.files['file'] + + if file.filename == '': + return jsonify({ + 'status': 'error', + 'message': '没有选择文件' + }), 400 + + if file and allowed_file(file.filename): + try: + # 生成唯一文件名 + filename = secure_filename(file.filename) + unique_filename = f"{uuid.uuid4()}_{filename}" + filepath = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename) + + # 保存上传的文件 + file.save(filepath) + + # 转换音频格式 + converted_path, audio_data, sample_rate = convert_audio_format(filepath) + + # 进行预测 + start_time = datetime.now() + label, score = predictor.predict(audio_data=converted_path) + end_time = datetime.now() + + # 计算预测时间 + prediction_time = (end_time - start_time).total_seconds() + + # 清理临时文件 + if os.path.exists(converted_path): + os.remove(converted_path) + # 可选:保留原始文件或删除 + # os.remove(filepath) + + logger.info(f"预测完成 - 文件: {filename}, 结果: {label}, 得分: {score:.4f}, 耗时: {prediction_time:.3f}s") + + return jsonify({ + 'status': 'success', + 'result': { + 'predicted_class': label, # 前端期望的字段名 + 'confidence': float(score), # 前端期望的字段名 + 'label': label, # 保持兼容性 + 'score': float(score), # 保持兼容性 + 'filename': filename, + 'prediction_time': prediction_time, + 'audio_info': { + 'sample_rate': sample_rate, + 'duration': len(audio_data) / sample_rate + } + } + }) + + except Exception as e: + logger.error(f"预测失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'预测失败: {str(e)}' + }), 500 + else: + return jsonify({ + 'status': 'error', + 'message': '不支持的文件格式,支持的格式:wav, mp3, flac, m4a, ogg, aac' + }), 400 + +@app.route('/api/predict', methods=['POST']) +def predict_audio_data(): + """直接预测音频数据(用于录音功能)""" + global predictor + + if predictor is None: + return jsonify({ + 'status': 'error', + 'message': '模型未初始化,请先调用 /api/init 接口' + }), 400 + + try: + data = request.get_json() + + if 'audio_data' not in data: + return jsonify({ + 'status': 'error', + 'message': '缺少音频数据' + }), 400 + + audio_data = np.array(data['audio_data'], dtype=np.float32) + sample_rate = data.get('sample_rate', 16000) + + # 创建临时文件 + temp_file = tempfile.NamedTemporaryFile(suffix='.wav', delete=False) + temp_path = temp_file.name + temp_file.close() + + # 保存音频数据 + sf.write(temp_path, audio_data, sample_rate) + + # 进行预测 + start_time = datetime.now() + label, score = predictor.predict(audio_data=temp_path) + end_time = datetime.now() + + prediction_time = (end_time - start_time).total_seconds() + # 清理临时文件 + os.remove(temp_path) + + logger.info(f"录音预测完成 - 结果: {label}, 得分: {score:.4f}, 耗时: {prediction_time:.3f}s") + + return jsonify({ + 'status': 'success', + 'result': { + 'predicted_class': label, # 前端期望的字段名 + 'confidence': float(score), # 前端期望的字段名 + 'label': label, # 保持兼容性 + 'score': float(score), # 保持兼容性 + 'prediction_time': prediction_time, + 'audio_info': { + 'sample_rate': sample_rate, + 'duration': len(audio_data) / sample_rate + } + } + }) + + except Exception as e: + logger.error(f"录音预测失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'录音预测失败: {str(e)}' + }), 500 + +@app.route('/api/labels', methods=['GET']) +def get_labels(): + """获取分类标签列表""" + try: + # 读取标签文件 + label_file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../dataset/label_list.txt')) + + if not os.path.exists(label_file_path): + return jsonify({ + 'status': 'error', + 'message': '标签文件不存在' + }), 404 + + with open(label_file_path, 'r', encoding='utf-8') as f: + labels = [line.strip() for line in f.readlines() if line.strip()] + + return jsonify({ + 'status': 'success', + 'labels': labels, + 'count': len(labels) + }) + + except Exception as e: + logger.error(f"读取标签失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'读取标签失败: {str(e)}' + }), 500 + +@app.route('/api/model/info', methods=['GET']) +def get_model_info(): + """获取模型信息""" + global predictor + + if predictor is None: + return jsonify({ + 'status': 'error', + 'message': '模型未初始化' + }), 400 + + try: + # 获取模型配置信息 + return jsonify({ + 'status': 'success', + 'model_info': { + 'initialized': True, + 'model_type': 'AudioClassification', + 'framework': 'PyTorch' + } + }) + + except Exception as e: + logger.error(f"获取模型信息失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'获取模型信息失败: {str(e)}' + }), 500 + +@app.errorhandler(413) +def too_large(e): + """文件过大错误处理""" + return jsonify({ + 'status': 'error', + 'message': '文件过大,最大支持50MB' + }), 413 + +@app.errorhandler(404) +def not_found(e): + """404错误处理""" + return jsonify({ + 'status': 'error', + 'message': '接口不存在' + }), 404 + +@app.errorhandler(500) +def internal_error(e): + """500错误处理""" + return jsonify({ + 'status': 'error', + 'message': '服务器内部错误' + }), 500 + +if __name__ == '__main__': + logger.info("启动音频分类API服务器...") + app.run(host='0.0.0.0', port=5000, debug=True) diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/backend/config.py b/src/声源定位代码/audio-classification/audio-classification-platform/backend/config.py new file mode 100644 index 0000000..039439f --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/backend/config.py @@ -0,0 +1,39 @@ +import os +import sys + +# 配置 +class Config: + # 模型配置 + MODEL_CONFIG_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../configs/cam++.yml')) + MODEL_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../models/CAMPPlus_Fbank/best_model/')) + LABEL_FILE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../dataset/label_list.txt')) + + # Flask配置 + SECRET_KEY = 'your-secret-key-here' + MAX_CONTENT_LENGTH = 50 * 1024 * 1024 # 50MB + + # 文件上传配置 + UPLOAD_FOLDER = 'uploads' + ALLOWED_EXTENSIONS = {'wav', 'mp3', 'flac', 'm4a', 'ogg', 'aac'} + + # 音频处理配置 + TARGET_SAMPLE_RATE = 16000 + + # 日志配置 + LOG_LEVEL = 'INFO' + + # GPU配置 + USE_GPU = True + +class DevelopmentConfig(Config): + DEBUG = True + +class ProductionConfig(Config): + DEBUG = False + +# 根据环境变量选择配置 +config = { + 'development': DevelopmentConfig, + 'production': ProductionConfig, + 'default': DevelopmentConfig +} diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/backend/requirements.txt b/src/声源定位代码/audio-classification/audio-classification-platform/backend/requirements.txt new file mode 100644 index 0000000..de8b375 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/backend/requirements.txt @@ -0,0 +1,7 @@ +Flask==2.3.3 +Flask-CORS==4.0.0 +librosa==0.10.1 +soundfile==0.12.1 +numpy==1.24.3 +loguru==0.7.2 +Werkzeug==2.3.7 diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/index.html b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/index.html new file mode 100644 index 0000000..e8eba15 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/index.html @@ -0,0 +1,26 @@ + + + + + + + 声纹识别系统 + + + +
+ + + diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/package.json b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/package.json new file mode 100644 index 0000000..39dcbc3 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/package.json @@ -0,0 +1,24 @@ +{ + "name": "audio-classification-frontend", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "serve": "vite preview" + }, "dependencies": { + "vue": "^3.3.4", + "vue-router": "^4.2.4", + "axios": "^1.5.0", + "element-plus": "^2.3.9", + "@element-plus/icons-vue": "^2.1.0", + "echarts": "^5.4.3" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^4.3.4", + "vite": "^4.4.9", + "unplugin-vue-components": "^0.25.2", + "unplugin-auto-import": "^0.16.6" + } +} diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/App.vue b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/App.vue new file mode 100644 index 0000000..0908a7a --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/App.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder.vue b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder.vue new file mode 100644 index 0000000..d1614fe --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder.vue @@ -0,0 +1,690 @@ + + + + + diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue new file mode 100644 index 0000000..73a92b4 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue @@ -0,0 +1,1020 @@ + + + + + diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioUpload.vue b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioUpload.vue new file mode 100644 index 0000000..2a10b97 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/AudioUpload.vue @@ -0,0 +1,714 @@ + + + + + diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/HistoryList.vue b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/HistoryList.vue new file mode 100644 index 0000000..ac088fa --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/HistoryList.vue @@ -0,0 +1,616 @@ + + + + + diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/PredictionResult.vue b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/PredictionResult.vue new file mode 100644 index 0000000..33783a3 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/components/PredictionResult.vue @@ -0,0 +1,941 @@ + + + + + diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/main.js b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/main.js new file mode 100644 index 0000000..99badf7 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/main.js @@ -0,0 +1,18 @@ +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' +import * as ElementPlusIconsVue from '@element-plus/icons-vue' + +const app = createApp(App) + +// 注册所有图标 +for (const [key, component] of Object.entries(ElementPlusIconsVue)) { + app.component(key, component) +} + +app.use(ElementPlus) +app.use(router) + +app.mount('#app') diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/router/index.js b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/router/index.js new file mode 100644 index 0000000..3109046 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/router/index.js @@ -0,0 +1,17 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomePage from '../views/HomePage.vue' + +const routes = [ + { + path: '/', + name: 'Home', + component: HomePage + } +] + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +export default router diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/utils/api.js b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/utils/api.js new file mode 100644 index 0000000..0db7b1a --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/utils/api.js @@ -0,0 +1,213 @@ +import axios from 'axios' +import { ElMessage } from 'element-plus' + +// 创建axios实例 +const api = axios.create({ + baseURL: '/api', + timeout: 30000, + headers: { + 'Content-Type': 'application/json' + } +}) + +// 请求拦截器 +api.interceptors.request.use( + (config) => { + // 可以在这里添加token等认证信息 + return config + }, + (error) => { + return Promise.reject(error) + } +) + +// 响应拦截器 +api.interceptors.response.use( + (response) => { + return response + }, + (error) => { + let errorMessage = '请求失败' + + if (error.response) { + // 服务器返回错误状态码 + const { status, data } = error.response + + switch (status) { + case 400: + errorMessage = data.message || '请求参数错误' + break + case 401: + errorMessage = '未授权访问' + break + case 403: + errorMessage = '禁止访问' + break + case 404: + errorMessage = '请求的资源不存在' + break + case 413: + errorMessage = '文件过大,最大支持50MB' + break + case 500: + errorMessage = data.message || '服务器内部错误' + break + default: + errorMessage = data.message || `请求失败 (${status})` + } + } else if (error.request) { + // 网络错误 + errorMessage = '网络连接失败,请检查网络设置' + } else { + // 其他错误 + errorMessage = error.message || '未知错误' + } + + // 显示错误消息 + ElMessage.error(errorMessage) + + return Promise.reject(new Error(errorMessage)) + } +) + +// API服务类 +export const apiService = { + // 健康检查 + healthCheck: () => { + return api.get('/health') + }, + + // 初始化模型 + initModel: (config) => { + return api.post('/init', config) + }, + // 上传文件并预测 + uploadAndPredict: (file, onProgress) => { + const formData = new FormData() + formData.append('file', file) + + return api.post('/upload', formData, { + // 不要手动设置 Content-Type,让浏览器自动设置 boundary + onUploadProgress: (progressEvent) => { + if (onProgress && progressEvent.total) { + const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total) + onProgress(percent) + } + } + }) + }, + + // 预测音频数据(录音) + predictAudioData: (audioData) => { + return api.post('/predict', audioData) + }, + + // 获取标签列表 + getLabels: () => { + return api.get('/labels') + }, + + // 获取模型信息 + getModelInfo: () => { + return api.get('/model/info') + } +} + +// 工具函数 +export const utils = { + // 格式化文件大小 + formatFileSize: (bytes) => { + if (bytes === 0) return '0 B' + + const k = 1024 + const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] + const i = Math.floor(Math.log(bytes) / Math.log(k)) + + return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] + }, + + // 格式化时长 + formatDuration: (seconds) => { + if (!seconds) return '0s' + + const hrs = Math.floor(seconds / 3600) + const mins = Math.floor((seconds % 3600) / 60) + const secs = Math.floor(seconds % 60) + + if (hrs > 0) { + return `${hrs}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}` + } else if (mins > 0) { + return `${mins}:${secs.toString().padStart(2, '0')}` + } else { + return `${secs}s` + } + }, + + // 检查音频文件格式 + isAudioFile: (file) => { + const allowedTypes = ['audio/wav', 'audio/mpeg', 'audio/flac', 'audio/m4a', 'audio/ogg', 'audio/aac'] + const allowedExtensions = ['wav', 'mp3', 'flac', 'm4a', 'ogg', 'aac'] + + const fileExtension = file.name.split('.').pop().toLowerCase() + + return allowedTypes.includes(file.type) || allowedExtensions.includes(fileExtension) + }, + + // 检查文件大小 + isFileSizeValid: (file, maxSizeMB = 50) => { + const maxSize = maxSizeMB * 1024 * 1024 + return file.size <= maxSize + }, + + // 生成唯一ID + generateId: () => { + return Date.now().toString(36) + Math.random().toString(36).substr(2) + }, + + // 下载文件 + downloadFile: (content, filename, type = 'application/json') => { + const blob = new Blob([content], { type }) + const url = URL.createObjectURL(blob) + + const link = document.createElement('a') + link.href = url + link.download = filename + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + URL.revokeObjectURL(url) + }, + + // 复制到剪贴板 + copyToClipboard: async (text) => { + try { + await navigator.clipboard.writeText(text) + return true + } catch (error) { + console.error('复制失败:', error) + return false + } + }, + + // 获取音频时长 + getAudioDuration: (file) => { + return new Promise((resolve, reject) => { + const audio = new Audio() + const url = URL.createObjectURL(file) + + audio.addEventListener('loadedmetadata', () => { + URL.revokeObjectURL(url) + resolve(audio.duration) + }) + + audio.addEventListener('error', (error) => { + URL.revokeObjectURL(url) + reject(error) + }) + + audio.src = url + }) + } +} + +export default api diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/views/HomePage.vue b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/views/HomePage.vue new file mode 100644 index 0000000..f313fea --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/src/views/HomePage.vue @@ -0,0 +1,841 @@ + + + + + diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/vite.config.js b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/vite.config.js new file mode 100644 index 0000000..34b05a8 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/vite.config.js @@ -0,0 +1,33 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import AutoImport from 'unplugin-auto-import/vite' +import Components from 'unplugin-vue-components/vite' +import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' + +export default defineConfig({ + plugins: [ + vue(), + AutoImport({ + resolvers: [ElementPlusResolver()], + }), + Components({ + resolvers: [ElementPlusResolver()], + }), + ], + server: { + port: 3000, + host: '0.0.0.0', + proxy: { + '/api': { + target: 'http://localhost:5000', + changeOrigin: true, + secure: false, + } + } + }, + build: { + outDir: 'dist', + assetsDir: 'assets', + chunkSizeWarningLimit: 1000 + } +}) diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/frontend/yarn.lock b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/yarn.lock new file mode 100644 index 0000000..47a4043 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/frontend/yarn.lock @@ -0,0 +1,1092 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@antfu/utils@^0.7.5", "@antfu/utils@^0.7.6": + version "0.7.10" + resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.7.10.tgz#ae829f170158e297a9b6a28f161a8e487d00814d" + integrity sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@babel/parser@^7.27.2": + version "7.27.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.4.tgz#f92e89e4f51847be05427285836fc88341c956df" + integrity sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g== + dependencies: + "@babel/types" "^7.27.3" + +"@babel/types@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.27.3.tgz#c0257bedf33aad6aad1f406d35c44758321eb3ec" + integrity sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + +"@ctrl/tinycolor@^3.4.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31" + integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA== + +"@element-plus/icons-vue@^2.1.0", "@element-plus/icons-vue@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz#1f635ad5fdd5c85ed936481525570e82b5a8307a" + integrity sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg== + +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + +"@floating-ui/core@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.0.tgz#1aff27a993ea1b254a586318c29c3b16ea0f4d0a" + integrity sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA== + dependencies: + "@floating-ui/utils" "^0.2.9" + +"@floating-ui/dom@^1.0.1": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.0.tgz#f9f83ee4fee78ac23ad9e65b128fc11a27857532" + integrity sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg== + dependencies: + "@floating-ui/core" "^1.7.0" + "@floating-ui/utils" "^0.2.9" + +"@floating-ui/utils@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.9.tgz#50dea3616bc8191fb8e112283b49eaff03e78429" + integrity sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg== + +"@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7": + version "2.11.7" + resolved "https://registry.yarnpkg.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671" + integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ== + +"@rollup/pluginutils@^5.0.2", "@rollup/pluginutils@^5.0.5", "@rollup/pluginutils@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a" + integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" + +"@types/estree@^1.0.0": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" + integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== + +"@types/lodash-es@^4.17.6": + version "4.17.12" + resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b" + integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*", "@types/lodash@^4.14.182": + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.17.tgz#fb85a04f47e9e4da888384feead0de05f7070355" + integrity sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ== + +"@types/web-bluetooth@^0.0.16": + version "0.0.16" + resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8" + integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ== + +"@vitejs/plugin-vue@^4.3.4": + version "4.6.2" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz#057d2ded94c4e71b94e9814f92dcd9306317aa46" + integrity sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw== + +"@vue/compiler-core@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.16.tgz#2f95f4f17c16c09c57bbf64399075b921506630b" + integrity sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ== + dependencies: + "@babel/parser" "^7.27.2" + "@vue/shared" "3.5.16" + entities "^4.5.0" + estree-walker "^2.0.2" + source-map-js "^1.2.1" + +"@vue/compiler-dom@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz#151d8390252975c0b1a773029220fdfcfaa2d743" + integrity sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ== + dependencies: + "@vue/compiler-core" "3.5.16" + "@vue/shared" "3.5.16" + +"@vue/compiler-sfc@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz#577f7fd42a46fac8357ffed46e8fb34d32698419" + integrity sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw== + dependencies: + "@babel/parser" "^7.27.2" + "@vue/compiler-core" "3.5.16" + "@vue/compiler-dom" "3.5.16" + "@vue/compiler-ssr" "3.5.16" + "@vue/shared" "3.5.16" + estree-walker "^2.0.2" + magic-string "^0.30.17" + postcss "^8.5.3" + source-map-js "^1.2.1" + +"@vue/compiler-ssr@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz#3b7874dff771ab2f85fb09be71f6c76a75fcc5ac" + integrity sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A== + dependencies: + "@vue/compiler-dom" "3.5.16" + "@vue/shared" "3.5.16" + +"@vue/devtools-api@^6.6.4": + version "6.6.4" + resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz#cbe97fe0162b365edc1dba80e173f90492535343" + integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g== + +"@vue/reactivity@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.16.tgz#528c535a088b3c1b67f285f1f2211be79425b962" + integrity sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA== + dependencies: + "@vue/shared" "3.5.16" + +"@vue/runtime-core@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.16.tgz#0a828c322224ada26f81a2e227c3d4aebcb72c7a" + integrity sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ== + dependencies: + "@vue/reactivity" "3.5.16" + "@vue/shared" "3.5.16" + +"@vue/runtime-dom@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.16.tgz#c1bcbcca862b77186f81c92edd5176e74670f078" + integrity sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww== + dependencies: + "@vue/reactivity" "3.5.16" + "@vue/runtime-core" "3.5.16" + "@vue/shared" "3.5.16" + csstype "^3.1.3" + +"@vue/server-renderer@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.16.tgz#5a68cd1d423d843f74c9e6b37133850abab07c13" + integrity sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg== + dependencies: + "@vue/compiler-ssr" "3.5.16" + "@vue/shared" "3.5.16" + +"@vue/shared@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.16.tgz#d5ea7671182742192938a4b4cbf86ef12bef7418" + integrity sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg== + +"@vueuse/core@^9.1.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4" + integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw== + dependencies: + "@types/web-bluetooth" "^0.0.16" + "@vueuse/metadata" "9.13.0" + "@vueuse/shared" "9.13.0" + vue-demi "*" + +"@vueuse/metadata@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff" + integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ== + +"@vueuse/shared@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9" + integrity sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw== + dependencies: + vue-demi "*" + +acorn@^8.14.0: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +async-validator@^4.2.5: + version "4.2.5" + resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339" + integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^1.5.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.9.0.tgz#25534e3b72b54540077d33046f77e3b8d7081901" + integrity sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + +confbox@^0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110" + integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ== + +csstype@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +dayjs@^1.11.13: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + +debug@^4.3.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +echarts@^5.4.3: + version "5.6.0" + resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.6.0.tgz#2377874dca9fb50f104051c3553544752da3c9d6" + integrity sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA== + dependencies: + tslib "2.3.0" + zrender "5.6.1" + +element-plus@^2.3.9: + version "2.9.11" + resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-2.9.11.tgz#c939a8d945330f596b7a35aae0e501ea170874a2" + integrity sha512-x4L/6YC8de4JtuE3vpaEugJdQIeHQaHtIYKyk67IeF6dTIiVax45aX4nWOygnh+xX+0gTvL6xO+9BZhPA3G82w== + dependencies: + "@ctrl/tinycolor" "^3.4.1" + "@element-plus/icons-vue" "^2.3.1" + "@floating-ui/dom" "^1.0.1" + "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7" + "@types/lodash" "^4.14.182" + "@types/lodash-es" "^4.17.6" + "@vueuse/core" "^9.1.0" + async-validator "^4.2.5" + dayjs "^1.11.13" + escape-html "^1.0.3" + lodash "^4.17.21" + lodash-es "^4.17.21" + lodash-unified "^1.0.2" + memoize-one "^6.0.0" + normalize-wheel-es "^1.2.0" + +entities@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +esbuild@^0.18.10: + version "0.18.20" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +exsolve@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.5.tgz#1f5b6b4fe82ad6b28a173ccb955a635d77859dcf" + integrity sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg== + +fast-glob@^3.3.0, fast-glob@^3.3.1, fast-glob@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + +form-data@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c" + integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + mime-types "^2.1.12" + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +js-tokens@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4" + integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== + +local-pkg@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963" + integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g== + +local-pkg@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.1.tgz#69658638d2a95287534d4c2fff757980100dbb6d" + integrity sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ== + dependencies: + mlly "^1.7.3" + pkg-types "^1.2.1" + +local-pkg@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.1.tgz#f5fe74a97a3bd3c165788ee08ca9fbe998dc58dd" + integrity sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg== + dependencies: + mlly "^1.7.4" + pkg-types "^2.0.1" + quansync "^0.2.8" + +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash-unified@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/lodash-unified/-/lodash-unified-1.0.3.tgz#80b1eac10ed2eb02ed189f08614a29c27d07c894" + integrity sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +magic-string@^0.30.1, magic-string@^0.30.17, magic-string@^0.30.5: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimatch@^9.0.3: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +mlly@^1.7.3, mlly@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.4.tgz#3d7295ea2358ec7a271eaa5d000a0f84febe100f" + integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw== + dependencies: + acorn "^8.14.0" + pathe "^2.0.1" + pkg-types "^1.3.0" + ufo "^1.5.4" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-wheel-es@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz#0fa2593d619f7245a541652619105ab076acf09e" + integrity sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +pathe@^2.0.1, pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +pkg-types@^1.2.1, pkg-types@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" + integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== + dependencies: + confbox "^0.1.8" + mlly "^1.7.4" + pathe "^2.0.1" + +pkg-types@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-2.1.0.tgz#70c9e1b9c74b63fdde749876ee0aa007ea9edead" + integrity sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A== + dependencies: + confbox "^0.2.1" + exsolve "^1.0.1" + pathe "^2.0.3" + +postcss@^8.4.27, postcss@^8.5.3: + version "8.5.4" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.4.tgz#d61014ac00e11d5f58458ed7247d899bd65f99c0" + integrity sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +quansync@^0.2.8: + version "0.2.10" + resolved "https://registry.yarnpkg.com/quansync/-/quansync-0.2.10.tgz#32053cf166fa36511aae95fc49796116f2dc20e1" + integrity sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +resolve@^1.22.2: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +rollup@^3.27.1: + version "3.29.5" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54" + integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w== + optionalDependencies: + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +scule@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/scule/-/scule-1.3.0.tgz#6efbd22fd0bb801bdcc585c89266a7d2daa8fbd3" + integrity sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +strip-literal@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.1.1.tgz#26906e65f606d49f748454a08084e94190c2e5ad" + integrity sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q== + dependencies: + js-tokens "^9.0.1" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tslib@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + +ufo@^1.5.4: + version "1.6.1" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" + integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== + +unimport@^3.4.0: + version "3.14.6" + resolved "https://registry.yarnpkg.com/unimport/-/unimport-3.14.6.tgz#f01170aa2fb94c4f97b22c0ac2822ef7e8e0726d" + integrity sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g== + dependencies: + "@rollup/pluginutils" "^5.1.4" + acorn "^8.14.0" + escape-string-regexp "^5.0.0" + estree-walker "^3.0.3" + fast-glob "^3.3.3" + local-pkg "^1.0.0" + magic-string "^0.30.17" + mlly "^1.7.4" + pathe "^2.0.1" + picomatch "^4.0.2" + pkg-types "^1.3.0" + scule "^1.3.0" + strip-literal "^2.1.1" + unplugin "^1.16.1" + +unplugin-auto-import@^0.16.6: + version "0.16.7" + resolved "https://registry.yarnpkg.com/unplugin-auto-import/-/unplugin-auto-import-0.16.7.tgz#f4f1f7ab3fba24129bc38e47f83782684030d6e4" + integrity sha512-w7XmnRlchq6YUFJVFGSvG1T/6j8GrdYN6Em9Wf0Ye+HXgD/22kont+WnuCAA0UaUoxtuvRR1u/mXKy63g/hfqQ== + dependencies: + "@antfu/utils" "^0.7.6" + "@rollup/pluginutils" "^5.0.5" + fast-glob "^3.3.1" + local-pkg "^0.5.0" + magic-string "^0.30.5" + minimatch "^9.0.3" + unimport "^3.4.0" + unplugin "^1.5.0" + +unplugin-vue-components@^0.25.2: + version "0.25.2" + resolved "https://registry.yarnpkg.com/unplugin-vue-components/-/unplugin-vue-components-0.25.2.tgz#99d9d02a4066a24e720edbe74a82a4ee6ff86153" + integrity sha512-OVmLFqILH6w+eM8fyt/d/eoJT9A6WO51NZLf1vC5c1FZ4rmq2bbGxTy8WP2Jm7xwFdukaIdv819+UI7RClPyCA== + dependencies: + "@antfu/utils" "^0.7.5" + "@rollup/pluginutils" "^5.0.2" + chokidar "^3.5.3" + debug "^4.3.4" + fast-glob "^3.3.0" + local-pkg "^0.4.3" + magic-string "^0.30.1" + minimatch "^9.0.3" + resolve "^1.22.2" + unplugin "^1.4.0" + +unplugin@^1.16.1, unplugin@^1.4.0, unplugin@^1.5.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.16.1.tgz#a844d2e3c3b14a4ac2945c42be80409321b61199" + integrity sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w== + dependencies: + acorn "^8.14.0" + webpack-virtual-modules "^0.6.2" + +vite@^4.4.9: + version "4.5.14" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.14.tgz#2e652bc1d898265d987d6543ce866ecd65fa4086" + integrity sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g== + dependencies: + esbuild "^0.18.10" + postcss "^8.4.27" + rollup "^3.27.1" + optionalDependencies: + fsevents "~2.3.2" + +vue-demi@*: + version "0.14.10" + resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04" + integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg== + +vue-router@^4.2.4: + version "4.5.1" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.5.1.tgz#47bffe2d3a5479d2886a9a244547a853aa0abf69" + integrity sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw== + dependencies: + "@vue/devtools-api" "^6.6.4" + +vue@^3.3.4: + version "3.5.16" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.16.tgz#f0cde88c2688354f00ff2d77eb295c26440f8c7a" + integrity sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w== + dependencies: + "@vue/compiler-dom" "3.5.16" + "@vue/compiler-sfc" "3.5.16" + "@vue/runtime-dom" "3.5.16" + "@vue/server-renderer" "3.5.16" + "@vue/shared" "3.5.16" + +webpack-virtual-modules@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8" + integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ== + +zrender@5.6.1: + version "5.6.1" + resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.6.1.tgz#e08d57ecf4acac708c4fcb7481eb201df7f10a6b" + integrity sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag== + dependencies: + tslib "2.3.0" diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/start.bat b/src/声源定位代码/audio-classification/audio-classification-platform/start.bat new file mode 100644 index 0000000..8094d48 --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/start.bat @@ -0,0 +1,24 @@ +@echo off +echo ================================ +echo 声纹识别系统启动脚本 +echo ================================ +echo. + +echo 正在启动后端服务... +cd /d "%~dp0backend" +start "后端服务" cmd /k "python app.py" + +echo 等待后端服务启动... +timeout /t 3 /nobreak >nul + +echo 正在启动前端服务... +cd /d "%~dp0frontend" +start "前端服务" cmd /k "npm run dev" + +echo. +echo 启动完成! +echo 后端服务: http://localhost:5000 +echo 前端服务: http://localhost:3000 +echo. +echo 请等待服务完全启动后访问前端地址 +pause diff --git a/src/声源定位代码/audio-classification/audio-classification-platform/start.sh b/src/声源定位代码/audio-classification/audio-classification-platform/start.sh new file mode 100644 index 0000000..06674da --- /dev/null +++ b/src/声源定位代码/audio-classification/audio-classification-platform/start.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +echo "================================" +echo " 声纹识别系统启动脚本" +echo "================================" +echo + +# 获取脚本所在目录 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +echo "正在启动后端服务..." +cd "$SCRIPT_DIR/backend" +python app.py & +BACKEND_PID=$! + +echo "等待后端服务启动..." +sleep 3 + +echo "正在启动前端服务..." +cd "$SCRIPT_DIR/frontend" +npm run dev & +FRONTEND_PID=$! + +echo +echo "启动完成!" +echo "后端服务: http://localhost:5000" +echo "前端服务: http://localhost:3000" +echo +echo "后端进程 PID: $BACKEND_PID" +echo "前端进程 PID: $FRONTEND_PID" +echo +echo "按 Ctrl+C 停止所有服务" + +# 等待用户中断 +trap 'echo "正在停止服务..."; kill $BACKEND_PID $FRONTEND_PID; exit' INT +wait diff --git a/src/声源定位代码/audio-classification/configs/augmentation.yml b/src/声源定位代码/audio-classification/configs/augmentation.yml new file mode 100644 index 0000000..5ffe3c5 --- /dev/null +++ b/src/声源定位代码/audio-classification/configs/augmentation.yml @@ -0,0 +1,46 @@ +# 语速增强 +speed: + # 增强概率 + prob: 1.0 + +# 音量增强 +volume: + # 增强概率 + prob: 0.0 + # 最小增益 + min_gain_dBFS: -15 + # 最大增益 + max_gain_dBFS: 15 + +# 噪声增强 +noise: + # 增强概率 + prob: 0.5 + # 噪声增强的噪声文件夹 + noise_dir: 'dataset/noise' + # 针对噪声的最小音量增益 + min_snr_dB: 10 + # 针对噪声的最大音量增益 + max_snr_dB: 50 + +# 混响增强 +reverb: + # 增强概率 + prob: 0.5 + # 混响增强的混响文件夹 + reverb_dir: 'dataset/reverb' + +# Spec增强 +spec_aug: + # 增强概率 + prob: 0.5 + # 频域掩蔽的比例 + freq_mask_ratio: 0.1 + # 频域掩蔽次数 + n_freq_masks: 1 + # 频域掩蔽的比例 + time_mask_ratio: 0.05 + # 频域掩蔽次数 + n_time_masks: 1 + # 最大时间扭曲 + max_time_warp: 0 diff --git a/src/声源定位代码/audio-classification/configs/cam++.yml b/src/声源定位代码/audio-classification/configs/cam++.yml new file mode 100644 index 0000000..ce68da9 --- /dev/null +++ b/src/声源定位代码/audio-classification/configs/cam++.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 64 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 8 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'CAMPPlus' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/audio-classification/configs/ecapa_tdnn.yml b/src/声源定位代码/audio-classification/configs/ecapa_tdnn.yml new file mode 100644 index 0000000..6c13e50 --- /dev/null +++ b/src/声源定位代码/audio-classification/configs/ecapa_tdnn.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 128 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 16 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'EcapaTdnn' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/audio-classification/configs/eres2net.yml b/src/声源定位代码/audio-classification/configs/eres2net.yml new file mode 100644 index 0000000..6bc1170 --- /dev/null +++ b/src/声源定位代码/audio-classification/configs/eres2net.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 32 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 4 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型,支持ERes2Net、ERes2NetV2 + model: 'ERes2Net' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/audio-classification/configs/panns.yml b/src/声源定位代码/audio-classification/configs/panns.yml new file mode 100644 index 0000000..5d000f1 --- /dev/null +++ b/src/声源定位代码/audio-classification/configs/panns.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 64 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 8 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: +# 所使用的模型,支持PANNS_CNN6、PANNS_CNN10、PANNS_CNN14 + model: 'PANNS_CNN10' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/audio-classification/configs/res2net.yml b/src/声源定位代码/audio-classification/configs/res2net.yml new file mode 100644 index 0000000..072e2e4 --- /dev/null +++ b/src/声源定位代码/audio-classification/configs/res2net.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 32 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 4 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'Res2Net' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/audio-classification/configs/resnet_se.yml b/src/声源定位代码/audio-classification/configs/resnet_se.yml new file mode 100644 index 0000000..5af006d --- /dev/null +++ b/src/声源定位代码/audio-classification/configs/resnet_se.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 32 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 4 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'ResNetSE' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/audio-classification/configs/tdnn.yml b/src/声源定位代码/audio-classification/configs/tdnn.yml new file mode 100644 index 0000000..9cd3d2a --- /dev/null +++ b/src/声源定位代码/audio-classification/configs/tdnn.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 64 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 8 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'TDNN' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/audio-classification/create_data.py b/src/声源定位代码/audio-classification/create_data.py new file mode 100644 index 0000000..da73e90 --- /dev/null +++ b/src/声源定位代码/audio-classification/create_data.py @@ -0,0 +1,99 @@ +import os + + +# 生成数据列表 +def get_data_list(audio_path, list_path): + sound_sum = 0 + audios = os.listdir(audio_path) + os.makedirs(list_path, exist_ok=True) + f_train = open(os.path.join(list_path, 'train_list.txt'), 'w', encoding='utf-8') + f_test = open(os.path.join(list_path, 'test_list.txt'), 'w', encoding='utf-8') + f_label = open(os.path.join(list_path, 'label_list.txt'), 'w', encoding='utf-8') + + for i in range(len(audios)): + f_label.write(f'{audios[i]}\n') + sounds = os.listdir(os.path.join(audio_path, audios[i])) + for sound in sounds: + sound_path = os.path.join(audio_path, audios[i], sound).replace('\\', '/') + if sound_sum % 10 == 0: + f_test.write(f'{sound_path}\t{i}\n') + else: + f_train.write(f'{sound_path}\t{i}\n') + sound_sum += 1 + print(f"Audio:{i + 1}/{len(audios)}") + f_label.close() + f_test.close() + f_train.close() + + +# 下载数据方式,执行:./tools/download_3dspeaker_data.sh +# 生成生成方言数据列表 +def get_language_identification_data_list(audio_path, list_path): + labels_dict = {0: 'Standard Mandarin', 3: 'Southwestern Mandarin', 6: 'Central Plains Mandarin', + 4: 'JiangHuai Mandarin', 2: 'Wu dialect', 8: 'Gan dialect', 9: 'Jin dialect', + 11: 'LiaoJiao Mandarin', 12: 'JiLu Mandarin', 10: 'Min dialect', 7: 'Yue dialect', + 5: 'Hakka dialect', 1: 'Xiang dialect', 13: 'Northern Mandarin'} + + with open(os.path.join(list_path, 'train_list.txt'), 'w', encoding='utf-8') as f: + train_dir = os.path.join(audio_path, 'train') + for root, dirs, files in os.walk(train_dir): + for file in files: + if not file.endswith('.wav'): continue + label = int(file.split('_')[-1].replace('.wav', '')[-2:]) + file = os.path.join(root, file) + f.write(f'{file}\t{label}\n') + + with open(os.path.join(list_path, 'test_list.txt'), 'w', encoding='utf-8') as f: + test_dir = os.path.join(audio_path, 'test') + for root, dirs, files in os.walk(test_dir): + for file in files: + if not file.endswith('.wav'): continue + label = int(file.split('_')[-1].replace('.wav', '')[-2:]) + file = os.path.join(root, file) + f.write(f'{file}\t{label}\n') + + with open(os.path.join(list_path, 'label_list.txt'), 'w', encoding='utf-8') as f: + for i in range(len(labels_dict)): + f.write(f'{labels_dict[i]}\n') + + +# 创建UrbanSound8K数据列表 +def create_UrbanSound8K_list(audio_path, metadata_path, list_path): + sound_sum = 0 + + f_train = open(os.path.join(list_path, 'train_list.txt'), 'w', encoding='utf-8') + f_test = open(os.path.join(list_path, 'test_list.txt'), 'w', encoding='utf-8') + f_label = open(os.path.join(list_path, 'label_list.txt'), 'w', encoding='utf-8') + + with open(metadata_path) as f: + lines = f.readlines() + + labels = {} + for i, line in enumerate(lines): + if i == 0:continue + data = line.replace('\n', '').split(',') + class_id = int(data[6]) + if class_id not in labels.keys(): + labels[class_id] = data[-1] + sound_path = os.path.join(audio_path, f'fold{data[5]}', data[0]).replace('\\', '/') + if sound_sum % 10 == 0: + f_test.write(f'{sound_path}\t{data[6]}\n') + else: + f_train.write(f'{sound_path}\t{data[6]}\n') + sound_sum += 1 + for i in range(len(labels)): + f_label.write(f'{labels[i]}\n') + f_label.close() + f_test.close() + f_train.close() + + +if __name__ == '__main__': + # get_data_list('dataset/audio', 'dataset') + # 生成生成方言数据列表 + # get_language_identification_data_list(audio_path='dataset/language', + # list_path='dataset/') + # 创建UrbanSound8K数据列表 + create_UrbanSound8K_list(audio_path='dataset/UrbanSound8K/audio', + metadata_path='dataset/UrbanSound8K/metadata/UrbanSound8K.csv', + list_path='dataset') diff --git a/src/声源定位代码/audio-classification/docs/images/image1.png b/src/声源定位代码/audio-classification/docs/images/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..6bba58a14c8d2e9aea2a11ea36b75a8c7e2c3d40 GIT binary patch literal 69600 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 literal 0 HcmV?d00001 diff --git a/src/声源定位代码/audio-classification/docs/images/log.jpg b/src/声源定位代码/audio-classification/docs/images/log.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4a98e48e4dd781313b299c0de7cf3a3ecc9d9c82 GIT binary patch literal 117637 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
-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 literal 0 HcmV?d00001 diff --git a/src/声源定位代码/audio-classification/eval.py b/src/声源定位代码/audio-classification/eval.py new file mode 100644 index 0000000..ce7b04f --- /dev/null +++ b/src/声源定位代码/audio-classification/eval.py @@ -0,0 +1,26 @@ +import argparse +import functools +import time + +from macls.trainer import MAClsTrainer +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', "配置文件") +add_arg("use_gpu", bool, True, "是否使用GPU评估模型") +add_arg('save_matrix_path', str, 'output/images/', "保存混合矩阵的路径") +add_arg('resume_model', str, 'models/CAMPPlus_Fbank/best_model/', "模型的路径") +add_arg('overwrites', str, None, '覆盖配置文件中的参数,比如"train_conf.max_epoch=100",多个用逗号隔开') +args = parser.parse_args() +print_arguments(args=args) + +# 获取训练器 +trainer = MAClsTrainer(configs=args.configs, use_gpu=args.use_gpu, overwrites=args.overwrites) + +# 开始评估 +start = time.time() +loss, accuracy = trainer.evaluate(resume_model=args.resume_model, + save_matrix_path=args.save_matrix_path) +end = time.time() +print('评估消耗时间:{}s,loss:{:.5f},accuracy:{:.5f}'.format(int(end - start), loss, accuracy)) diff --git a/src/声源定位代码/audio-classification/extract_features.py b/src/声源定位代码/audio-classification/extract_features.py new file mode 100644 index 0000000..c707a58 --- /dev/null +++ b/src/声源定位代码/audio-classification/extract_features.py @@ -0,0 +1,19 @@ +import argparse +import functools + +from macls.trainer import MAClsTrainer +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', '配置文件') +add_arg('save_dir', str, 'dataset/features', '保存特征的路径') +add_arg('max_duration', int, 100, '提取特征的最大时长,避免过长显存不足,单位秒') +args = parser.parse_args() +print_arguments(args=args) + +# 获取训练器 +trainer = MAClsTrainer(configs=args.configs) + +# 提取特征保存文件 +trainer.extract_features(save_dir=args.save_dir, max_duration=args.max_duration) diff --git a/src/声源定位代码/audio-classification/infer.py b/src/声源定位代码/audio-classification/infer.py new file mode 100644 index 0000000..6312cad --- /dev/null +++ b/src/声源定位代码/audio-classification/infer.py @@ -0,0 +1,23 @@ +import argparse +import functools + +from macls.predict import MAClsPredictor +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', '配置文件') +add_arg('use_gpu', bool, True, '是否使用GPU预测') +add_arg('audio_path', str, 'dataset/UrbanSound8K/audio/fold5/156634-5-2-5.wav', '音频路径') +add_arg('model_path', str, 'models/CAMPPlus_Fbank/best_model/', '导出的预测模型文件路径') +args = parser.parse_args() +print_arguments(args=args) + +# 获取识别器 +predictor = MAClsPredictor(configs=args.configs, + model_path=args.model_path, + use_gpu=args.use_gpu) + +label, score = predictor.predict(audio_data=args.audio_path) + +print(f'音频:{args.audio_path} 的预测结果标签为:{label},得分:{score}') diff --git a/src/声源定位代码/audio-classification/infer_record.py b/src/声源定位代码/audio-classification/infer_record.py new file mode 100644 index 0000000..4723439 --- /dev/null +++ b/src/声源定位代码/audio-classification/infer_record.py @@ -0,0 +1,58 @@ +import argparse +import functools +import threading +import time + +import numpy as np +import soundcard as sc + +from macls.predict import MAClsPredictor +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', '配置文件') +add_arg('use_gpu', bool, True, '是否使用GPU预测') +add_arg('record_seconds', float, 3, '录音长度') +add_arg('model_path', str, 'models/CAMPPlus_Fbank/best_model/', '导出的预测模型文件路径') +args = parser.parse_args() +print_arguments(args=args) + +# 获取识别器 +predictor = MAClsPredictor(configs=args.configs, + model_path=args.model_path, + use_gpu=args.use_gpu) + +all_data = [] +# 获取默认麦克风 +default_mic = sc.default_microphone() +# 录音采样率 +samplerate = 16000 +# 录音块大小 +numframes = 1024 +# 模型输入长度 +infer_len = int(samplerate * args.record_seconds / numframes) + + +def infer_thread(): + global all_data + s = time.time() + while True: + if len(all_data) < infer_len: continue + # 截取最新的音频数据 + seg_data = all_data[-infer_len:] + d = np.concatenate(seg_data) + # 删除旧的音频数据 + del all_data[:len(all_data) - infer_len] + label, score = predictor.predict(audio_data=d, sample_rate=samplerate) + print(f'{int(time.time() - s)}s 预测结果标签为:{label},得分:{score}') + + +thread = threading.Thread(target=infer_thread, args=()) +thread.start() + + +with default_mic.recorder(samplerate=samplerate, channels=1) as mic: + while True: + data = mic.record(numframes=numframes) + all_data.append(data) diff --git a/src/声源定位代码/audio-classification/macls/__init__.py b/src/声源定位代码/audio-classification/macls/__init__.py new file mode 100644 index 0000000..382021f --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/__init__.py @@ -0,0 +1 @@ +__version__ = "1.0.6" diff --git a/src/声源定位代码/audio-classification/macls/data_utils/__init__.py b/src/声源定位代码/audio-classification/macls/data_utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/声源定位代码/audio-classification/macls/data_utils/collate_fn.py b/src/声源定位代码/audio-classification/macls/data_utils/collate_fn.py new file mode 100644 index 0000000..354e37e --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/data_utils/collate_fn.py @@ -0,0 +1,23 @@ +import torch + + +# 对一个batch的数据处理 +def collate_fn(batch): + # 找出音频长度最长的 + batch_sorted = sorted(batch, key=lambda sample: sample[0].size(0), reverse=True) + freq_size = batch_sorted[0][0].size(1) + max_freq_length = batch_sorted[0][0].size(0) + batch_size = len(batch_sorted) + # 以最大的长度创建0张量 + features = torch.zeros((batch_size, max_freq_length, freq_size), dtype=torch.float32) + input_lens, labels = [], [] + for x in range(batch_size): + tensor, label = batch[x] + seq_length = tensor.size(0) + # 将数据插入都0张量中,实现了padding + features[x, :seq_length, :] = tensor[:, :] + labels.append(label) + input_lens.append(seq_length) + labels = torch.tensor(labels, dtype=torch.int64) + input_lens = torch.tensor(input_lens, dtype=torch.int64) + return features, labels, input_lens diff --git a/src/声源定位代码/audio-classification/macls/data_utils/featurizer.py b/src/声源定位代码/audio-classification/macls/data_utils/featurizer.py new file mode 100644 index 0000000..d880f2c --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/data_utils/featurizer.py @@ -0,0 +1,132 @@ +import numpy as np +import torch +import torchaudio.compliance.kaldi as Kaldi +from torch import nn +from torchaudio.transforms import MelSpectrogram, Spectrogram, MFCC +from loguru import logger + + +class AudioFeaturizer(nn.Module): + """音频特征器 + + :param feature_method: 所使用的预处理方法 + :type feature_method: str + :param use_hf_model: 是否使用HF上的Wav2Vec2类似模型提取音频特征 + :type use_hf_model: bool + :param method_args: 预处理方法的参数 + :type method_args: dict + """ + + def __init__(self, feature_method='MelSpectrogram', use_hf_model=False, method_args={}): + super().__init__() + self._method_args = method_args + self._feature_method = feature_method + self.use_hf_model = use_hf_model + if self.use_hf_model: + from transformers import AutoModel, AutoFeatureExtractor + # 判断是否使用GPU提取特征 + use_gpu = torch.cuda.is_available() and method_args.get('use_gpu', True) + self.device = torch.device("cuda") if use_gpu else torch.device("cpu") + # 加载Wav2Vec2类似模型 + self.processor = AutoFeatureExtractor.from_pretrained(feature_method) + self.feature_model = AutoModel.from_pretrained(feature_method).to(self.device) + logger.info(f'使用模型【{feature_method}】提取特征,使用【{self.device}】设备提取') + # 获取模型的输出通道数 + inputs = self.processor(np.ones(16000 * 1, dtype=np.float32), sampling_rate=16000, + return_tensors="pt").to(self.device) + with torch.no_grad(): + outputs = self.feature_model(**inputs) + self.output_channels = outputs.extract_features.shape[2] + else: + if feature_method == 'MelSpectrogram': + self.feat_fun = MelSpectrogram(**method_args) + elif feature_method == 'Spectrogram': + self.feat_fun = Spectrogram(**method_args) + elif feature_method == 'MFCC': + self.feat_fun = MFCC(**method_args) + elif feature_method == 'Fbank': + self.feat_fun = KaldiFbank(**method_args) + else: + raise Exception(f'预处理方法 {self._feature_method} 不存在!') + logger.info(f'使用【{feature_method}】提取特征') + + def forward(self, waveforms, input_lens_ratio=None): + """从AudioSegment中提取音频特征 + + :param waveforms: Audio segment to extract features from. + :type waveforms: AudioSegment + :param input_lens_ratio: input length ratio + :type input_lens_ratio: tensor + :return: Spectrogram audio feature in 2darray. + :rtype: ndarray + """ + if len(waveforms.shape) == 1: + waveforms = waveforms.unsqueeze(0) + if self.use_hf_model: + # 使用HF上的Wav2Vec2类似模型提取音频特征 + if isinstance(waveforms, torch.Tensor): + waveforms = waveforms.numpy() + inputs = self.processor(waveforms, sampling_rate=16000, + return_tensors="pt").to(self.device) + with torch.no_grad(): + outputs = self.feature_model(**inputs) + feature = outputs.extract_features.cpu().detach() + else: + # 使用普通方法提取音频特征 + feature = self.feat_fun(waveforms) + feature = feature.transpose(2, 1) + # 归一化 + feature = feature - feature.mean(1, keepdim=True) + if input_lens_ratio is not None: + # 对掩码比例进行扩展 + input_lens = (input_lens_ratio * feature.shape[1]) + mask_lens = torch.round(input_lens).long() + mask_lens = mask_lens.unsqueeze(1) + # 生成掩码张量 + idxs = torch.arange(feature.shape[1], device=feature.device).repeat(feature.shape[0], 1) + mask = idxs < mask_lens + mask = mask.unsqueeze(-1) + # 对特征进行掩码操作 + feature = torch.where(mask, feature, torch.zeros_like(feature)) + return feature + + @property + def feature_dim(self): + """返回特征大小 + + :return: 特征大小 + :rtype: int + """ + if self.use_hf_model: + return self.output_channels + if self._feature_method == 'MelSpectrogram': + return self._method_args.get('n_mels', 128) + elif self._feature_method == 'Spectrogram': + return self._method_args.get('n_fft', 400) // 2 + 1 + elif self._feature_method == 'MFCC': + return self._method_args.get('n_mfcc', 40) + elif self._feature_method == 'Fbank': + return self._method_args.get('num_mel_bins', 23) + else: + raise Exception('没有{}预处理方法'.format(self._feature_method)) + + +class KaldiFbank(nn.Module): + def __init__(self, **kwargs): + super(KaldiFbank, self).__init__() + self.kwargs = kwargs + + def forward(self, waveforms): + """ + :param waveforms: [Batch, Length] + :return: [Batch, Feature, Length] + """ + log_fbanks = [] + for waveform in waveforms: + if len(waveform.shape) == 1: + waveform = waveform.unsqueeze(0) + log_fbank = Kaldi.fbank(waveform, **self.kwargs) + log_fbank = log_fbank.transpose(0, 1) + log_fbanks.append(log_fbank) + log_fbank = torch.stack(log_fbanks) + return log_fbank diff --git a/src/声源定位代码/audio-classification/macls/data_utils/reader.py b/src/声源定位代码/audio-classification/macls/data_utils/reader.py new file mode 100644 index 0000000..7d496da --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/data_utils/reader.py @@ -0,0 +1,157 @@ +import random + +import numpy as np +import torch +from torch.utils.data import Dataset +from tqdm import tqdm +from yeaudio.audio import AudioSegment +from yeaudio.augmentation import SpeedPerturbAugmentor, VolumePerturbAugmentor, NoisePerturbAugmentor, \ + ReverbPerturbAugmentor, SpecAugmentor + +from macls.data_utils.featurizer import AudioFeaturizer + + +class MAClsDataset(Dataset): + def __init__(self, + data_list_path, + audio_featurizer: AudioFeaturizer, + max_duration=3, + min_duration=0.5, + mode='train', + sample_rate=16000, + aug_conf=None, + use_dB_normalization=True, + target_dB=-20): + """音频数据加载器 + + Args: + data_list_path: 包含音频路径和标签的数据列表文件的路径 + audio_featurizer: 声纹特征提取器 + max_duration: 最长的音频长度,大于这个长度会裁剪掉 + min_duration: 过滤最短的音频长度 + aug_conf: 用于指定音频增强的配置 + mode: 数据集模式。在训练模式下,数据集可能会进行一些数据增强的预处理 + sample_rate: 采样率 + use_dB_normalization: 是否对音频进行音量归一化 + target_dB: 音量归一化的大小 + """ + super(MAClsDataset, self).__init__() + assert mode in ['train', 'eval', 'extract_feature'] + self.data_list_path = data_list_path + self.max_duration = max_duration + self.min_duration = min_duration + self.mode = mode + self._target_sample_rate = sample_rate + self._use_dB_normalization = use_dB_normalization + self._target_dB = target_dB + self.speed_augment = None + self.volume_augment = None + self.noise_augment = None + self.reverb_augment = None + self.spec_augment = None + # 获取特征器 + self.audio_featurizer = audio_featurizer + # 获取特征裁剪的大小 + self.max_feature_len = self.get_crop_feature_len() + # 获取数据列表 + with open(self.data_list_path, 'r', encoding='utf-8') as f: + self.lines = f.readlines() + if mode == 'train' and aug_conf is not None: + # 获取数据增强器 + self.get_augmentor(aug_conf) + # 评估模式下,数据列表需要排序 + if self.mode == 'eval': + self.sort_list() + + def __getitem__(self, idx): + # 分割数据文件路径和标签 + data_path, label = self.lines[idx].replace('\n', '').split('\t') + # 如果后缀名为.npy的文件,那么直接读取 + if data_path.endswith('.npy'): + feature = np.load(data_path) + if feature.shape[0] > self.max_feature_len: + crop_start = random.randint(0, feature.shape[0] - self.max_feature_len) if self.mode == 'train' else 0 + feature = feature[crop_start:crop_start + self.max_feature_len, :] + feature = torch.tensor(feature, dtype=torch.float32) + else: + audio_path, label = self.lines[idx].strip().split('\t') + # 读取音频 + audio_segment = AudioSegment.from_file(audio_path) + # 数据太短不利于训练 + if self.mode == 'train' or self.mode == 'extract_feature': + if audio_segment.duration < self.min_duration: + return self.__getitem__(idx + 1 if idx < len(self.lines) - 1 else 0) + # 音频增强 + if self.mode == 'train': + audio_segment = self.augment_audio(audio_segment) + # 重采样 + if audio_segment.sample_rate != self._target_sample_rate: + audio_segment.resample(self._target_sample_rate) + # 音量归一化 + if self._use_dB_normalization: + audio_segment.normalize(target_db=self._target_dB) + # 裁剪需要的数据 + if audio_segment.duration > self.max_duration: + audio_segment.crop(duration=self.max_duration, mode=self.mode) + samples = torch.tensor(audio_segment.samples, dtype=torch.float32) + feature = self.audio_featurizer(samples) + feature = feature.squeeze(0) + if self.mode == 'train' and self.spec_augment is not None: + feature = self.spec_augment(feature.cpu().numpy()) + feature = torch.tensor(feature, dtype=torch.float32) + label = torch.tensor(int(label), dtype=torch.int64) + return feature, label + + def __len__(self): + return len(self.lines) + + # 获取特征裁剪的大小,对应max_duration音频提取特征后的长度 + def get_crop_feature_len(self): + samples = torch.randn((1, self.max_duration * self._target_sample_rate)) + feature = self.audio_featurizer(samples).squeeze(0) + freq_len = feature.size(0) + return freq_len + + # 数据列表需要排序 + def sort_list(self): + lengths = [] + for line in tqdm(self.lines, desc=f"对列表[{self.data_list_path}]进行长度排序"): + # 分割数据文件路径和标签 + data_path, _ = line.split('\t') + if data_path.endswith('.npy'): + feature = np.load(data_path) + length = feature.shape[0] + lengths.append(length) + else: + # 读取音频 + audio_segment = AudioSegment.from_file(data_path) + length = audio_segment.duration + lengths.append(length) + # 对长度排序并获取索引 + sorted_indexes = np.argsort(lengths) + self.lines = [self.lines[i] for i in sorted_indexes] + + # 获取数据增强器 + def get_augmentor(self, aug_conf): + if aug_conf.speed is not None: + self.speed_augment = SpeedPerturbAugmentor(**aug_conf.speed) + if aug_conf.volume is not None: + self.volume_augment = VolumePerturbAugmentor(**aug_conf.volume) + if aug_conf.noise is not None: + self.noise_augment = NoisePerturbAugmentor(**aug_conf.noise) + if aug_conf.reverb is not None: + self.reverb_augment = ReverbPerturbAugmentor(**aug_conf.reverb) + if aug_conf.spec_aug is not None: + self.spec_augment = SpecAugmentor(**aug_conf.spec_aug) + + # 音频增强 + def augment_audio(self, audio_segment): + if self.speed_augment is not None: + audio_segment = self.speed_augment(audio_segment) + if self.volume_augment is not None: + audio_segment = self.volume_augment(audio_segment) + if self.noise_augment is not None: + audio_segment = self.noise_augment(audio_segment) + if self.reverb_augment is not None: + audio_segment = self.reverb_augment(audio_segment) + return audio_segment diff --git a/src/声源定位代码/audio-classification/macls/metric/__init__.py b/src/声源定位代码/audio-classification/macls/metric/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/声源定位代码/audio-classification/macls/metric/metrics.py b/src/声源定位代码/audio-classification/macls/metric/metrics.py new file mode 100644 index 0000000..431c60a --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/metric/metrics.py @@ -0,0 +1,12 @@ +import numpy as np +import torch + + +# 计算准确率 +def accuracy(output, label): + output = torch.nn.functional.softmax(output, dim=-1) + output = output.data.cpu().numpy() + output = np.argmax(output, axis=1) + label = label.data.cpu().numpy() + acc = np.mean((output == label).astype(int)) + return acc diff --git a/src/声源定位代码/audio-classification/macls/optimizer/__init__.py b/src/声源定位代码/audio-classification/macls/optimizer/__init__.py new file mode 100644 index 0000000..4362420 --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/optimizer/__init__.py @@ -0,0 +1,32 @@ +import importlib + +from loguru import logger +from torch.optim import * +from .scheduler import WarmupCosineSchedulerLR +from torch.optim.lr_scheduler import * + +__all__ = ['build_optimizer', 'build_lr_scheduler'] + + +def build_optimizer(params, configs): + use_optimizer = configs.optimizer_conf.get('optimizer', 'Adam') + optimizer_args = configs.optimizer_conf.get('optimizer_args', {}) + optim = importlib.import_module(__name__) + optimizer = getattr(optim, use_optimizer)(params=params, **optimizer_args) + logger.info(f'成功创建优化方法:{use_optimizer},参数为:{optimizer_args}') + return optimizer + + +def build_lr_scheduler(optimizer, step_per_epoch, configs): + use_scheduler = configs.optimizer_conf.get('scheduler', 'WarmupCosineSchedulerLR') + scheduler_args = configs.optimizer_conf.get('scheduler_args', {}) + if configs.optimizer_conf.scheduler == 'CosineAnnealingLR' and 'T_max' not in scheduler_args: + scheduler_args.T_max = int(configs.train_conf.max_epoch * 1.2) * step_per_epoch + if configs.optimizer_conf.scheduler == 'WarmupCosineSchedulerLR' and 'fix_epoch' not in scheduler_args: + scheduler_args.fix_epoch = configs.train_conf.max_epoch + if configs.optimizer_conf.scheduler == 'WarmupCosineSchedulerLR' and 'step_per_epoch' not in scheduler_args: + scheduler_args.step_per_epoch = step_per_epoch + optim = importlib.import_module(__name__) + scheduler = getattr(optim, use_scheduler)(optimizer=optimizer, **scheduler_args) + logger.info(f'成功创建学习率衰减:{use_scheduler},参数为:{scheduler_args}') + return scheduler diff --git a/src/声源定位代码/audio-classification/macls/optimizer/scheduler.py b/src/声源定位代码/audio-classification/macls/optimizer/scheduler.py new file mode 100644 index 0000000..e2ac1b7 --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/optimizer/scheduler.py @@ -0,0 +1,48 @@ +import math +from typing import List + + +class WarmupCosineSchedulerLR: + def __init__( + self, + optimizer, + min_lr, + max_lr, + warmup_epoch, + fix_epoch, + step_per_epoch + ): + self.optimizer = optimizer + assert min_lr <= max_lr + self.min_lr = min_lr + self.max_lr = max_lr + self.warmup_step = warmup_epoch * step_per_epoch + self.fix_step = fix_epoch * step_per_epoch + self.current_step = 0.0 + + def set_lr(self, ): + new_lr = self.clr(self.current_step) + for param_group in self.optimizer.param_groups: + param_group['lr'] = new_lr + return new_lr + + def step(self, step=None): + if step is not None: + self.current_step = step + new_lr = self.set_lr() + self.current_step += 1 + return new_lr + + def clr(self, step): + if step < self.warmup_step: + return self.min_lr + (self.max_lr - self.min_lr) * \ + (step / self.warmup_step) + elif self.warmup_step <= step < self.fix_step: + return self.min_lr + 0.5 * (self.max_lr - self.min_lr) * \ + (1 + math.cos(math.pi * (step - self.warmup_step) / + (self.fix_step - self.warmup_step))) + else: + return self.min_lr + + def get_last_lr(self) -> List[float]: + return [self.clr(self.current_step)] diff --git a/src/声源定位代码/audio-classification/macls/predict.py b/src/声源定位代码/audio-classification/macls/predict.py new file mode 100644 index 0000000..25e3bbc --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/predict.py @@ -0,0 +1,177 @@ +import os +import sys +from io import BufferedReader +from typing import List + +import numpy as np +import torch +import yaml +from loguru import logger +from yeaudio.audio import AudioSegment +from macls.data_utils.featurizer import AudioFeaturizer +from macls.models import build_model +from macls.utils.utils import dict_to_object, print_arguments, convert_string_based_on_type + + +class MAClsPredictor: + def __init__(self, + configs, + model_path='models/CAMPPlus_Fbank/best_model/', + use_gpu=True, + overwrites=None, + log_level="info"): + """声音分类预测工具 + + :param configs: 配置文件路径,或者模型名称,如果是模型名称则会使用默认的配置文件 + :param model_path: 导出的预测模型文件夹路径 + :param use_gpu: 是否使用GPU预测 + :param overwrites: 覆盖配置文件中的参数,比如"train_conf.max_epoch=100",多个用逗号隔开 + :param log_level: 打印的日志等级,可选值有:"debug", "info", "warning", "error" + """ + if use_gpu: + assert (torch.cuda.is_available()), 'GPU不可用' + self.device = torch.device("cuda") + else: + os.environ['CUDA_VISIBLE_DEVICES'] = '-1' + self.device = torch.device("cpu") + self.log_level = log_level.upper() + logger.remove() + logger.add(sink=sys.stdout, level=self.log_level) + # 读取配置文件 + if isinstance(configs, str): + # 获取当前程序绝对路径 + absolute_path = os.path.dirname(__file__) + # 获取默认配置文件路径 + config_path = os.path.join(absolute_path, f"configs/{configs}.yml") + configs = config_path if os.path.exists(config_path) else configs + with open(configs, 'r', encoding='utf-8') as f: + configs = yaml.load(f.read(), Loader=yaml.FullLoader) + self.configs = dict_to_object(configs) + # 覆盖配置文件中的参数 + if overwrites: + overwrites = overwrites.split(",") + for overwrite in overwrites: + keys, value = overwrite.strip().split("=") + attrs = keys.split('.') + current_level = self.configs + for attr in attrs[:-1]: + current_level = getattr(current_level, attr) + before_value = getattr(current_level, attrs[-1]) + setattr(current_level, attrs[-1], convert_string_based_on_type(before_value, value)) + # 打印配置信息 + print_arguments(configs=self.configs) + # 获取特征器 + self._audio_featurizer = AudioFeaturizer(feature_method=self.configs.preprocess_conf.feature_method, + use_hf_model=self.configs.preprocess_conf.get('use_hf_model', False), + method_args=self.configs.preprocess_conf.get('method_args', {})) + # 获取分类标签 + with open(self.configs.dataset_conf.label_list_path, 'r', encoding='utf-8') as f: + lines = f.readlines() + self.class_labels = [l.replace('\n', '') for l in lines] + # 自动获取列表数量 + if self.configs.model_conf.model_args.get('num_class', None) is None: + self.configs.model_conf.model_args.num_class = len(self.class_labels) + # 获取模型 + self.predictor = build_model(input_size=self._audio_featurizer.feature_dim, configs=self.configs) + self.predictor.to(self.device) + # 加载模型 + if os.path.isdir(model_path): + model_path = os.path.join(model_path, 'model.pth') + assert os.path.exists(model_path), f"{model_path} 模型不存在!" + if torch.cuda.is_available() and use_gpu: + model_state_dict = torch.load(model_path, weights_only=False) + else: + model_state_dict = torch.load(model_path, weights_only=False, map_location='cpu') + self.predictor.load_state_dict(model_state_dict) + logger.info(f"成功加载模型参数:{model_path}") + self.predictor.eval() + + def _load_audio(self, audio_data, sample_rate=16000): + """加载音频 + :param audio_data: 需要识别的数据,支持文件路径,文件对象,字节,numpy。如果是字节的话,必须是完整的字节文件 + :param sample_rate: 如果传入的事numpy数据,需要指定采样率 + :return: 识别的文本结果和解码的得分数 + """ + # 加载音频文件,并进行预处理 + if isinstance(audio_data, str): + audio_segment = AudioSegment.from_file(audio_data) + elif isinstance(audio_data, BufferedReader): + audio_segment = AudioSegment.from_file(audio_data) + elif isinstance(audio_data, np.ndarray): + audio_segment = AudioSegment.from_ndarray(audio_data, sample_rate) + elif isinstance(audio_data, bytes): + audio_segment = AudioSegment.from_bytes(audio_data) + else: + raise Exception(f'不支持该数据类型,当前数据类型为:{type(audio_data)}') + # 重采样 + if audio_segment.sample_rate != self.configs.dataset_conf.dataset.sample_rate: + audio_segment.resample(self.configs.dataset_conf.dataset.sample_rate) + # decibel normalization + if self.configs.dataset_conf.dataset.use_dB_normalization: + audio_segment.normalize(target_db=self.configs.dataset_conf.dataset.target_dB) + assert audio_segment.duration >= self.configs.dataset_conf.dataset.min_duration, \ + f'音频太短,最小应该为{self.configs.dataset_conf.dataset.min_duration}s,当前音频为{audio_segment.duration}s' + return audio_segment + + # 预测一个音频的特征 + def predict(self, + audio_data, + sample_rate=16000): + """预测一个音频 + + :param audio_data: 需要识别的数据,支持文件路径,文件对象,字节,numpy。如果是字节的话,必须是完整并带格式的字节文件 + :param sample_rate: 如果传入的事numpy数据,需要指定采样率 + :return: 结果标签和对应的得分 + """ + # 加载音频文件,并进行预处理 + input_data = self._load_audio(audio_data=audio_data, sample_rate=sample_rate) + input_data = torch.tensor(input_data.samples, dtype=torch.float32).unsqueeze(0) + audio_feature = self._audio_featurizer(input_data).to(self.device) + # 执行预测 + output = self.predictor(audio_feature) + result = torch.nn.functional.softmax(output, dim=-1)[0] + result = result.data.cpu().numpy() + # 最大概率的label + lab = np.argsort(result)[-1] + score = result[lab] + return self.class_labels[lab], round(float(score), 5) + + def predict_batch(self, audios_data: List, sample_rate=16000): + """预测一批音频的特征 + + :param audios_data: 需要识别的数据,支持文件路径,文件对象,字节,numpy。如果是字节的话,必须是完整并带格式的字节文件 + :param sample_rate: 如果传入的事numpy数据,需要指定采样率 + :return: 结果标签和对应的得分 + """ + audios_data1 = [] + for audio_data in audios_data: + # 加载音频文件,并进行预处理 + input_data = self._load_audio(audio_data=audio_data, sample_rate=sample_rate) + audios_data1.append(input_data.samples) + # 找出音频长度最长的 + batch = sorted(audios_data1, key=lambda a: a.shape[0], reverse=True) + max_audio_length = batch[0].shape[0] + batch_size = len(batch) + # 以最大的长度创建0张量 + inputs = np.zeros((batch_size, max_audio_length), dtype=np.float32) + input_lens_ratio = [] + for x in range(batch_size): + tensor = audios_data1[x] + seq_length = tensor.shape[0] + # 将数据插入都0张量中,实现了padding + inputs[x, :seq_length] = tensor[:] + input_lens_ratio.append(seq_length / max_audio_length) + inputs = torch.tensor(inputs, dtype=torch.float32) + input_lens_ratio = torch.tensor(input_lens_ratio, dtype=torch.float32) + audio_feature = self._audio_featurizer(inputs, input_lens_ratio).to(self.device) + # 执行预测 + output = self.predictor(audio_feature) + results = torch.nn.functional.softmax(output, dim=-1) + results = results.data.cpu().numpy() + labels, scores = [], [] + for result in results: + lab = np.argsort(result)[-1] + score = result[lab] + labels.append(self.class_labels[lab]) + scores.append(round(float(score), 5)) + return labels, scores diff --git a/src/声源定位代码/audio-classification/macls/trainer.py b/src/声源定位代码/audio-classification/macls/trainer.py new file mode 100644 index 0000000..4412d21 --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/trainer.py @@ -0,0 +1,456 @@ +import os +import platform +import sys +import time +import uuid +from datetime import timedelta + +import numpy as np +import torch +import torch.distributed as dist +import yaml +from sklearn.metrics import confusion_matrix +from torch.utils.data import DataLoader, RandomSampler +from torch.utils.data.distributed import DistributedSampler +from torchinfo import summary +from tqdm import tqdm +from loguru import logger +from visualdl import LogWriter + +from macls.data_utils.collate_fn import collate_fn +from macls.data_utils.featurizer import AudioFeaturizer +from macls.data_utils.reader import MAClsDataset +from macls.metric.metrics import accuracy +from macls.models import build_model +from macls.optimizer import build_optimizer, build_lr_scheduler +from macls.utils.checkpoint import load_pretrained, load_checkpoint, save_checkpoint +from macls.utils.utils import dict_to_object, plot_confusion_matrix, print_arguments, convert_string_based_on_type + + +class MAClsTrainer(object): + def __init__(self, + configs, + use_gpu=True, + data_augment_configs=None, + num_class=None, + overwrites=None, + log_level="info"): + """声音分类训练工具类 + + :param configs: 配置文件路径,或者模型名称,如果是模型名称则会使用默认的配置文件 + :param use_gpu: 是否使用GPU训练模型 + :param data_augment_configs: 数据增强配置字典或者其文件路径 + :param num_class: 分类大小,对应配置文件中的model_conf.model_args.num_class + :param overwrites: 覆盖配置文件中的参数,比如"train_conf.max_epoch=100",多个用逗号隔开 + :param log_level: 打印的日志等级,可选值有:"debug", "info", "warning", "error" + """ + if use_gpu: + assert (torch.cuda.is_available()), 'GPU不可用' + self.device = torch.device("cuda") + else: + os.environ['CUDA_VISIBLE_DEVICES'] = '-1' + self.device = torch.device("cpu") + self.use_gpu = use_gpu + self.log_level = log_level.upper() + logger.remove() + logger.add(sink=sys.stdout, level=self.log_level) + # 读取配置文件 + if isinstance(configs, str): + # 获取当前程序绝对路径 + absolute_path = os.path.dirname(__file__) + # 获取默认配置文件路径 + config_path = os.path.join(absolute_path, f"configs/{configs}.yml") + configs = config_path if os.path.exists(config_path) else configs + with open(configs, 'r', encoding='utf-8') as f: + configs = yaml.load(f.read(), Loader=yaml.FullLoader) + self.configs = dict_to_object(configs) + if num_class is not None: + self.configs.model_conf.model_args.num_class = num_class + # 覆盖配置文件中的参数 + if overwrites: + overwrites = overwrites.split(",") + for overwrite in overwrites: + keys, value = overwrite.strip().split("=") + attrs = keys.split('.') + current_level = self.configs + for attr in attrs[:-1]: + current_level = getattr(current_level, attr) + before_value = getattr(current_level, attrs[-1]) + setattr(current_level, attrs[-1], convert_string_based_on_type(before_value, value)) + # 打印配置信息 + print_arguments(configs=self.configs) + self.model = None + self.optimizer = None + self.scheduler = None + self.audio_featurizer = None + self.train_dataset = None + self.train_loader = None + self.test_dataset = None + self.test_loader = None + self.amp_scaler = None + # 读取数据增强配置文件 + if isinstance(data_augment_configs, str): + with open(data_augment_configs, 'r', encoding='utf-8') as f: + data_augment_configs = yaml.load(f.read(), Loader=yaml.FullLoader) + print_arguments(configs=data_augment_configs, title='数据增强配置') + self.data_augment_configs = dict_to_object(data_augment_configs) + # 获取分类标签 + with open(self.configs.dataset_conf.label_list_path, 'r', encoding='utf-8') as f: + lines = f.readlines() + self.class_labels = [l.replace('\n', '') for l in lines] + if platform.system().lower() == 'windows': + self.configs.dataset_conf.dataLoader.num_workers = 0 + logger.warning('Windows系统不支持多线程读取数据,已自动关闭!') + if self.configs.preprocess_conf.get('use_hf_model', False): + self.configs.dataset_conf.dataLoader.num_workers = 0 + logger.warning('使用HuggingFace模型不支持多线程进行特征提取,已自动关闭!') + self.max_step, self.train_step = None, None + self.train_loss, self.train_acc = None, None + self.train_eta_sec = None + self.eval_loss, self.eval_acc = None, None + self.test_log_step, self.train_log_step = 0, 0 + self.stop_train, self.stop_eval = False, False + + def __setup_dataloader(self, is_train=False): + """ 获取数据加载器 + + :param is_train: 是否获取训练数据 + """ + # 获取特征器 + self.audio_featurizer = AudioFeaturizer(feature_method=self.configs.preprocess_conf.feature_method, + use_hf_model=self.configs.preprocess_conf.get('use_hf_model', False), + method_args=self.configs.preprocess_conf.get('method_args', {})) + + dataset_args = self.configs.dataset_conf.get('dataset', {}) + data_loader_args = self.configs.dataset_conf.get('dataLoader', {}) + if is_train: + self.train_dataset = MAClsDataset(data_list_path=self.configs.dataset_conf.train_list, + audio_featurizer=self.audio_featurizer, + aug_conf=self.data_augment_configs, + mode='train', + **dataset_args) + # 设置支持多卡训练 + train_sampler = RandomSampler(self.train_dataset) + if torch.cuda.device_count() > 1: + # 设置支持多卡训练 + train_sampler = DistributedSampler(dataset=self.train_dataset) + self.train_loader = DataLoader(dataset=self.train_dataset, + collate_fn=collate_fn, + sampler=train_sampler, + **data_loader_args) + # 获取测试数据 + data_loader_args.drop_last = False + dataset_args.max_duration = self.configs.dataset_conf.eval_conf.max_duration + data_loader_args.batch_size = self.configs.dataset_conf.eval_conf.batch_size + self.test_dataset = MAClsDataset(data_list_path=self.configs.dataset_conf.test_list, + audio_featurizer=self.audio_featurizer, + mode='eval', + **dataset_args) + self.test_loader = DataLoader(dataset=self.test_dataset, + collate_fn=collate_fn, + shuffle=False, + **data_loader_args) + + def extract_features(self, save_dir='dataset/features', max_duration=100): + """ 提取特征保存文件 + + :param save_dir: 保存路径 + :param max_duration: 提取特征的最大时长,避免过长显存不足,单位秒 + """ + self.audio_featurizer = AudioFeaturizer(feature_method=self.configs.preprocess_conf.feature_method, + use_hf_model=self.configs.preprocess_conf.get('use_hf_model', False), + method_args=self.configs.preprocess_conf.get('method_args', {})) + dataset_args = self.configs.dataset_conf.get('dataset', {}) + dataset_args.max_duration = max_duration + data_loader_args = self.configs.dataset_conf.get('dataLoader', {}) + data_loader_args.drop_last = False + for data_list in [self.configs.dataset_conf.train_list, self.configs.dataset_conf.test_list]: + test_dataset = MAClsDataset(data_list_path=data_list, + audio_featurizer=self.audio_featurizer, + mode='extract_feature', + **dataset_args) + test_loader = DataLoader(dataset=test_dataset, + collate_fn=collate_fn, + shuffle=False, + **data_loader_args) + save_data_list = data_list.replace('.txt', '_features.txt') + with open(save_data_list, 'w', encoding='utf-8') as f: + for features, labels, input_lens in tqdm(test_loader): + for i in range(len(features)): + feature, label, input_len = features[i], labels[i], input_lens[i] + feature = feature.numpy()[:input_len] + label = int(label) + save_path = os.path.join(save_dir, str(label), + f'{str(uuid.uuid4())}.npy').replace('\\', '/') + os.makedirs(os.path.dirname(save_path), exist_ok=True) + np.save(save_path, feature) + f.write(f'{save_path}\t{label}\n') + logger.info(f'{data_list}列表中的数据已提取特征完成,新列表为:{save_data_list}') + + def __setup_model(self, input_size, is_train=False): + """ 获取模型 + + :param input_size: 模型输入特征大小 + :param is_train: 是否获取训练模型 + """ + # 自动获取列表数量 + if self.configs.model_conf.model_args.get('num_class', None) is None: + self.configs.model_conf.model_args.num_class = len(self.class_labels) + # 获取模型 + self.model = build_model(input_size=input_size, configs=self.configs) + self.model.to(self.device) + if self.log_level == "DEBUG" or self.log_level == "INFO": + # 打印模型信息,98是长度,这个取决于输入的音频长度 + summary(self.model, input_size=(1, 98, input_size)) + # 使用Pytorch2.0的编译器 + if self.configs.train_conf.use_compile and torch.__version__ >= "2" and platform.system().lower() == 'windows': + self.model = torch.compile(self.model, mode="reduce-overhead") + # print(self.model) + # 获取损失函数 + label_smoothing = self.configs.train_conf.get('label_smoothing', 0.0) + self.loss = torch.nn.CrossEntropyLoss(label_smoothing=label_smoothing) + if is_train: + if self.configs.train_conf.enable_amp: + self.amp_scaler = torch.GradScaler(init_scale=1024) + # 获取优化方法 + self.optimizer = build_optimizer(params=self.model.parameters(), configs=self.configs) + # 学习率衰减函数 + self.scheduler = build_lr_scheduler(optimizer=self.optimizer, step_per_epoch=len(self.train_loader), + configs=self.configs) + + def __train_epoch(self, epoch_id, local_rank, writer, nranks=0): + """训练一个epoch + + :param epoch_id: 当前epoch + :param local_rank: 当前显卡id + :param writer: VisualDL对象 + :param nranks: 所使用显卡的数量 + """ + train_times, accuracies, loss_sum = [], [], [] + start = time.time() + for batch_id, (features, label, input_len) in enumerate(self.train_loader): + if self.stop_train: break + if nranks > 1: + features = features.to(local_rank) + label = label.to(local_rank).long() + else: + features = features.to(self.device) + label = label.to(self.device).long() + # 执行模型计算,是否开启自动混合精度 + with torch.autocast('cuda', enabled=self.configs.train_conf.enable_amp): + output = self.model(features) + # 计算损失值 + los = self.loss(output, label) + # 是否开启自动混合精度 + if self.configs.train_conf.enable_amp: + # loss缩放,乘以系数loss_scaling + scaled = self.amp_scaler.scale(los) + scaled.backward() + else: + los.backward() + # 是否开启自动混合精度 + if self.configs.train_conf.enable_amp: + self.amp_scaler.unscale_(self.optimizer) + self.amp_scaler.step(self.optimizer) + self.amp_scaler.update() + else: + self.optimizer.step() + self.optimizer.zero_grad() + + # 计算准确率 + acc = accuracy(output, label) + accuracies.append(acc) + loss_sum.append(los.data.cpu().numpy()) + train_times.append((time.time() - start) * 1000) + self.train_step += 1 + + # 多卡训练只使用一个进程打印 + if batch_id % self.configs.train_conf.log_interval == 0 and local_rank == 0: + batch_id = batch_id + 1 + # 计算每秒训练数据量 + train_speed = self.configs.dataset_conf.dataLoader.batch_size / ( + sum(train_times) / len(train_times) / 1000) + # 计算剩余时间 + self.train_eta_sec = (sum(train_times) / len(train_times)) * (self.max_step - self.train_step) / 1000 + eta_str = str(timedelta(seconds=int(self.train_eta_sec))) + self.train_loss = sum(loss_sum) / len(loss_sum) + self.train_acc = sum(accuracies) / len(accuracies) + logger.info(f'Train epoch: [{epoch_id}/{self.configs.train_conf.max_epoch}], ' + f'batch: [{batch_id}/{len(self.train_loader)}], ' + f'loss: {self.train_loss:.5f}, accuracy: {self.train_acc:.5f}, ' + f'learning rate: {self.scheduler.get_last_lr()[0]:>.8f}, ' + f'speed: {train_speed:.2f} data/sec, eta: {eta_str}') + writer.add_scalar('Train/Loss', self.train_loss, self.train_log_step) + writer.add_scalar('Train/Accuracy', self.train_acc, self.train_log_step) + # 记录学习率 + writer.add_scalar('Train/lr', self.scheduler.get_last_lr()[0], self.train_log_step) + train_times, accuracies, loss_sum = [], [], [] + self.train_log_step += 1 + start = time.time() + self.scheduler.step() + + def train(self, + save_model_path='models/', + log_dir='log/', + max_epoch=None, + resume_model=None, + pretrained_model=None): + """ + 训练模型 + :param save_model_path: 模型保存的路径 + :param log_dir: 保存VisualDL日志文件的路径 + :param max_epoch: 最大训练轮数,对应配置文件中的train_conf.max_epoch + :param resume_model: 恢复训练,当为None则不使用预训练模型 + :param pretrained_model: 预训练模型的路径,当为None则不使用预训练模型 + """ + # 获取有多少张显卡训练 + nranks = torch.cuda.device_count() + local_rank = 0 + writer = None + if local_rank == 0: + # 日志记录器 + writer = LogWriter(logdir=log_dir) + + if nranks > 1 and self.use_gpu: + # 初始化NCCL环境 + dist.init_process_group(backend='nccl') + local_rank = int(os.environ["LOCAL_RANK"]) + + # 获取数据 + self.__setup_dataloader(is_train=True) + # 获取模型 + self.__setup_model(input_size=self.audio_featurizer.feature_dim, is_train=True) + # 加载预训练模型 + self.model = load_pretrained(model=self.model, pretrained_model=pretrained_model, use_gpu=self.use_gpu) + # 加载恢复模型 + self.model, self.optimizer, self.amp_scaler, self.scheduler, last_epoch, best_acc = \ + load_checkpoint(configs=self.configs, model=self.model, optimizer=self.optimizer, + amp_scaler=self.amp_scaler, scheduler=self.scheduler, step_epoch=len(self.train_loader), + save_model_path=save_model_path, resume_model=resume_model) + + # 支持多卡训练 + if nranks > 1 and self.use_gpu: + self.model.to(local_rank) + self.model = torch.nn.parallel.DistributedDataParallel(self.model, device_ids=[local_rank]) + logger.info('训练数据:{}'.format(len(self.train_dataset))) + + self.train_loss, self.train_acc = None, None + self.eval_loss, self.eval_acc = None, None + self.test_log_step, self.train_log_step = 0, 0 + if local_rank == 0: + writer.add_scalar('Train/lr', self.scheduler.get_last_lr()[0], last_epoch) + if max_epoch is not None: + self.configs.train_conf.max_epoch = max_epoch + # 最大步数 + self.max_step = len(self.train_loader) * self.configs.train_conf.max_epoch + self.train_step = max(last_epoch, 0) * len(self.train_loader) + # 开始训练 + for epoch_id in range(last_epoch, self.configs.train_conf.max_epoch): + if self.stop_train: break + epoch_id += 1 + start_epoch = time.time() + # 训练一个epoch + self.__train_epoch(epoch_id=epoch_id, local_rank=local_rank, writer=writer, nranks=nranks) + # 多卡训练只使用一个进程执行评估和保存模型 + if local_rank == 0: + if self.stop_eval: continue + logger.info('=' * 70) + self.eval_loss, self.eval_acc = self.evaluate() + logger.info('Test epoch: {}, time/epoch: {}, loss: {:.5f}, accuracy: {:.5f}'.format( + epoch_id, str(timedelta(seconds=(time.time() - start_epoch))), self.eval_loss, self.eval_acc)) + logger.info('=' * 70) + writer.add_scalar('Test/Accuracy', self.eval_acc, self.test_log_step) + writer.add_scalar('Test/Loss', self.eval_loss, self.test_log_step) + self.test_log_step += 1 + self.model.train() + # # 保存最优模型 + if self.eval_acc >= best_acc: + best_acc = self.eval_acc + save_checkpoint(configs=self.configs, model=self.model, optimizer=self.optimizer, + amp_scaler=self.amp_scaler, save_model_path=save_model_path, epoch_id=epoch_id, + accuracy=self.eval_acc, best_model=True) + # 保存模型 + save_checkpoint(configs=self.configs, model=self.model, optimizer=self.optimizer, + amp_scaler=self.amp_scaler, save_model_path=save_model_path, epoch_id=epoch_id, + accuracy=self.eval_acc) + + def evaluate(self, resume_model=None, save_matrix_path=None): + """ + 评估模型 + :param resume_model: 所使用的模型 + :param save_matrix_path: 保存混合矩阵的路径 + :return: 评估结果 + """ + if self.test_loader is None: + self.__setup_dataloader() + if self.model is None: + self.__setup_model(input_size=self.audio_featurizer.feature_dim) + if resume_model is not None: + if os.path.isdir(resume_model): + resume_model = os.path.join(resume_model, 'model.pth') + assert os.path.exists(resume_model), f"{resume_model} 模型不存在!" + model_state_dict = torch.load(resume_model, weights_only=False) + self.model.load_state_dict(model_state_dict) + logger.info(f'成功加载模型:{resume_model}') + self.model.eval() + if isinstance(self.model, torch.nn.parallel.DistributedDataParallel): + eval_model = self.model.module + else: + eval_model = self.model + + accuracies, losses, preds, labels = [], [], [], [] + with torch.no_grad(): + for batch_id, (features, label, input_lens) in enumerate(tqdm(self.test_loader, desc='执行评估')): + if self.stop_eval: break + features = features.to(self.device) + label = label.to(self.device).long() + output = eval_model(features) + los = self.loss(output, label) + # 计算准确率 + acc = accuracy(output, label) + accuracies.append(acc) + # 模型预测标签 + label = label.data.cpu().numpy() + output = output.data.cpu().numpy() + pred = np.argmax(output, axis=1) + preds.extend(pred.tolist()) + # 真实标签 + labels.extend(label.tolist()) + losses.append(los.data.cpu().numpy()) + loss = float(sum(losses) / len(losses)) if len(losses) > 0 else -1 + acc = float(sum(accuracies) / len(accuracies)) if len(accuracies) > 0 else -1 + # 保存混合矩阵 + if save_matrix_path is not None: + try: + cm = confusion_matrix(labels, preds) + plot_confusion_matrix(cm=cm, save_path=os.path.join(save_matrix_path, f'{int(time.time())}.png'), + class_labels=self.class_labels) + except Exception as e: + logger.error(f'保存混淆矩阵失败:{e}') + self.model.train() + return loss, acc + + def export(self, save_model_path='models/', resume_model='models/EcapaTdnn_Fbank/best_model/'): + """ + 导出预测模型 + :param save_model_path: 模型保存的路径 + :param resume_model: 准备转换的模型路径 + :return: + """ + self.__setup_model(input_size=self.audio_featurizer.feature_dim) + # 加载预训练模型 + if os.path.isdir(resume_model): + resume_model = os.path.join(resume_model, 'model.pth') + assert os.path.exists(resume_model), f"{resume_model} 模型不存在!" + model_state_dict = torch.load(resume_model) + self.model.load_state_dict(model_state_dict) + logger.info('成功恢复模型参数和优化方法参数:{}'.format(resume_model)) + self.model.eval() + # 获取静态模型 + infer_model = self.model.export() + infer_model_path = os.path.join(save_model_path, + f'{self.configs.use_model}_{self.configs.preprocess_conf.feature_method}', + 'inference.pth') + os.makedirs(os.path.dirname(infer_model_path), exist_ok=True) + torch.jit.save(infer_model, infer_model_path) + logger.info("预测模型已保存:{}".format(infer_model_path)) diff --git a/src/声源定位代码/audio-classification/macls/utils/__init__.py b/src/声源定位代码/audio-classification/macls/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/声源定位代码/audio-classification/macls/utils/checkpoint.py b/src/声源定位代码/audio-classification/macls/utils/checkpoint.py new file mode 100644 index 0000000..c076929 --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/utils/checkpoint.py @@ -0,0 +1,162 @@ +import json +import os +import shutil + +import torch +from loguru import logger +from macls import __version__ + + +def load_pretrained(model, pretrained_model, use_gpu=True): + """加载预训练模型 + + :param model: 使用的模型 + :param pretrained_model: 预训练模型路径 + :param use_gpu: 模型是否使用GPU + :return: 加载的模型 + """ + # 加载预训练模型 + if pretrained_model is None: return model + if os.path.isdir(pretrained_model): + pretrained_model = os.path.join(pretrained_model, 'model.pth') + assert os.path.exists(pretrained_model), f"{pretrained_model} 模型不存在!" + if isinstance(model, torch.nn.parallel.DistributedDataParallel): + model_dict = model.module.state_dict() + else: + model_dict = model.state_dict() + if torch.cuda.is_available() and use_gpu: + model_state_dict = torch.load(pretrained_model, weights_only=False) + else: + model_state_dict = torch.load(pretrained_model, weights_only=False, map_location='cpu') + # 过滤不存在的参数 + for name, weight in model_dict.items(): + if name in model_state_dict.keys(): + if list(weight.shape) != list(model_state_dict[name].shape): + logger.warning(f'{name} not used, shape {list(model_state_dict[name].shape)} ' + f'unmatched with {list(weight.shape)} in model.') + model_state_dict.pop(name, None) + # 加载权重 + if isinstance(model, torch.nn.parallel.DistributedDataParallel): + missing_keys, unexpected_keys = model.module.load_state_dict(model_state_dict, strict=False) + else: + missing_keys, unexpected_keys = model.load_state_dict(model_state_dict, strict=False) + if len(unexpected_keys) > 0: + logger.warning('Unexpected key(s) in state_dict: {}. ' + .format(', '.join('"{}"'.format(k) for k in unexpected_keys))) + if len(missing_keys) > 0: + logger.warning('Missing key(s) in state_dict: {}. ' + .format(', '.join('"{}"'.format(k) for k in missing_keys))) + logger.info('成功加载预训练模型:{}'.format(pretrained_model)) + return model + + +def load_checkpoint(configs, model, optimizer, amp_scaler, scheduler, + step_epoch, save_model_path, resume_model): + """加载模型 + + :param configs: 配置信息 + :param model: 使用的模型 + :param optimizer: 使用的优化方法 + :param amp_scaler: 使用的自动混合精度 + :param scheduler: 使用的学习率调整策略 + :param step_epoch: 每个epoch的step数量 + :param save_model_path: 模型保存路径 + :param resume_model: 恢复训练的模型路径 + """ + last_epoch1 = 0 + accuracy1 = 0. + + def load_model(model_path): + assert os.path.exists(os.path.join(model_path, 'model.pth')), "模型参数文件不存在!" + assert os.path.exists(os.path.join(model_path, 'optimizer.pth')), "优化方法参数文件不存在!" + state_dict = torch.load(os.path.join(model_path, 'model.pth'), weights_only=False) + if isinstance(model, torch.nn.parallel.DistributedDataParallel): + model.module.load_state_dict(state_dict) + else: + model.load_state_dict(state_dict) + optimizer.load_state_dict(torch.load(os.path.join(model_path, 'optimizer.pth'), weights_only=False)) + # 自动混合精度参数 + if amp_scaler is not None and os.path.exists(os.path.join(model_path, 'scaler.pth')): + amp_scaler.load_state_dict(torch.load(os.path.join(model_path, 'scaler.pth')), weights_only=False) + with open(os.path.join(model_path, 'model.state'), 'r', encoding='utf-8') as f: + json_data = json.load(f) + last_epoch = json_data['last_epoch'] + accuracy = json_data['accuracy'] + logger.info('成功恢复模型参数和优化方法参数:{}'.format(model_path)) + optimizer.step() + [scheduler.step() for _ in range(last_epoch * step_epoch)] + return last_epoch, accuracy + + # 获取最后一个保存的模型 + save_feature_method = configs.preprocess_conf.feature_method + if configs.preprocess_conf.get('use_hf_model', False): + save_feature_method = save_feature_method[:-1] if save_feature_method[-1] == '/' else save_feature_method + save_feature_method = os.path.basename(save_feature_method) + last_model_dir = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', + 'last_model') + if resume_model is not None or (os.path.exists(os.path.join(last_model_dir, 'model.pth')) + and os.path.exists(os.path.join(last_model_dir, 'optimizer.pth'))): + if resume_model is not None: + last_epoch1, accuracy1 = load_model(resume_model) + else: + try: + # 自动获取最新保存的模型 + last_epoch1, accuracy1 = load_model(last_model_dir) + except Exception as e: + logger.warning(f'尝试自动恢复最新模型失败,错误信息:{e}') + return model, optimizer, amp_scaler, scheduler, last_epoch1, accuracy1 + + +# 保存模型 +def save_checkpoint(configs, model, optimizer, amp_scaler, save_model_path, epoch_id, + accuracy=0., best_model=False): + """保存模型 + + :param configs: 配置信息 + :param model: 使用的模型 + :param optimizer: 使用的优化方法 + :param amp_scaler: 使用的自动混合精度 + :param save_model_path: 模型保存路径 + :param epoch_id: 当前epoch + :param accuracy: 当前准确率 + :param best_model: 是否为最佳模型 + """ + if isinstance(model, torch.nn.parallel.DistributedDataParallel): + state_dict = model.module.state_dict() + else: + state_dict = model.state_dict() + # 保存模型的路径 + save_feature_method = configs.preprocess_conf.feature_method + if configs.preprocess_conf.get('use_hf_model', False): + save_feature_method = save_feature_method[:-1] if save_feature_method[-1] == '/' else save_feature_method + save_feature_method = os.path.basename(save_feature_method) + if best_model: + model_path = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', 'best_model') + else: + model_path = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', 'epoch_{}'.format(epoch_id)) + os.makedirs(model_path, exist_ok=True) + # 保存模型参数 + torch.save(optimizer.state_dict(), os.path.join(model_path, 'optimizer.pth')) + torch.save(state_dict, os.path.join(model_path, 'model.pth')) + # 自动混合精度参数 + if amp_scaler is not None: + torch.save(amp_scaler.state_dict(), os.path.join(model_path, 'scaler.pth')) + with open(os.path.join(model_path, 'model.state'), 'w', encoding='utf-8') as f: + data = {"last_epoch": epoch_id, "accuracy": accuracy, "version": __version__, + "model": configs.model_conf.model, "feature_method": save_feature_method} + f.write(json.dumps(data, indent=4, ensure_ascii=False)) + if not best_model: + last_model_path = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', 'last_model') + shutil.rmtree(last_model_path, ignore_errors=True) + shutil.copytree(model_path, last_model_path) + # 删除旧的模型 + old_model_path = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', + 'epoch_{}'.format(epoch_id - 3)) + if os.path.exists(old_model_path): + shutil.rmtree(old_model_path) + logger.info('已保存模型:{}'.format(model_path)) diff --git a/src/声源定位代码/audio-classification/macls/utils/record.py b/src/声源定位代码/audio-classification/macls/utils/record.py new file mode 100644 index 0000000..db0a992 --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/utils/record.py @@ -0,0 +1,31 @@ +import os + +import soundcard +import soundfile + + +class RecordAudio: + def __init__(self, channels=1, sample_rate=16000): + # 录音参数 + self.channels = channels + self.sample_rate = sample_rate + + # 获取麦克风 + self.default_mic = soundcard.default_microphone() + + def record(self, record_seconds=3, save_path=None): + """录音 + + :param record_seconds: 录音时间,默认3秒 + :param save_path: 录音保存的路径,后缀名为wav + :return: 音频的numpy数据 + """ + print("开始录音......") + num_frames = int(record_seconds * self.sample_rate) + data = self.default_mic.record(samplerate=self.sample_rate, numframes=num_frames, channels=self.channels) + audio_data = data.squeeze() + print("录音已结束!") + if save_path is not None: + os.makedirs(os.path.dirname(save_path), exist_ok=True) + soundfile.write(save_path, data=data, samplerate=self.sample_rate) + return audio_data diff --git a/src/声源定位代码/audio-classification/macls/utils/utils.py b/src/声源定位代码/audio-classification/macls/utils/utils.py new file mode 100644 index 0000000..c05ecdf --- /dev/null +++ b/src/声源定位代码/audio-classification/macls/utils/utils.py @@ -0,0 +1,131 @@ +import distutils.util +import os + +import matplotlib.pyplot as plt +import numpy as np + +from loguru import logger + + +def print_arguments(args=None, configs=None, title=None): + if args: + logger.info("----------- 额外配置参数 -----------") + for arg, value in sorted(vars(args).items()): + logger.info("%s: %s" % (arg, value)) + logger.info("------------------------------------------------") + if configs: + title = title if title else "配置文件参数" + logger.info(f"----------- {title} -----------") + for arg, value in sorted(configs.items()): + if isinstance(value, dict): + logger.info(f"{arg}:") + for a, v in sorted(value.items()): + if isinstance(v, dict): + logger.info(f"\t{a}:") + for a1, v1 in sorted(v.items()): + logger.info("\t\t%s: %s" % (a1, v1)) + else: + logger.info("\t%s: %s" % (a, v)) + else: + logger.info("%s: %s" % (arg, value)) + logger.info("------------------------------------------------") + + +def add_arguments(argname, type, default, help, argparser, **kwargs): + type = distutils.util.strtobool if type == bool else type + argparser.add_argument("--" + argname, + default=default, + type=type, + help=help + ' 默认: %(default)s.', + **kwargs) + + +class Dict(dict): + __setattr__ = dict.__setitem__ + __getattr__ = dict.__getitem__ + + +def dict_to_object(dict_obj): + if not isinstance(dict_obj, dict): + return dict_obj + inst = Dict() + for k, v in dict_obj.items(): + inst[k] = dict_to_object(v) + return inst + + +def plot_confusion_matrix(cm, save_path, class_labels, show=False): + """ + 绘制混淆矩阵 + @param cm: 混淆矩阵, 一个二维数组,表示预测结果与真实结果的混淆情况。 + @param save_path: 保存路径, 字符串,指定混淆矩阵图像的保存位置。 + @param class_labels: 类别名称, 一个列表,包含各个类别的名称。 + @param show: 是否显示图像, 布尔值,控制是否在绘图窗口显示混淆矩阵图像。 + """ + # 检测类别名称是否包含中文,是则设置相应字体 + s = ''.join(class_labels) + is_ascii = all(ord(c) < 128 for c in s) + if not is_ascii: + plt.rcParams['font.sans-serif'] = ['SimHei'] + plt.rcParams['axes.unicode_minus'] = False + + # 初始化绘图参数并绘制混淆矩阵 + plt.figure(figsize=(12, 8), dpi=100) + np.set_printoptions(precision=2) + # 在混淆矩阵中绘制每个格子的概率值 + ind_array = np.arange(len(class_labels)) + x, y = np.meshgrid(ind_array, ind_array) + for x_val, y_val in zip(x.flatten(), y.flatten()): + c = cm[y_val][x_val] / (np.sum(cm[:, x_val]) + 1e-6) + # 忽略概率值太小的格子 + if c < 1e-4: continue + plt.text(x_val, y_val, "%0.2f" % (c,), color='red', fontsize=15, va='center', ha='center') + m = np.sum(cm, axis=0) + 1e-6 + plt.imshow(cm / m, interpolation='nearest', cmap=plt.cm.binary) + plt.title('Confusion Matrix' if is_ascii else '混合矩阵') + plt.colorbar() + # 设置类别标签 + xlocations = np.array(range(len(class_labels))) + plt.xticks(xlocations, class_labels, rotation=90) + plt.yticks(xlocations, class_labels) + plt.ylabel('Actual label' if is_ascii else '实际标签') + plt.xlabel('Predict label' if is_ascii else '预测标签') + + # 调整刻度标记位置,提高可视化效果 + tick_marks = np.array(range(len(class_labels))) + 0.5 + plt.gca().set_xticks(tick_marks, minor=True) + plt.gca().set_yticks(tick_marks, minor=True) + plt.gca().xaxis.set_ticks_position('none') + plt.gca().yaxis.set_ticks_position('none') + plt.grid(True, which='minor', linestyle='-') + plt.gcf().subplots_adjust(bottom=0.15) + # 保存图片 + os.makedirs(os.path.dirname(save_path), exist_ok=True) + plt.savefig(save_path, format='png') + if show: + # 显示图片 + plt.show() + + +# 根据a的类型,将b转换为相应的类型 +def convert_string_based_on_type(a, b): + if isinstance(a, int): + try: + b = int(b) + except ValueError: + logger.error("无法将字符串转换为整数") + elif isinstance(a, float): + try: + b = float(b) + except ValueError: + logger.error("无法将字符串转换为浮点数") + elif isinstance(a, str): + return b + elif isinstance(a, bool): + b = b.lower() == 'true' + else: + try: + b = eval(b) + except Exception as e: + logger.exception("无法将字符串转换为其他类型,将忽略该参数类型转换") + return b diff --git a/src/声源定位代码/audio-classification/record_audio.py b/src/声源定位代码/audio-classification/record_audio.py new file mode 100644 index 0000000..406808f --- /dev/null +++ b/src/声源定位代码/audio-classification/record_audio.py @@ -0,0 +1,14 @@ +import time + +from macls.utils.record import RecordAudio + +s = input('请输入你计划录音多少秒:') +record_seconds = int(s) +save_path = "dataset/save_audio/%s.wav" % str(int(time.time()*1000)) + +record_audio = RecordAudio() +input(f"按下回车键开机录音,录音{record_seconds}秒中:") +record_audio.record(record_seconds=record_seconds, + save_path=save_path) + +print('文件保存在:%s' % save_path) diff --git a/src/声源定位代码/audio-classification/requirements.txt b/src/声源定位代码/audio-classification/requirements.txt new file mode 100644 index 0000000..52c91bf --- /dev/null +++ b/src/声源定位代码/audio-classification/requirements.txt @@ -0,0 +1,17 @@ +numpy>=1.19.2 +scipy>=1.6.3 +librosa>=0.9.1 +soundfile>=0.12.1 +soundcard>=0.4.2 +resampy>=0.2.2 +numba>=0.53.0 +pydub~=0.25.1 +matplotlib>=3.5.2 +pillow>=10.3.0 +tqdm>=4.66.3 +visualdl==2.5.3 +pyyaml>=5.4.1 +scikit-learn>=1.0.2 +torchinfo>=1.7.2 +loguru>=0.7.2 +yeaudio>=0.0.7 diff --git a/src/声源定位代码/audio-classification/setup.py b/src/声源定位代码/audio-classification/setup.py new file mode 100644 index 0000000..7fc9e0b --- /dev/null +++ b/src/声源定位代码/audio-classification/setup.py @@ -0,0 +1,54 @@ +import shutil + +from setuptools import setup, find_packages + +import macls + +VERSION = macls.__version__ + +# 复制配置文件到项目目录下 +shutil.rmtree('./macls/configs/', ignore_errors=True) +shutil.copytree('./configs/', './macls/configs/') + + +def readme(): + with open('README.md', encoding='utf-8') as f: + content = f.read() + return content + + +def parse_requirements(): + with open('./requirements.txt', encoding="utf-8") as f: + requirements = f.readlines() + return requirements + + +if __name__ == "__main__": + setup( + name='macls', + packages=find_packages(), + package_data={'': ['configs/*']}, + author='yeyupiaoling', + version=VERSION, + install_requires=parse_requirements(), + description='Audio Classification toolkit on Pytorch', + long_description=readme(), + long_description_content_type='text/markdown', + url='https://github.com/yeyupiaoling/AudioClassification-Pytorch', + download_url='https://github.com/yeyupiaoling/AudioClassification-Pytorch.git', + keywords=['audio', 'pytorch'], + classifiers=[ + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Natural Language :: Chinese (Simplified)', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Utilities' + ], + license='Apache License 2.0', + ext_modules=[]) + shutil.rmtree('./macls/configs/', ignore_errors=True) diff --git a/src/声源定位代码/audio-classification/tools/download_language_data.sh b/src/声源定位代码/audio-classification/tools/download_language_data.sh new file mode 100644 index 0000000..d0fe5e6 --- /dev/null +++ b/src/声源定位代码/audio-classification/tools/download_language_data.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +download_dir=dataset/language + + +[ ! -d ${download_dir} ] && mkdir -p ${download_dir} + +if [ ! -f ${download_dir}/test.tar.gz ]; then + echo "准备下载测试集" + wget --no-check-certificate https://speech-lab-share-data.oss-cn-shanghai.aliyuncs.com/3D-Speaker/test.tar.gz -P ${download_dir} + md5=$(md5sum ${download_dir}/test.tar.gz | awk '{print $1}') + [ $md5 != "45972606dd10d3f7c1c31f27acdfbed7" ] && echo "Wrong md5sum of 3dspeaker test.tar.gz" && exit 1 +fi + +if [ ! -f ${download_dir}/train.tar.gz ]; then + echo "准备下载训练集" + wget --no-check-certificate https://speech-lab-share-data.oss-cn-shanghai.aliyuncs.com/3D-Speaker/train.tar.gz -P ${download_dir} + md5=$(md5sum ${download_dir}/train.tar.gz | awk '{print $1}') + [ $md5 != "c2cea55fd22a2b867d295fb35a2d3340" ] && echo "Wrong md5sum of 3dspeaker train.tar.gz" && exit 1 +fi + +echo "下载完成!" + +echo "准备解压" + +tar -zxvf ${download_dir}/train.tar.gz -C ${rawdata_dir}/ +tar -xzvf ${download_dir}/test.tar.gz -C ${rawdata_dir}/ + +echo "解压完成!" diff --git a/src/声源定位代码/audio-classification/train.py b/src/声源定位代码/audio-classification/train.py new file mode 100644 index 0000000..50f1cce --- /dev/null +++ b/src/声源定位代码/audio-classification/train.py @@ -0,0 +1,30 @@ +import argparse +import functools + +from macls.trainer import MAClsTrainer +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', '配置文件') +add_arg('data_augment_configs', str, 'configs/augmentation.yml', '数据增强配置文件') +add_arg("local_rank", int, 0, '多卡训练需要的参数') +add_arg("use_gpu", bool, True, '是否使用GPU训练') +add_arg('save_model_path', str, 'models/', '模型保存的路径') +add_arg('log_dir', str, 'log/', '保存VisualDL日志文件的路径') +add_arg('resume_model', str, None, '恢复训练,当为None则不使用预训练模型') +add_arg('pretrained_model', str, None, '预训练模型的路径,当为None则不使用预训练模型') +add_arg('overwrites', str, None, '覆盖配置文件中的参数,比如"train_conf.max_epoch=100",多个用逗号隔开') +args = parser.parse_args() +print_arguments(args=args) + +# 获取训练器 +trainer = MAClsTrainer(configs=args.configs, + use_gpu=args.use_gpu, + data_augment_configs=args.data_augment_configs, + overwrites=args.overwrites) + +trainer.train(save_model_path=args.save_model_path, + log_dir=args.log_dir, + resume_model=args.resume_model, + pretrained_model=args.pretrained_model) diff --git a/src/声源定位代码/back-code/README.md b/src/声源定位代码/back-code/README.md new file mode 100644 index 0000000..be14557 --- /dev/null +++ b/src/声源定位代码/back-code/README.md @@ -0,0 +1,421 @@ +# 声源定位系统 - 开发板与PC端配合工作流程 + +## 📋 项目概述 + +本项目实现了一个基于麦克风阵列的声源定位系统,采用开发板(K210)与PC端服务器协同工作的架构。系统能够实时检测枪声并进行精确的声源定位,适用于战场感知、安防监控等场景。 + +### 🎯 系统特点 + +- **高精度定位**:基于TDOA算法的麦克风阵列定位 +- **智能识别**:PC端强大的枪声识别算法 +- **实时响应**:定位与识别并行处理 +- **可靠通信**:WiFi网络下的稳定数据传输 +- **可视化界面**:实时显示定位结果和系统状态 + +## 🏗️ 系统架构 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 开发板端 (K210) │ +├─────────────────────────────────────────────────────────────┤ +│ 硬件层: │ +│ • 麦克风阵列 (4通道) │ +│ • WiFi模块 (ESP8285) │ +│ • LED指示灯、蜂鸣器 │ +├─────────────────────────────────────────────────────────────┤ +│ 软件层: │ +│ • 音频采集与预处理 │ +│ • 声源定位算法 (TDOA) │ +│ • 网络通信管理 │ +│ • 系统状态监控 │ +└─────────────────────────────────────────────────────────────┘ + │ + ┌─────────┴─────────┐ + │ WiFi网络通信 │ + └─────────┬─────────┘ + │ +┌─────────────────────────────────────────────────────────────┐ +│ PC端服务器 │ +├─────────────────────────────────────────────────────────────┤ +│ 功能模块: │ +│ • 音频识别引擎 (枪声检测) │ +│ • 数据可视化界面 (matplotlib) │ +│ • Web API服务 (Flask) │ +│ • 数据存储与分析 │ +└─────────────────────────────────────────────────────────────┘ +``` + +## 🔧 硬件配置 + +### 开发板端硬件 +- **主控芯片**: K210 (双核64位RISC-V) +- **麦克风阵列**: 4通道I2S接口 +- **网络模块**: ESP8285 WiFi模块 +- **存储**: 16MB Flash + 8MB PSRAM +- **接口**: UART、I2S、GPIO、PWM + +### 引脚配置 +```python +# 麦克风阵列引脚 +mic_i2s_d0 = 23 # 数据通道0 +mic_i2s_d1 = 22 # 数据通道1 +mic_i2s_d2 = 21 # 数据通道2 +mic_i2s_d3 = 20 # 数据通道3 +mic_i2s_ws = 19 # 字选择 +mic_i2s_sclk = 18 # 时钟 + +# 其他硬件 +led_pin = 12 # LED指示灯 +buzzer_pin = 13 # 蜂鸣器 +wifi_en_pin = 8 # WiFi使能控制 +``` + +## 🌐 网络配置 + +### 开发板端网络设置 +```python +# WiFi连接配置 +wifi_ssid = "junzekeki" +wifi_password = "234567890l" + +# PC端服务器地址 +pc_ip = "192.168.1.100" +pc_port_audio = 12346 # 音频数据传输端口 +pc_port_cmd = 12347 # 指令控制端口 +pc_port_location = 12348 # 定位数据传输端口 +``` + +### PC端服务器配置 +```python +# 服务器监听配置 +host = "0.0.0.0" # 监听所有网络接口 +port_audio = 12346 # 音频数据接收端口 +port_cmd = 12347 # 指令发送端口 +port_location = 12348 # 定位数据接收端口 +``` + +## 🔄 详细工作流程 + +### 阶段1: 系统初始化 + +#### 开发板端初始化流程 +1. **硬件初始化** + - 初始化麦克风阵列I2S接口 + - 配置GPIO引脚(LED、蜂鸣器、WiFi使能) + - 初始化定时器和中断 + +2. **网络连接** + - 启用WiFi模块 + - 连接到指定WiFi网络 + - 建立3个Socket连接: + * `audio_socket`: 发送音频数据 + * `cmd_socket`: 接收PC端指令 + * `location_socket`: 发送定位数据 + +3. **系统启动** + - 启动性能监控模块 + - 启动心跳机制(30秒间隔) + - 初始化音频缓冲区和映射队列 + - 切换到录音模式 + +#### PC端初始化流程 +1. **服务器启动** + - 创建3个Socket服务器 + - 初始化音频识别模块 + - 启动matplotlib可视化界面 + - 初始化Flask Web API + +2. **等待连接** + - 监听开发板连接请求 + - 建立数据通信通道 + - 启动数据处理线程 + +### 阶段2: 录音监听模式 + +#### 开发板端工作流程 +1. **音频采集** + - 从麦克风阵列获取音频数据 + - 应用增益控制和噪声抑制 + - 将音频数据转换为标准格式 + +2. **数据传输** + - 将音频数据通过`audio_socket`发送给PC端 + - 更新性能统计(发送包数、数据量等) + +3. **指令监听** + - 非阻塞检查`cmd_socket`是否有PC端指令 + - 处理模式切换指令(START_LOCATION、STOP_LOCATION等) + +#### PC端工作流程 +1. **音频接收** + - 从`audio_socket`接收音频数据 + - 将数据添加到音频处理器缓冲区 + +2. **枪声识别** + - 当缓冲区达到处理阈值时进行识别 + - 使用预训练的音频分类模型 + - 计算枪声检测置信度 + +3. **模式切换** + - 当检测到枪声时,发送"START_LOCATION"指令 + - 切换到定位模式进行精确定位 + +### 阶段3: 定位识别模式(核心流程) + +#### 开发板端定位流程 +1. **音频缓冲** + - 持续录音并添加到定位音频缓冲区 + - 缓冲区大小:0.5秒音频数据 + - 当缓冲区满时触发处理 + +2. **声源定位** + - 对缓冲的音频数据进行预处理 + - 计算各麦克风间的时延差(TDOA) + - 使用最小二乘法求解声源位置 + - 应用卡尔曼滤波平滑定位结果 + +3. **映射存储** + - 将定位结果和对应音频存储为映射关系 + - 映射结构: + ```python + { + 'location_data': LocationData对象, + 'audio_data': 音频数据列表, + 'timestamp': 时间戳, + 'processed': False + } + ``` + +4. **识别请求** + - 构建识别请求:`RECOGNITION_REQUEST:timestamp:data_size` + - 通过`audio_socket`发送音频数据给PC端 + - 清空音频缓冲区,准备下一轮 + +#### PC端识别流程 +1. **请求处理** + - 检测识别请求标识 + - 解析请求头获取时间戳和数据大小 + - 接收指定大小的音频数据 + +2. **枪声识别** + - 将音频数据转换为numpy数组 + - 检查音频质量(信噪比、能量等) + - 使用音频分类模型进行识别 + - 计算识别置信度 + +3. **结果返回** + - 构建识别结果:`RECOGNITION_RESULT:timestamp:is_gunshot:confidence` + - 通过`cmd_socket`发送给开发板 + +### 阶段4: 结果处理与输出 + +#### 开发板端结果处理 +1. **结果接收** + - 从`cmd_socket`接收识别结果 + - 解析时间戳、枪声标识、置信度 + +2. **时间戳匹配** + - 在映射队列中查找时间戳最接近的定位数据 + - 匹配条件:时间差小于1秒 + - 标记匹配的映射为已处理 + +3. **条件输出** + - 如果识别结果为枪声: + * 提取对应的定位坐标 + * 通过`location_socket`发送给PC端 + * 记录日志和性能统计 + - 如果识别结果不是枪声: + * 忽略该定位数据 + * 继续监听下一轮 + +4. **资源清理** + - 移除已处理的映射关系 + - 清理过期的识别结果(超过5秒) + - 维护映射队列大小(最大20个) + +#### PC端数据处理 +1. **定位数据接收** + - 从`location_socket`接收定位数据 + - 解析坐标、强度、角度等信息 + +2. **数据后处理** + - 应用卡尔曼滤波平滑轨迹 + - 异常值检测和剔除 + - 数据平滑和插值 + +3. **可视化更新** + - 更新matplotlib实时图表 + - 显示枪声位置、轨迹、统计信息 + - 更新Web API数据接口 + +4. **数据存储** + - 将定位数据添加到历史记录 + - 更新性能统计和系统状态 + - 生成分析报告 + +### 阶段5: 模式切换与维护 + +#### 动态模式切换 +1. **录音→定位模式** + - 触发条件:PC端检测到枪声 + - 切换指令:`START_LOCATION` + - 开发板响应:重置定位缓冲区,开始定位流程 + +2. **定位→录音模式** + - 触发条件:PC端发送停止指令或超时 + - 切换指令:`STOP_LOCATION` + - 开发板响应:清理定位资源,回到录音模式 + +#### 系统维护 +1. **心跳机制** + - 开发板每30秒发送心跳包 + - 包含系统状态、内存使用、错误统计 + - PC端监控连接状态和系统健康 + +2. **错误恢复** + - 网络断开自动重连 + - 硬件故障检测和恢复 + - 异常状态处理和日志记录 + +3. **性能监控** + - 实时监控CPU、内存使用率 + - 统计数据传输量和延迟 + - 生成性能报告和告警 + +## 📊 数据格式规范 + +### 音频数据格式 +```python +# 音频参数 +sample_rate = 16000 # 采样率 16kHz +channels = 1 # 单声道 +format = "int16" # 16位整数格式 +chunk_size = 1024 # 数据块大小 +``` + +### 定位数据格式 +```python +# 定位数据结构 +LocationData { + x: float, # X坐标 (米) + y: float, # Y坐标 (米) + strength: float, # 信号强度 (0-1) + angle: float, # 方位角 (度) + timestamp: float, # 时间戳 + confidence: float, # 置信度 (0-1) + quality: float, # 定位质量 (0-1) + noise_level: float # 噪声水平 (0-1) +} +``` + +### 通信协议格式 +```python +# 识别请求 +"RECOGNITION_REQUEST:timestamp:data_size" + +# 识别结果 +"RECOGNITION_RESULT:timestamp:is_gunshot:confidence" + +# 定位数据 +"x,y,strength,angle" + +# 心跳数据 +"HEARTBEAT:timestamp:mode:status:memory" +``` + +## 🎯 系统优势 + +### 1. 准确性优势 +- **分离式处理**:开发板专注定位,PC端专注识别 +- **时间戳匹配**:精确关联定位数据和识别结果 +- **多重验证**:音频质量检查、置信度阈值、异常值检测 + +### 2. 实时性优势 +- **并行处理**:定位和识别同时进行 +- **非阻塞通信**:Socket超时机制,避免阻塞 +- **缓冲优化**:合理的缓冲区大小和清理策略 + +### 3. 可靠性优势 +- **自动重连**:网络断开自动恢复 +- **错误处理**:完善的异常捕获和恢复机制 +- **状态监控**:实时监控系统健康状态 + +### 4. 扩展性优势 +- **模块化设计**:各功能模块独立,易于升级 +- **配置灵活**:支持动态配置参数 +- **接口标准化**:标准化的数据格式和通信协议 + +## 🔍 应用场景 + +### 1. 战场感知 +- 实时检测枪声位置 +- 威胁源定位和追踪 +- 战场态势分析 + +### 2. 安防监控 +- 枪声检测和报警 +- 安全区域监控 +- 事件记录和分析 + +### 3. 训练模拟 +- 射击训练评估 +- 战术演练分析 +- 性能数据统计 + +### 4. 城市安全 +- 公共安全监控 +- 应急响应支持 +- 犯罪预防分析 + +## 📈 性能指标 + +### 定位精度 +- **角度精度**: ±2° (在10米距离) +- **距离精度**: ±0.5米 (在10米距离) +- **响应时间**: <100ms + +### 识别性能 +- **检测准确率**: >95% +- **误报率**: <2% +- **漏报率**: <3% + +### 系统性能 +- **最大检测距离**: 50米 +- **工作温度**: -20°C ~ +70°C +- **连续工作时间**: >24小时 +- **网络延迟**: <50ms + +## 🛠️ 部署说明 + +### 开发板端部署 +1. 将代码烧录到K210开发板 +2. 配置WiFi网络参数 +3. 连接麦克风阵列硬件 +4. 启动系统并检查连接状态 + +### PC端部署 +1. 安装Python依赖包 +2. 配置服务器网络参数 +3. 启动音频识别服务 +4. 运行可视化界面 + +### 网络配置 +1. 确保开发板和PC在同一WiFi网络 +2. 检查防火墙设置 +3. 验证端口连通性 +4. 测试数据传输 + +## 📝 注意事项 + +1. **硬件连接**:确保麦克风阵列正确连接,检查I2S信号质量 +2. **网络稳定**:使用稳定的WiFi网络,避免频繁断开 +3. **电源供应**:开发板需要稳定的5V电源供应 +4. **环境噪声**:避免强电磁干扰和机械振动 +5. **定期维护**:定期检查系统状态和清理日志文件 + +--- + +**版本**: 3.0.0 +**作者**: 声源定位系统开发团队 +**日期**: 2025年 +**许可证**: MIT License \ No newline at end of file diff --git a/src/声源定位代码/back-code/development_board.py b/src/声源定位代码/back-code/development_board.py new file mode 100644 index 0000000..06af0f9 --- /dev/null +++ b/src/声源定位代码/back-code/development_board.py @@ -0,0 +1,3309 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +开发板端主程序 - K210专用版本 +功能: +1. 开机后进入录音状态,持续录音并发送给PC端 +2. 接收PC端的指令,当识别到枪声时切换到声源定位模式 +3. 在定位模式下,实时发送声源定位数据给PC端 +4. 支持WiFi连接管理、音频采集、声源定位等功能 +5. 完善的异常处理、错误恢复和性能监控机制 + +作者: 声源定位系统开发团队 +版本: 3.0.0 +日期: 2025 +""" + +import gc +import math +import time +import socket +import network +import json +import os +import sys +import traceback +from machine import UART, Timer, PWM +from fpioa_manager import fm +from Maix import GPIO, MIC_ARRAY as mic +from board import board_info +from typing import Optional, Dict, Any, List, Tuple, Union, Callable +from dataclasses import dataclass, field +from enum import Enum, auto +import _thread +import utime +import numpy as np + +# ========== 常量定义 ========== +class Constants: + """系统常量定义""" + # 系统配置 + MAX_RETRY_ATTEMPTS = 5 + DEFAULT_TIMEOUT = 30.0 + HEARTBEAT_INTERVAL = 30.0 + BUFFER_SIZE = 4096 + MAX_LOG_SIZE = 1024 * 1024 # 1MB + + # 音频配置 + DEFAULT_SAMPLE_RATE = 16000 + DEFAULT_CHANNELS = 1 + DEFAULT_CHUNK_SIZE = 1024 + DEFAULT_RECORD_DURATION = 3.0 + + # 网络配置 + DEFAULT_WIFI_SSID = "junzekeki" + DEFAULT_WIFI_PASSWORD = "234567890l" + DEFAULT_PC_IP = "192.168.1.100" + DEFAULT_PC_PORT_AUDIO = 12346 + DEFAULT_PC_PORT_CMD = 12347 + DEFAULT_PC_PORT_LOCATION = 12348 + + # 硬件配置 + K210_MAX_PINS = 48 + DEFAULT_MIC_I2S_D0 = 23 + DEFAULT_MIC_I2S_D1 = 22 + DEFAULT_MIC_I2S_D2 = 21 + DEFAULT_MIC_I2S_D3 = 20 + DEFAULT_MIC_I2S_WS = 19 + DEFAULT_MIC_I2S_SCLK = 18 + DEFAULT_SK9822_DAT = 24 + DEFAULT_SK9822_CLK = 25 + DEFAULT_WIFI_EN_PIN = 8 + + # 错误码 + ERROR_SUCCESS = 0 + ERROR_WIFI_CONNECTION_FAILED = 1001 + ERROR_SOCKET_CONNECTION_FAILED = 1002 + ERROR_AUDIO_INIT_FAILED = 1003 + ERROR_MIC_ARRAY_INIT_FAILED = 1004 + ERROR_CONFIG_LOAD_FAILED = 1005 + ERROR_MEMORY_INSUFFICIENT = 1006 + ERROR_HARDWARE_FAULT = 1007 + +# ========== 枚举定义 ========== +class SystemMode(Enum): + """系统运行模式枚举""" + INITIALIZING = auto() # 初始化模式 + RECORDING = auto() # 录音模式 + LOCATING = auto() # 定位模式 + ERROR = auto() # 错误模式 + SHUTDOWN = auto() # 关闭模式 + MAINTENANCE = auto() # 维护模式 + DIAGNOSTIC = auto() # 诊断模式 + +class ConnectionStatus(Enum): + """连接状态枚举""" + DISCONNECTED = auto() + CONNECTING = auto() + CONNECTED = auto() + ERROR = auto() + RECONNECTING = auto() + TIMEOUT = auto() + +class WiFiStatus(Enum): + """WiFi状态枚举""" + DISCONNECTED = auto() + CONNECTING = auto() + CONNECTED = auto() + ERROR = auto() + AUTH_FAILED = auto() + NO_AP_FOUND = auto() + +class AudioStatus(Enum): + """音频状态枚举""" + IDLE = auto() + RECORDING = auto() + PROCESSING = auto() + ERROR = auto() + BUFFER_FULL = auto() + BUFFER_EMPTY = auto() + +class ErrorLevel(Enum): + """错误级别枚举""" + DEBUG = auto() + INFO = auto() + WARNING = auto() + ERROR = auto() + CRITICAL = auto() + FATAL = auto() + +# ========== 异常类定义 ========== +class DevelopmentBoardError(Exception): + """开发板基础异常类""" + def __init__(self, message: str, error_code: int = Constants.ERROR_SUCCESS): + super().__init__(message) + self.error_code = error_code + self.timestamp = time.time() + +class WiFiConnectionError(DevelopmentBoardError): + """WiFi连接异常""" + def __init__(self, message: str, ssid: str = "", error_code: int = Constants.ERROR_WIFI_CONNECTION_FAILED): + super().__init__(message, error_code) + self.ssid = ssid + +class SocketConnectionError(DevelopmentBoardError): + """Socket连接异常""" + def __init__(self, message: str, host: str = "", port: int = 0, error_code: int = Constants.ERROR_SOCKET_CONNECTION_FAILED): + super().__init__(message, error_code) + self.host = host + self.port = port + +class AudioInitError(DevelopmentBoardError): + """音频初始化异常""" + def __init__(self, message: str, error_code: int = Constants.ERROR_AUDIO_INIT_FAILED): + super().__init__(message, error_code) + +class MicArrayInitError(DevelopmentBoardError): + """麦克风阵列初始化异常""" + def __init__(self, message: str, error_code: int = Constants.ERROR_MIC_ARRAY_INIT_FAILED): + super().__init__(message, error_code) + +class ConfigError(DevelopmentBoardError): + """配置错误异常""" + def __init__(self, message: str, config_file: str = "", error_code: int = Constants.ERROR_CONFIG_LOAD_FAILED): + super().__init__(message, error_code) + self.config_file = config_file + +class MemoryError(DevelopmentBoardError): + """内存不足异常""" + def __init__(self, message: str, required: int = 0, available: int = 0, error_code: int = Constants.ERROR_MEMORY_INSUFFICIENT): + super().__init__(message, error_code) + self.required = required + self.available = available + +class HardwareFaultError(DevelopmentBoardError): + """硬件故障异常""" + def __init__(self, message: str, component: str = "", error_code: int = Constants.ERROR_HARDWARE_FAULT): + super().__init__(message, error_code) + self.component = component + +# ========== 数据类定义 ========== +@dataclass +class LocationData: + """定位数据结构""" + x: float + y: float + strength: float + angle: float + timestamp: float + confidence: float = 1.0 + quality: float = 1.0 + noise_level: float = 0.0 + source_type: str = "unknown" + + def __post_init__(self): + """数据验证和规范化""" + try: + # 类型检查 + if not isinstance(self.x, (int, float)): + raise ValueError("X坐标必须是数值类型") + if not isinstance(self.y, (int, float)): + raise ValueError("Y坐标必须是数值类型") + if not isinstance(self.strength, (int, float)) or self.strength < 0: + raise ValueError("强度必须是非负数值") + if not isinstance(self.angle, (int, float)): + raise ValueError("角度必须是数值类型") + if not isinstance(self.confidence, (int, float)) or not (0 <= self.confidence <= 1): + raise ValueError("置信度必须在0-1范围内") + if not isinstance(self.quality, (int, float)) or not (0 <= self.quality <= 1): + raise ValueError("质量必须在0-1范围内") + if not isinstance(self.noise_level, (int, float)) or self.noise_level < 0: + raise ValueError("噪声水平必须是非负数值") + + # 角度规范化到0-360度 + self.angle = self.angle % 360 + + # 坐标范围检查 + if abs(self.x) > 1000 or abs(self.y) > 1000: + raise ValueError("坐标值超出合理范围") + + except Exception as e: + raise ValueError(f"定位数据验证失败: {e}") + + def to_dict(self) -> Dict[str, Any]: + """转换为字典格式""" + return { + 'x': self.x, + 'y': self.y, + 'strength': self.strength, + 'angle': self.angle, + 'timestamp': self.timestamp, + 'confidence': self.confidence, + 'quality': self.quality, + 'noise_level': self.noise_level, + 'source_type': self.source_type + } + + def to_json(self) -> str: + """转换为JSON字符串""" + return json.dumps(self.to_dict()) + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> 'LocationData': + """从字典创建实例""" + return cls(**data) + + @classmethod + def from_json(cls, json_str: str) -> 'LocationData': + """从JSON字符串创建实例""" + data = json.loads(json_str) + return cls.from_dict(data) + +@dataclass +class AudioConfig: + """音频配置""" + sample_rate: int = Constants.DEFAULT_SAMPLE_RATE + channels: int = Constants.DEFAULT_CHANNELS + chunk_size: int = Constants.DEFAULT_CHUNK_SIZE + record_duration: float = Constants.DEFAULT_RECORD_DURATION + format: str = "int16" + bit_depth: int = 16 + buffer_size: int = Constants.BUFFER_SIZE + gain: float = 1.0 + noise_reduction: bool = True + auto_gain_control: bool = True + + def validate(self) -> bool: + """验证配置有效性""" + try: + if self.sample_rate <= 0 or self.sample_rate > 48000: + raise ValueError("采样率必须在1-48000范围内") + if self.channels not in [1, 2, 4, 8]: + raise ValueError("声道数必须是1、2、4或8") + if self.chunk_size <= 0 or self.chunk_size > 8192: + raise ValueError("音频块大小必须在1-8192范围内") + if self.record_duration <= 0 or self.record_duration > 60: + raise ValueError("录音时长必须在1-60秒范围内") + if self.format not in ["int8", "int16", "int24", "int32", "float32"]: + raise ValueError("不支持的音频格式") + if self.bit_depth not in [8, 16, 24, 32]: + raise ValueError("位深度必须是8、16、24或32") + if self.buffer_size <= 0 or self.buffer_size > 65536: + raise ValueError("缓冲区大小必须在1-65536范围内") + if self.gain <= 0 or self.gain > 10: + raise ValueError("增益必须在0-10范围内") + return True + except Exception as e: + raise AudioInitError(f"音频配置验证失败: {e}") + + def to_dict(self) -> Dict[str, Any]: + """转换为字典格式""" + return { + 'sample_rate': self.sample_rate, + 'channels': self.channels, + 'chunk_size': self.chunk_size, + 'record_duration': self.record_duration, + 'format': self.format, + 'bit_depth': self.bit_depth, + 'buffer_size': self.buffer_size, + 'gain': self.gain, + 'noise_reduction': self.noise_reduction, + 'auto_gain_control': self.auto_gain_control + } + +@dataclass +class NetworkConfig: + """网络配置""" + wifi_ssid: str = Constants.DEFAULT_WIFI_SSID + wifi_password: str = Constants.DEFAULT_WIFI_PASSWORD + pc_ip: str = Constants.DEFAULT_PC_IP + pc_port_audio: int = Constants.DEFAULT_PC_PORT_AUDIO + pc_port_cmd: int = Constants.DEFAULT_PC_PORT_CMD + pc_port_location: int = Constants.DEFAULT_PC_PORT_LOCATION + connection_timeout: float = Constants.DEFAULT_TIMEOUT + reconnect_interval: float = 5.0 + max_reconnect_attempts: int = Constants.MAX_RETRY_ATTEMPTS + heartbeat_interval: float = Constants.HEARTBEAT_INTERVAL + keep_alive: bool = True + tcp_nodelay: bool = True + socket_timeout: float = 1.0 + + def validate(self) -> bool: + """验证配置有效性""" + try: + if not self.wifi_ssid or len(self.wifi_ssid) > 32: + raise ValueError("WiFi SSID不能为空且长度不能超过32字符") + if not self.wifi_password or len(self.wifi_password) > 64: + raise ValueError("WiFi密码不能为空且长度不能超过64字符") + if not self.pc_ip or not self._is_valid_ip(self.pc_ip): + raise ValueError("PC端IP地址格式无效") + if not (1024 <= self.pc_port_audio <= 65535): + raise ValueError("音频端口必须在1024-65535范围内") + if not (1024 <= self.pc_port_cmd <= 65535): + raise ValueError("指令端口必须在1024-65535范围内") + if not (1024 <= self.pc_port_location <= 65535): + raise ValueError("定位端口必须在1024-65535范围内") + if self.connection_timeout <= 0 or self.connection_timeout > 300: + raise ValueError("连接超时必须在1-300秒范围内") + if self.reconnect_interval <= 0 or self.reconnect_interval > 60: + raise ValueError("重连间隔必须在1-60秒范围内") + if self.max_reconnect_attempts <= 0 or self.max_reconnect_attempts > 100: + raise ValueError("最大重连次数必须在1-100范围内") + return True + except Exception as e: + raise WiFiConnectionError(f"网络配置验证失败: {e}") + + def _is_valid_ip(self, ip: str) -> bool: + """验证IP地址格式""" + try: + parts = ip.split('.') + if len(parts) != 4: + return False + for part in parts: + if not part.isdigit() or not (0 <= int(part) <= 255): + return False + return True + except: + return False + + def to_dict(self) -> Dict[str, Any]: + """转换为字典格式""" + return { + 'wifi_ssid': self.wifi_ssid, + 'wifi_password': self.wifi_password, + 'pc_ip': self.pc_ip, + 'pc_port_audio': self.pc_port_audio, + 'pc_port_cmd': self.pc_port_cmd, + 'pc_port_location': self.pc_port_location, + 'connection_timeout': self.connection_timeout, + 'reconnect_interval': self.reconnect_interval, + 'max_reconnect_attempts': self.max_reconnect_attempts, + 'heartbeat_interval': self.heartbeat_interval, + 'keep_alive': self.keep_alive, + 'tcp_nodelay': self.tcp_nodelay, + 'socket_timeout': self.socket_timeout + } + +@dataclass +class HardwareConfig: + """硬件配置""" + # 麦克风阵列引脚 + mic_i2s_d0: int = Constants.DEFAULT_MIC_I2S_D0 + mic_i2s_d1: int = Constants.DEFAULT_MIC_I2S_D1 + mic_i2s_d2: int = Constants.DEFAULT_MIC_I2S_D2 + mic_i2s_d3: int = Constants.DEFAULT_MIC_I2S_D3 + mic_i2s_ws: int = Constants.DEFAULT_MIC_I2S_WS + mic_i2s_sclk: int = Constants.DEFAULT_MIC_I2S_SCLK + sk9822_dat: int = Constants.DEFAULT_SK9822_DAT + sk9822_clk: int = Constants.DEFAULT_SK9822_CLK + + # WiFi控制引脚 + wifi_en_pin: int = Constants.DEFAULT_WIFI_EN_PIN + + # 其他硬件配置 + led_pin: int = 12 + buzzer_pin: int = 13 + button_pin: int = 14 + temperature_sensor_pin: int = 15 + + # 硬件参数 + mic_array_gain: float = 1.0 + led_brightness: int = 255 + buzzer_frequency: int = 1000 + temperature_threshold: float = 85.0 + + def validate(self) -> bool: + """验证配置有效性""" + try: + # 检查引脚范围 + valid_pins = list(range(0, Constants.K210_MAX_PINS)) + pin_configs = { + 'mic_i2s_d0': self.mic_i2s_d0, + 'mic_i2s_d1': self.mic_i2s_d1, + 'mic_i2s_d2': self.mic_i2s_d2, + 'mic_i2s_d3': self.mic_i2s_d3, + 'mic_i2s_ws': self.mic_i2s_ws, + 'mic_i2s_sclk': self.mic_i2s_sclk, + 'sk9822_dat': self.sk9822_dat, + 'sk9822_clk': self.sk9822_clk, + 'wifi_en_pin': self.wifi_en_pin, + 'led_pin': self.led_pin, + 'buzzer_pin': self.buzzer_pin, + 'button_pin': self.button_pin, + 'temperature_sensor_pin': self.temperature_sensor_pin + } + + for pin_name, pin_value in pin_configs.items(): + if pin_value not in valid_pins: + raise ValueError(f"引脚 {pin_name}={pin_value} 超出有效范围(0-{Constants.K210_MAX_PINS-1})") + + # 检查引脚冲突 + pin_values = list(pin_configs.values()) + if len(pin_values) != len(set(pin_values)): + raise ValueError("存在引脚冲突,请检查配置") + + # 检查其他参数 + if self.mic_array_gain <= 0 or self.mic_array_gain > 10: + raise ValueError("麦克风阵列增益必须在0-10范围内") + if not (0 <= self.led_brightness <= 255): + raise ValueError("LED亮度必须在0-255范围内") + if self.buzzer_frequency <= 0 or self.buzzer_frequency > 20000: + raise ValueError("蜂鸣器频率必须在1-20000Hz范围内") + if self.temperature_threshold <= 0 or self.temperature_threshold > 150: + raise ValueError("温度阈值必须在0-150°C范围内") + + return True + except Exception as e: + raise HardwareFaultError(f"硬件配置验证失败: {e}") + + def to_dict(self) -> Dict[str, Any]: + """转换为字典格式""" + return { + 'mic_i2s_d0': self.mic_i2s_d0, + 'mic_i2s_d1': self.mic_i2s_d1, + 'mic_i2s_d2': self.mic_i2s_d2, + 'mic_i2s_d3': self.mic_i2s_d3, + 'mic_i2s_ws': self.mic_i2s_ws, + 'mic_i2s_sclk': self.mic_i2s_sclk, + 'sk9822_dat': self.sk9822_dat, + 'sk9822_clk': self.sk9822_clk, + 'wifi_en_pin': self.wifi_en_pin, + 'led_pin': self.led_pin, + 'buzzer_pin': self.buzzer_pin, + 'button_pin': self.button_pin, + 'temperature_sensor_pin': self.temperature_sensor_pin, + 'mic_array_gain': self.mic_array_gain, + 'led_brightness': self.led_brightness, + 'buzzer_frequency': self.buzzer_frequency, + 'temperature_threshold': self.temperature_threshold + } + +@dataclass +class SystemConfig: + """系统配置""" + log_level: str = "INFO" + heartbeat_interval: float = Constants.HEARTBEAT_INTERVAL + location_update_interval: float = 0.1 + audio_buffer_size: int = Constants.BUFFER_SIZE + max_log_files: int = 5 + log_rotation_size: int = Constants.MAX_LOG_SIZE + enable_performance_monitor: bool = True + enable_auto_recovery: bool = True + enable_hardware_monitor: bool = True + enable_network_monitor: bool = True + enable_audio_monitor: bool = True + enable_error_reporting: bool = True + enable_debug_mode: bool = False + enable_maintenance_mode: bool = False + + def validate(self) -> bool: + """验证配置有效性""" + try: + valid_log_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] + if self.log_level not in valid_log_levels: + raise ValueError(f"日志级别必须是: {', '.join(valid_log_levels)}") + if self.heartbeat_interval <= 0 or self.heartbeat_interval > 300: + raise ValueError("心跳间隔必须在1-300秒范围内") + if self.location_update_interval <= 0 or self.location_update_interval > 1: + raise ValueError("定位更新间隔必须在0.001-1秒范围内") + if self.audio_buffer_size <= 0 or self.audio_buffer_size > 65536: + raise ValueError("音频缓冲区大小必须在1-65536范围内") + if self.max_log_files <= 0 or self.max_log_files > 20: + raise ValueError("最大日志文件数必须在1-20范围内") + if self.log_rotation_size <= 0 or self.log_rotation_size > 10 * 1024 * 1024: + raise ValueError("日志轮转大小必须在1-10MB范围内") + return True + except Exception as e: + raise ConfigError(f"系统配置验证失败: {e}") + + def to_dict(self) -> Dict[str, Any]: + """转换为字典格式""" + return { + 'log_level': self.log_level, + 'heartbeat_interval': self.heartbeat_interval, + 'location_update_interval': self.location_update_interval, + 'audio_buffer_size': self.audio_buffer_size, + 'max_log_files': self.max_log_files, + 'log_rotation_size': self.log_rotation_size, + 'enable_performance_monitor': self.enable_performance_monitor, + 'enable_auto_recovery': self.enable_auto_recovery, + 'enable_hardware_monitor': self.enable_hardware_monitor, + 'enable_network_monitor': self.enable_network_monitor, + 'enable_audio_monitor': self.enable_audio_monitor, + 'enable_error_reporting': self.enable_error_reporting, + 'enable_debug_mode': self.enable_debug_mode, + 'enable_maintenance_mode': self.enable_maintenance_mode + } + +# ========== 日志系统 ========== +class Logger: + """增强的日志系统,支持日志轮转、级别过滤和性能优化""" + + def __init__(self, name: str = "DevelopmentBoard", log_level: str = "INFO"): + self.name = name + self.log_level = log_level.upper() + self.log_dir = "/sd/logs" + self.log_file = f"{self.log_dir}/{name}.log" + self.error_log_file = f"{self.log_dir}/{name}_error.log" + self.max_file_size = Constants.MAX_LOG_SIZE + self.max_files = 5 + self.log_levels = { + "DEBUG": 0, + "INFO": 1, + "WARNING": 2, + "ERROR": 3, + "CRITICAL": 4, + "FATAL": 5 + } + self._ensure_log_dir() + self._check_log_rotation() + self._log_count = 0 + self._last_flush_time = time.time() + self._flush_interval = 5.0 # 5秒刷新一次 + + def _ensure_log_dir(self): + """确保日志目录存在""" + try: + if not os.path.exists(self.log_dir): + os.makedirs(self.log_dir) + except Exception as e: + print(f"创建日志目录失败: {e}") + + def _check_log_rotation(self): + """检查并执行日志轮转""" + try: + if os.path.exists(self.log_file): + file_size = os.path.getsize(self.log_file) + if file_size > self.max_file_size: + self._rotate_log_file(self.log_file) + + if os.path.exists(self.error_log_file): + file_size = os.path.getsize(self.error_log_file) + if file_size > self.max_file_size: + self._rotate_log_file(self.error_log_file) + except Exception as e: + print(f"日志轮转检查失败: {e}") + + def _rotate_log_file(self, log_file: str): + """轮转日志文件""" + try: + # 删除最老的日志文件 + for i in range(self.max_files - 1, 0, -1): + old_file = f"{log_file}.{i}" + new_file = f"{log_file}.{i + 1}" + if os.path.exists(old_file): + if i == self.max_files - 1: + os.remove(old_file) + else: + os.rename(old_file, new_file) + + # 重命名当前日志文件 + if os.path.exists(log_file): + os.rename(log_file, f"{log_file}.1") + except Exception as e: + print(f"日志轮转失败: {e}") + + def _get_timestamp(self) -> str: + """获取时间戳""" + return time.strftime("%Y-%m-%d %H:%M:%S") + + def _should_log(self, level: str) -> bool: + """检查是否应该记录该级别的日志""" + return self.log_levels.get(level.upper(), 0) >= self.log_levels.get(self.log_level, 0) + + def _write_log(self, level: str, message: str, error_log: bool = False): + """写入日志""" + if not self._should_log(level): + return + + try: + timestamp = self._get_timestamp() + log_entry = f"[{timestamp}] [{level}] [{self.name}] {message}" + + # 控制台输出 + print(log_entry) + + # 文件输出 + target_file = self.error_log_file if error_log else self.log_file + with open(target_file, "a", encoding="utf-8") as f: + f.write(log_entry + "\n") + + self._log_count += 1 + + # 定期刷新和检查轮转 + current_time = time.time() + if current_time - self._last_flush_time > self._flush_interval: + self._check_log_rotation() + self._last_flush_time = current_time + + except Exception as e: + print(f"写入日志失败: {e}") + + def debug(self, message: str): + """调试日志""" + self._write_log("DEBUG", message) + + def info(self, message: str): + """信息日志""" + self._write_log("INFO", message) + + def warning(self, message: str): + """警告日志""" + self._write_log("WARNING", message) + + def error(self, message: str): + """错误日志""" + self._write_log("ERROR", message, error_log=True) + + def critical(self, message: str): + """严重错误日志""" + self._write_log("CRITICAL", message, error_log=True) + + def fatal(self, message: str): + """致命错误日志""" + self._write_log("FATAL", message, error_log=True) + + def exception(self, message: str, exc_info: Exception = None): + """异常日志""" + if exc_info: + message = f"{message} - 异常: {str(exc_info)}" + self._write_log("ERROR", message, error_log=True) + + def performance(self, operation: str, duration: float, details: str = ""): + """性能日志""" + message = f"性能监控 - {operation}: {duration:.3f}s" + if details: + message += f" - {details}" + self._write_log("INFO", message) + + def get_log_stats(self) -> Dict[str, Any]: + """获取日志统计信息""" + try: + stats = { + 'log_count': self._log_count, + 'log_level': self.log_level, + 'log_file_size': 0, + 'error_log_file_size': 0 + } + + if os.path.exists(self.log_file): + stats['log_file_size'] = os.path.getsize(self.log_file) + if os.path.exists(self.error_log_file): + stats['error_log_file_size'] = os.path.getsize(self.error_log_file) + + return stats + except Exception as e: + return {'error': str(e)} + +# ========== 配置管理 ========== +class ConfigManager: + """增强的配置管理器,支持配置验证、热重载和备份恢复""" + + def __init__(self, config_file: str = "/sd/config.json"): + self.config_file = config_file + self.backup_file = f"{config_file}.backup" + self.logger = Logger("ConfigManager") + self.config = {} + self.last_modified = 0 + self.config_validators = {} + self._register_validators() + self._load_config() + + def _register_validators(self): + """注册配置验证器""" + self.config_validators = { + 'network': self._validate_network_config, + 'audio': self._validate_audio_config, + 'hardware': self._validate_hardware_config, + 'system': self._validate_system_config + } + + def _validate_network_config(self, config: Dict[str, Any]) -> bool: + """验证网络配置""" + try: + net_config = NetworkConfig(**config) + return net_config.validate() + except Exception as e: + self.logger.error(f"网络配置验证失败: {e}") + return False + + def _validate_audio_config(self, config: Dict[str, Any]) -> bool: + """验证音频配置""" + try: + audio_config = AudioConfig(**config) + return audio_config.validate() + except Exception as e: + self.logger.error(f"音频配置验证失败: {e}") + return False + + def _validate_hardware_config(self, config: Dict[str, Any]) -> bool: + """验证硬件配置""" + try: + hw_config = HardwareConfig(**config) + return hw_config.validate() + except Exception as e: + self.logger.error(f"硬件配置验证失败: {e}") + return False + + def _validate_system_config(self, config: Dict[str, Any]) -> bool: + """验证系统配置""" + try: + sys_config = SystemConfig(**config) + return sys_config.validate() + except Exception as e: + self.logger.error(f"系统配置验证失败: {e}") + return False + + def _load_config(self) -> Dict[str, Any]: + """加载配置""" + try: + if os.path.exists(self.config_file): + # 检查文件是否被修改 + current_modified = os.path.getmtime(self.config_file) + if current_modified > self.last_modified: + with open(self.config_file, "r", encoding="utf-8") as f: + config = json.load(f) + + # 验证配置 + if self._validate_config(config): + self.config = config + self.last_modified = current_modified + self.logger.info(f"配置文件加载成功: {self.config_file}") + return config + else: + self.logger.error("配置文件验证失败,使用默认配置") + return self._create_default_config() + else: + return self.config + else: + self.logger.warning("配置文件不存在,创建默认配置") + return self._create_default_config() + except Exception as e: + self.logger.error(f"加载配置文件失败: {e}") + return self._create_default_config() + + def _validate_config(self, config: Dict[str, Any]) -> bool: + """验证配置完整性""" + try: + required_sections = ['network', 'audio', 'hardware', 'system'] + for section in required_sections: + if section not in config: + self.logger.error(f"缺少配置节: {section}") + return False + + validator = self.config_validators.get(section) + if validator and not validator(config[section]): + return False + + return True + except Exception as e: + self.logger.error(f"配置验证失败: {e}") + return False + + def _create_default_config(self) -> Dict[str, Any]: + """创建默认配置""" + try: + config = { + "network": NetworkConfig().to_dict(), + "audio": AudioConfig().to_dict(), + "hardware": HardwareConfig().to_dict(), + "system": SystemConfig().to_dict() + } + + self._save_config(config) + return config + except Exception as e: + self.logger.error(f"创建默认配置失败: {e}") + return {} + + def _save_config(self, config: Dict[str, Any]): + """保存配置""" + try: + # 创建备份 + if os.path.exists(self.config_file): + os.rename(self.config_file, self.backup_file) + + # 保存新配置 + with open(self.config_file, "w", encoding="utf-8") as f: + json.dump(config, f, indent=2, ensure_ascii=False) + + self.logger.info(f"配置文件保存成功: {self.config_file}") + except Exception as e: + self.logger.error(f"保存配置文件失败: {e}") + # 恢复备份 + if os.path.exists(self.backup_file): + os.rename(self.backup_file, self.config_file) + + def reload_config(self) -> bool: + """重新加载配置""" + try: + self.config = self._load_config() + return len(self.config) > 0 + except Exception as e: + self.logger.error(f"重新加载配置失败: {e}") + return False + + def update_config(self, section: str, key: str, value: Any) -> bool: + """更新配置项""" + try: + if section not in self.config: + self.config[section] = {} + + self.config[section][key] = value + + # 验证更新后的配置 + if self._validate_config(self.config): + self._save_config(self.config) + self.logger.info(f"配置更新成功: {section}.{key} = {value}") + return True + else: + self.logger.error("配置更新后验证失败") + return False + except Exception as e: + self.logger.error(f"更新配置失败: {e}") + return False + + def get_network_config(self) -> NetworkConfig: + """获取网络配置""" + try: + self._load_config() # 重新加载以确保最新 + net_config = self.config.get("network", {}) + return NetworkConfig(**net_config) + except Exception as e: + self.logger.error(f"获取网络配置失败: {e}") + return NetworkConfig() + + def get_audio_config(self) -> AudioConfig: + """获取音频配置""" + try: + self._load_config() # 重新加载以确保最新 + audio_config = self.config.get("audio", {}) + return AudioConfig(**audio_config) + except Exception as e: + self.logger.error(f"获取音频配置失败: {e}") + return AudioConfig() + + def get_hardware_config(self) -> HardwareConfig: + """获取硬件配置""" + try: + self._load_config() # 重新加载以确保最新 + hw_config = self.config.get("hardware", {}) + return HardwareConfig(**hw_config) + except Exception as e: + self.logger.error(f"获取硬件配置失败: {e}") + return HardwareConfig() + + def get_system_config(self) -> SystemConfig: + """获取系统配置""" + try: + self._load_config() # 重新加载以确保最新 + sys_config = self.config.get("system", {}) + return SystemConfig(**sys_config) + except Exception as e: + self.logger.error(f"获取系统配置失败: {e}") + return SystemConfig() + + def export_config(self, export_file: str = None) -> bool: + """导出配置""" + try: + if not export_file: + export_file = f"{self.config_file}.export" + + with open(export_file, "w", encoding="utf-8") as f: + json.dump(self.config, f, indent=2, ensure_ascii=False) + + self.logger.info(f"配置导出成功: {export_file}") + return True + except Exception as e: + self.logger.error(f"配置导出失败: {e}") + return False + + def import_config(self, import_file: str) -> bool: + """导入配置""" + try: + with open(import_file, "r", encoding="utf-8") as f: + config = json.load(f) + + if self._validate_config(config): + self.config = config + self._save_config(config) + self.logger.info(f"配置导入成功: {import_file}") + return True + else: + self.logger.error("导入的配置验证失败") + return False + except Exception as e: + self.logger.error(f"配置导入失败: {e}") + return False + + def backup_config(self) -> bool: + """备份当前配置""" + try: + backup_file = f"{self.config_file}.backup_{int(time.time())}" + with open(backup_file, "w", encoding="utf-8") as f: + json.dump(self.config, f, indent=2, ensure_ascii=False) + + self.logger.info(f"配置备份成功: {backup_file}") + return True + except Exception as e: + self.logger.error(f"配置备份失败: {e}") + return False + + def restore_config(self, backup_file: str) -> bool: + """从备份恢复配置""" + try: + if not os.path.exists(backup_file): + self.logger.error(f"备份文件不存在: {backup_file}") + return False + + with open(backup_file, "r", encoding="utf-8") as f: + config = json.load(f) + + if self._validate_config(config): + self.config = config + self._save_config(config) + self.logger.info(f"配置恢复成功: {backup_file}") + return True + else: + self.logger.error("备份配置验证失败") + return False + except Exception as e: + self.logger.error(f"配置恢复失败: {e}") + return False + + def get_config_info(self) -> Dict[str, Any]: + """获取配置信息""" + try: + return { + 'config_file': self.config_file, + 'last_modified': self.last_modified, + 'sections': list(self.config.keys()), + 'backup_file': self.backup_file, + 'has_backup': os.path.exists(self.backup_file) + } + except Exception as e: + self.logger.error(f"获取配置信息失败: {e}") + return {} + +# ========== 性能监控 ========== +class PerformanceMonitor: + """增强的性能监控器,支持实时监控、告警和报告生成""" + + def __init__(self): + self.start_time = time.time() + self.logger = Logger("PerformanceMonitor") + self.stats = { + 'audio_packets_sent': 0, + 'location_packets_sent': 0, + 'commands_received': 0, + 'wifi_reconnects': 0, + 'errors': 0, + 'mode_switches': 0, + 'memory_usage': [], + 'cpu_usage': [], + 'network_latency': [], + 'audio_quality': [], + 'location_accuracy': [] + } + self.thresholds = { + 'memory_warning': 0.8, # 80%内存使用率告警 + 'cpu_warning': 0.9, # 90%CPU使用率告警 + 'latency_warning': 1000, # 1秒延迟告警 + 'error_warning': 10 # 10个错误告警 + } + self.alerts = [] + self.last_report_time = time.time() + self.report_interval = 300 # 5分钟生成一次报告 + + def increment(self, stat_name: str, value: int = 1): + """增加统计计数""" + if stat_name in self.stats: + if isinstance(self.stats[stat_name], list): + self.stats[stat_name].append(value) + # 保持最近100个数据点 + if len(self.stats[stat_name]) > 100: + self.stats[stat_name] = self.stats[stat_name][-100:] + else: + self.stats[stat_name] += value + + def record_metric(self, metric_name: str, value: float): + """记录指标""" + if metric_name in self.stats and isinstance(self.stats[metric_name], list): + self.stats[metric_name].append(value) + # 保持最近100个数据点 + if len(self.stats[metric_name]) > 100: + self.stats[metric_name] = self.stats[metric_name][-100:] + + def get_stats(self) -> Dict[str, Any]: + """获取统计信息""" + try: + current_time = time.time() + uptime = current_time - self.start_time + + # 计算平均值 + avg_stats = {} + for key, value in self.stats.items(): + if isinstance(value, list) and value: + avg_stats[f"{key}_avg"] = sum(value) / len(value) + avg_stats[f"{key}_min"] = min(value) + avg_stats[f"{key}_max"] = max(value) + avg_stats[f"{key}_latest"] = value[-1] + + stats = { + 'uptime_seconds': uptime, + 'uptime_formatted': self._format_uptime(uptime), + 'stats': self.stats.copy(), + 'avg_stats': avg_stats, + 'memory_usage': gc.mem_free(), + 'memory_percent': (1 - gc.mem_free() / gc.mem_alloc()) * 100 if gc.mem_alloc() > 0 else 0, + 'timestamp': current_time, + 'alerts': self.alerts.copy() + } + + return stats + except Exception as e: + self.logger.error(f"获取统计信息失败: {e}") + return {} + + def _format_uptime(self, seconds: float) -> str: + """格式化运行时间""" + days = int(seconds // 86400) + hours = int((seconds % 86400) // 3600) + minutes = int((seconds % 3600) // 60) + secs = int(seconds % 60) + + if days > 0: + return f"{days}天{hours}小时{minutes}分钟" + elif hours > 0: + return f"{hours}小时{minutes}分钟" + elif minutes > 0: + return f"{minutes}分钟{secs}秒" + else: + return f"{secs}秒" + + def check_alerts(self): + """检查告警条件""" + try: + current_time = time.time() + + # 检查内存使用率 + memory_percent = (1 - gc.mem_free() / gc.mem_alloc()) * 100 if gc.mem_alloc() > 0 else 0 + if memory_percent > self.thresholds['memory_warning'] * 100: + self._add_alert("MEMORY_WARNING", f"内存使用率过高: {memory_percent:.1f}%") + + # 检查错误数量 + if self.stats['errors'] > self.thresholds['error_warning']: + self._add_alert("ERROR_WARNING", f"错误数量过多: {self.stats['errors']}") + + # 检查网络延迟 + if self.stats['network_latency']: + avg_latency = sum(self.stats['network_latency']) / len(self.stats['network_latency']) + if avg_latency > self.thresholds['latency_warning']: + self._add_alert("LATENCY_WARNING", f"网络延迟过高: {avg_latency:.1f}ms") + + except Exception as e: + self.logger.error(f"检查告警失败: {e}") + + def _add_alert(self, alert_type: str, message: str): + """添加告警""" + alert = { + 'type': alert_type, + 'message': message, + 'timestamp': time.time() + } + self.alerts.append(alert) + + # 保持最近50个告警 + if len(self.alerts) > 50: + self.alerts = self.alerts[-50:] + + self.logger.warning(f"告警: {alert_type} - {message}") + + def log_stats(self): + """记录统计信息""" + try: + stats = self.get_stats() + self.logger.info(f"性能统计: {json.dumps(stats, indent=2)}") + + # 检查告警 + self.check_alerts() + + # 定期生成报告 + current_time = time.time() + if current_time - self.last_report_time > self.report_interval: + self._generate_report() + self.last_report_time = current_time + + except Exception as e: + self.logger.error(f"记录统计信息失败: {e}") + + def _generate_report(self): + """生成性能报告""" + try: + stats = self.get_stats() + report = { + 'report_time': time.strftime("%Y-%m-%d %H:%M:%S"), + 'uptime': stats['uptime_formatted'], + 'summary': { + 'total_audio_packets': stats['stats']['audio_packets_sent'], + 'total_location_packets': stats['stats']['location_packets_sent'], + 'total_commands': stats['stats']['commands_received'], + 'total_errors': stats['stats']['errors'], + 'total_reconnects': stats['stats']['wifi_reconnects'] + }, + 'performance': { + 'memory_usage_percent': stats['memory_percent'], + 'free_memory': stats['memory_usage'] + }, + 'alerts': stats['alerts'] + } + + self.logger.info(f"性能报告: {json.dumps(report, indent=2)}") + + # 保存报告到文件 + report_file = f"/sd/logs/performance_report_{int(time.time())}.json" + with open(report_file, "w", encoding="utf-8") as f: + json.dump(report, f, indent=2, ensure_ascii=False) + + except Exception as e: + self.logger.error(f"生成性能报告失败: {e}") + + def reset(self): + """重置统计""" + try: + self.start_time = time.time() + for key in self.stats: + if isinstance(self.stats[key], list): + self.stats[key] = [] + else: + self.stats[key] = 0 + self.alerts = [] + self.last_report_time = time.time() + self.logger.info("性能统计已重置") + except Exception as e: + self.logger.error(f"重置统计失败: {e}") + + def get_performance_score(self) -> float: + """计算性能评分 (0-100)""" + try: + score = 100.0 + + # 内存使用率扣分 + memory_percent = (1 - gc.mem_free() / gc.mem_alloc()) * 100 if gc.mem_alloc() > 0 else 0 + if memory_percent > 80: + score -= (memory_percent - 80) * 2 + + # 错误数量扣分 + if self.stats['errors'] > 0: + score -= min(self.stats['errors'] * 5, 30) + + # 重连次数扣分 + if self.stats['wifi_reconnects'] > 0: + score -= min(self.stats['wifi_reconnects'] * 3, 20) + + # 网络延迟扣分 + if self.stats['network_latency']: + avg_latency = sum(self.stats['network_latency']) / len(self.stats['network_latency']) + if avg_latency > 100: + score -= min((avg_latency - 100) / 10, 20) + + return max(0.0, score) + except Exception as e: + self.logger.error(f"计算性能评分失败: {e}") + return 0.0 + + def get_health_status(self) -> Dict[str, Any]: + """获取系统健康状态""" + try: + performance_score = self.get_performance_score() + + # 确定健康状态 + if performance_score >= 90: + health_status = "EXCELLENT" + elif performance_score >= 80: + health_status = "GOOD" + elif performance_score >= 60: + health_status = "FAIR" + elif performance_score >= 40: + health_status = "POOR" + else: + health_status = "CRITICAL" + + return { + 'health_status': health_status, + 'performance_score': performance_score, + 'alerts_count': len(self.alerts), + 'uptime': self._format_uptime(time.time() - self.start_time), + 'memory_usage_percent': (1 - gc.mem_free() / gc.mem_alloc()) * 100 if gc.mem_alloc() > 0 else 0, + 'free_memory': gc.mem_free(), + 'total_errors': self.stats['errors'], + 'total_reconnects': self.stats['wifi_reconnects'] + } + except Exception as e: + self.logger.error(f"获取健康状态失败: {e}") + return {'health_status': 'UNKNOWN', 'error': str(e)} + + def export_metrics(self, export_file: str = None) -> bool: + """导出性能指标""" + try: + if not export_file: + export_file = f"/sd/logs/metrics_export_{int(time.time())}.json" + + metrics = { + 'export_time': time.strftime("%Y-%m-%d %H:%M:%S"), + 'stats': self.stats.copy(), + 'health_status': self.get_health_status(), + 'alerts': self.alerts.copy(), + 'thresholds': self.thresholds.copy() + } + + with open(export_file, "w", encoding="utf-8") as f: + json.dump(metrics, f, indent=2, ensure_ascii=False) + + self.logger.info(f"性能指标导出成功: {export_file}") + return True + except Exception as e: + self.logger.error(f"性能指标导出失败: {e}") + return False + + def set_threshold(self, threshold_name: str, value: float) -> bool: + """设置告警阈值""" + try: + if threshold_name in self.thresholds: + self.thresholds[threshold_name] = value + self.logger.info(f"告警阈值更新: {threshold_name} = {value}") + return True + else: + self.logger.error(f"未知的阈值名称: {threshold_name}") + return False + except Exception as e: + self.logger.error(f"设置阈值失败: {e}") + return False + + def clear_alerts(self): + """清除告警""" + try: + self.alerts.clear() + self.logger.info("告警已清除") + except Exception as e: + self.logger.error(f"清除告警失败: {e}") + + def get_alert_summary(self) -> Dict[str, Any]: + """获取告警摘要""" + try: + alert_counts = {} + for alert in self.alerts: + alert_type = alert['type'] + alert_counts[alert_type] = alert_counts.get(alert_type, 0) + 1 + + return { + 'total_alerts': len(self.alerts), + 'alert_counts': alert_counts, + 'latest_alerts': self.alerts[-5:] if self.alerts else [] + } + except Exception as e: + self.logger.error(f"获取告警摘要失败: {e}") + return {} + +# ========== 全局变量 ========== +logger = Logger("DevelopmentBoard") +config_manager = ConfigManager() +performance_monitor = PerformanceMonitor() + +# 信号处理 +def signal_handler(signum, frame): + """信号处理器""" + logger.info(f"接收到信号 {signum},准备关闭程序...") + # 这里会在DevelopmentBoard类中实现优雅关闭 + sys.exit(0) + +class DevelopmentBoard: + """增强的开发板主类,支持完整的声源定位系统功能""" + + def __init__(self): + # 基础状态 + self.running = True + self.current_mode = SystemMode.INITIALIZING + self.previous_mode = SystemMode.INITIALIZING + self.system_status = "INITIALIZING" + + # 配置管理 + self.config_manager = ConfigManager() + self.network_config = self.config_manager.get_network_config() + self.audio_config = self.config_manager.get_audio_config() + self.hardware_config = self.config_manager.get_hardware_config() + self.system_config = self.config_manager.get_system_config() + + # 日志和监控 + self.logger = Logger("DevelopmentBoard", self.system_config.log_level) + self.performance_monitor = PerformanceMonitor() + + # 连接状态 + self.wifi_status = WiFiStatus.DISCONNECTED + self.connection_status = ConnectionStatus.DISCONNECTED + self.audio_status = AudioStatus.IDLE + + # WiFi相关 + self.uart = None + self.wifi_en = None + self.nic = None + self.wifi_connection_attempts = 0 + self.last_wifi_check = 0 + + # Socket连接 + self.audio_socket = None + self.cmd_socket = None + self.location_socket = None + self.socket_connection_attempts = 0 + self.last_socket_check = 0 + + # 硬件组件 + self.led = None + self.buzzer = None + self.button = None + self.temperature_sensor = None + + # 音频相关 + self.audio_buffer = [] + self.audio_processing = False + self.last_audio_timestamp = 0 + + # 定位相关 + self.location_buffer = [] + self.location_processing = False + self.last_location_timestamp = 0 + + # 新增:枪声检测器 + self.gunshot_detector = GunshotDetector(self.audio_config) + + # 新增:定位模式下的音频缓冲 + self.location_audio_buffer = [] + self.location_audio_buffer_size = int(self.audio_config.sample_rate * 0.5) # 0.5秒缓冲 + + # 新增:定位-音频映射队列 + self.location_audio_mappings = [] # 存储定位结果和音频的映射关系 + self.max_mapping_queue_size = 20 # 最大映射队列大小 + self.recognition_results = {} # 存储PC端的识别结果 {timestamp: result} + + # 系统监控 + self.heartbeat_timer = None + self.health_check_timer = None + self.last_heartbeat = 0 + self.last_health_check = 0 + + # 错误处理 + self.error_count = 0 + self.last_error_time = 0 + self.error_recovery_attempts = 0 + + # 性能统计 + self.start_time = time.time() + self.mode_switch_count = 0 + self.total_audio_packets = 0 + self.total_location_packets = 0 + + # 初始化系统 + self._initialize_system() + + def _initialize_system(self): + """初始化系统""" + try: + self.logger.info("开始系统初始化...") + self.logger.info(f"系统配置: {self.system_config.to_dict()}") + + # 检查内存 + free_memory = gc.mem_free() + if free_memory < 1024 * 1024: # 少于1MB + raise MemoryError(f"内存不足: {free_memory} bytes") + + # 初始化硬件 + self._initialize_hardware() + + # 初始化网络 + self._initialize_network() + + # 初始化音频系统 + self._initialize_audio_system() + + # 初始化定位系统 + self._initialize_location_system() + + # 启动监控 + self._start_monitoring() + + # 切换到录音模式 + self._switch_mode(SystemMode.RECORDING) + + self.logger.info("系统初始化完成") + self.system_status = "READY" + + except Exception as e: + self.logger.error(f"系统初始化失败: {e}") + self.system_status = "ERROR" + self.current_mode = SystemMode.ERROR + raise + + def _initialize_hardware(self): + """初始化硬件组件""" + try: + self.logger.info("初始化硬件组件...") + + # 初始化WiFi硬件 + self._init_wifi_hardware() + + # 初始化麦克风阵列 + self._init_microphone_array() + + # 初始化其他硬件组件 + self._init_additional_hardware() + + self.logger.info("硬件初始化完成") + + except Exception as e: + self.logger.error(f"硬件初始化失败: {e}") + raise HardwareFaultError(f"硬件初始化失败: {e}", "hardware_init") + + def _init_wifi_hardware(self): + """初始化WiFi硬件""" + try: + # GPIO用于WiFi使能控制 + fm.register(self.hardware_config.wifi_en_pin, fm.fpioa.GPIOHS0, force=True) + self.wifi_en = GPIO(GPIO.GPIOHS0, GPIO.OUT) + + # 配置UART用于与ESP8285通信 + fm.register(board_info.WIFI_RX, fm.fpioa.UART2_TX, force=True) + fm.register(board_info.WIFI_TX, fm.fpioa.UART2_RX, force=True) + + self.logger.info("WiFi硬件引脚初始化完成") + + except Exception as e: + self.logger.error(f"WiFi硬件初始化失败: {e}") + raise HardwareFaultError(f"WiFi硬件初始化失败: {e}", "wifi_hardware") + + def _init_microphone_array(self): + """初始化麦克风阵列""" + try: + mic.init( + i2s_d0=self.hardware_config.mic_i2s_d0, + i2s_d1=self.hardware_config.mic_i2s_d1, + i2s_d2=self.hardware_config.mic_i2s_d2, + i2s_d3=self.hardware_config.mic_i2s_d3, + i2s_ws=self.hardware_config.mic_i2s_ws, + i2s_sclk=self.hardware_config.mic_i2s_sclk, + sk9822_dat=self.hardware_config.sk9822_dat, + sk9822_clk=self.hardware_config.sk9822_clk + ) + self.logger.info("麦克风阵列初始化成功") + + except Exception as e: + self.logger.error(f"麦克风阵列初始化失败: {e}") + raise MicArrayInitError(f"麦克风阵列初始化失败: {e}") + + def _init_additional_hardware(self): + """初始化其他硬件组件""" + try: + # 初始化LED + fm.register(self.hardware_config.led_pin, fm.fpioa.GPIOHS1, force=True) + self.led = GPIO(GPIO.GPIOHS1, GPIO.OUT) + self.led.value(0) # 关闭LED + + # 初始化蜂鸣器 + fm.register(self.hardware_config.buzzer_pin, fm.fpioa.GPIOHS2, force=True) + self.buzzer = GPIO(GPIO.GPIOHS2, GPIO.OUT) + self.buzzer.value(0) # 关闭蜂鸣器 + + # 初始化按钮 + fm.register(self.hardware_config.button_pin, fm.fpioa.GPIOHS3, force=True) + self.button = GPIO(GPIO.GPIOHS3, GPIO.IN, GPIO.PULL_UP) + + self.logger.info("其他硬件组件初始化完成") + + except Exception as e: + self.logger.error(f"其他硬件组件初始化失败: {e}") + # 不抛出异常,这些组件不是必需的 + + def _initialize_network(self): + """初始化网络连接""" + try: + self.logger.info("初始化网络连接...") + + # 连接到WiFi + if not self._connect_wifi(): + raise WiFiConnectionError("WiFi连接失败", self.network_config.wifi_ssid) + + # 建立Socket连接 + if not self._setup_socket_connections(): + raise SocketConnectionError("Socket连接失败", self.network_config.pc_ip) + + self.logger.info("网络连接初始化完成") + + except Exception as e: + self.logger.error(f"网络连接初始化失败: {e}") + raise + + def _initialize_audio_system(self): + """初始化音频系统""" + try: + self.logger.info("初始化音频系统...") + + # 验证音频配置 + if not self.audio_config.validate(): + raise AudioInitError("音频配置验证失败") + + # 初始化音频缓冲区 + self.audio_buffer = [] + + self.logger.info("音频系统初始化完成") + + except Exception as e: + self.logger.error(f"音频系统初始化失败: {e}") + raise AudioInitError(f"音频系统初始化失败: {e}") + + def _initialize_location_system(self): + """初始化定位系统""" + try: + self.logger.info("初始化定位系统...") + + # 初始化定位缓冲区 + self.location_buffer = [] + + # 测试麦克风阵列功能 + test_location = self._get_mic_direction() + if test_location is None: + raise MicArrayInitError("麦克风阵列测试失败") + + self.logger.info("定位系统初始化完成") + + except Exception as e: + self.logger.error(f"定位系统初始化失败: {e}") + raise MicArrayInitError(f"定位系统初始化失败: {e}") + + def _start_monitoring(self): + """启动系统监控""" + try: + self.logger.info("启动系统监控...") + + # 启动心跳定时器 + if self.system_config.enable_performance_monitor: + self.heartbeat_timer = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PERIODIC, + period=int(self.system_config.heartbeat_interval * 1000), + callback=self._heartbeat_callback) + + # 启动健康检查定时器 + if self.system_config.enable_hardware_monitor: + self.health_check_timer = Timer(Timer.TIMER1, Timer.CHANNEL0, mode=Timer.MODE_PERIODIC, + period=60000, # 1分钟检查一次 + callback=self._health_check_callback) + + self.logger.info("系统监控启动完成") + + except Exception as e: + self.logger.error(f"系统监控启动失败: {e}") + # 不抛出异常,监控不是必需的 + + def _heartbeat_callback(self, timer): + """心跳回调函数""" + try: + current_time = time.time() + self.last_heartbeat = current_time + + # 发送心跳数据 + self._send_heartbeat() + + # 记录性能统计 + if self.system_config.enable_performance_monitor: + self.performance_monitor.log_stats() + + except Exception as e: + self.logger.error(f"心跳回调失败: {e}") + + def _health_check_callback(self, timer): + """健康检查回调函数""" + try: + current_time = time.time() + self.last_health_check = current_time + + # 检查系统健康状态 + health_status = self.performance_monitor.get_health_status() + + # 如果健康状态较差,尝试恢复 + if health_status['health_status'] in ['POOR', 'CRITICAL']: + self.logger.warning(f"系统健康状态较差: {health_status['health_status']}") + self._attempt_recovery() + + except Exception as e: + self.logger.error(f"健康检查回调失败: {e}") + + def _send_heartbeat(self): + """发送心跳数据""" + try: + heartbeat_data = { + 'type': 'heartbeat', + 'timestamp': time.time(), + 'mode': self.current_mode.value, + 'status': self.system_status, + 'uptime': time.time() - self.start_time, + 'memory': gc.mem_free(), + 'error_count': self.error_count + } + + if self.cmd_socket: + self.cmd_socket.send(json.dumps(heartbeat_data).encode('utf-8')) + + except Exception as e: + self.logger.error(f"发送心跳失败: {e}") + + def _attempt_recovery(self): + """尝试系统恢复""" + try: + if self.error_recovery_attempts >= Constants.MAX_RETRY_ATTEMPTS: + self.logger.error("恢复尝试次数已达上限,切换到错误模式") + self._switch_mode(SystemMode.ERROR) + return + + self.error_recovery_attempts += 1 + self.logger.info(f"尝试系统恢复 (第{self.error_recovery_attempts}次)") + + # 检查网络连接 + if self.wifi_status != WiFiStatus.CONNECTED: + self._connect_wifi() + + # 检查Socket连接 + if self.connection_status != ConnectionStatus.CONNECTED: + self._setup_socket_connections() + + # 重置错误计数 + if self.error_count > 0: + self.error_count = 0 + self.error_recovery_attempts = 0 + self.logger.info("系统恢复成功") + + except Exception as e: + self.logger.error(f"系统恢复失败: {e}") + + def _switch_mode(self, new_mode: SystemMode): + """切换系统模式""" + try: + if new_mode == self.current_mode: + return + + self.previous_mode = self.current_mode + self.current_mode = new_mode + self.mode_switch_count += 1 + + self.logger.info(f"系统模式切换: {self.previous_mode.value} -> {self.current_mode.value}") + + # 根据模式执行相应操作 + if new_mode == SystemMode.RECORDING: + self._enter_recording_mode() + elif new_mode == SystemMode.LOCATING: + self._enter_locating_mode() + elif new_mode == SystemMode.ERROR: + self._enter_error_mode() + elif new_mode == SystemMode.SHUTDOWN: + self._enter_shutdown_mode() + + # 更新性能统计 + self.performance_monitor.increment('mode_switches') + + except Exception as e: + self.logger.error(f"模式切换失败: {e}") + self.current_mode = SystemMode.ERROR + + def _enter_recording_mode(self): + """进入录音模式""" + try: + self.audio_status = AudioStatus.IDLE + self.logger.info("进入录音模式") + + # 设置LED状态 + if self.led: + self.led.value(1) # 点亮LED表示录音模式 + + except Exception as e: + self.logger.error(f"进入录音模式失败: {e}") + + def _enter_locating_mode(self): + """进入定位模式""" + try: + self.audio_status = AudioStatus.PROCESSING + self.logger.info("进入定位模式") + + # 重置枪声检测器 + self.gunshot_detector.reset() + + # 清空定位音频缓冲 + self.location_audio_buffer.clear() + + # 设置LED状态 + if self.led: + self.led.value(0) # 关闭LED表示定位模式 + + except Exception as e: + self.logger.error(f"进入定位模式失败: {e}") + + def _enter_error_mode(self): + """进入错误模式""" + try: + self.system_status = "ERROR" + self.logger.error("进入错误模式") + + # 设置LED状态 + if self.led: + self.led.value(1) # 点亮LED表示错误状态 + + # 蜂鸣器报警 + if self.buzzer: + self._beep_error() + + except Exception as e: + self.logger.error(f"进入错误模式失败: {e}") + + def _enter_shutdown_mode(self): + """进入关闭模式""" + try: + self.system_status = "SHUTDOWN" + self.logger.info("进入关闭模式") + + # 关闭所有硬件 + self._shutdown_hardware() + + except Exception as e: + self.logger.error(f"进入关闭模式失败: {e}") + + def _beep_error(self): + """错误蜂鸣""" + try: + if self.buzzer: + # 蜂鸣3次 + for i in range(3): + self.buzzer.value(1) + time.sleep_ms(200) + self.buzzer.value(0) + time.sleep_ms(200) + except Exception as e: + self.logger.error(f"错误蜂鸣失败: {e}") + + def _shutdown_hardware(self): + """关闭硬件""" + try: + # 关闭LED + if self.led: + self.led.value(0) + + # 关闭蜂鸣器 + if self.buzzer: + self.buzzer.value(0) + + # 关闭WiFi + if self.wifi_en: + self.wifi_en.value(0) + + self.logger.info("硬件关闭完成") + + except Exception as e: + self.logger.error(f"硬件关闭失败: {e}") + + def run(self): + """主运行循环""" + try: + self.logger.info("开始主运行循环") + + while self.running: + try: + # 根据当前模式执行相应操作 + if self.current_mode == SystemMode.RECORDING: + self._recording_mode_loop() + elif self.current_mode == SystemMode.LOCATING: + self._locating_mode_loop() + elif self.current_mode == SystemMode.ERROR: + self._error_mode_loop() + elif self.current_mode == SystemMode.SHUTDOWN: + break + + # 短暂休眠 + time.sleep_ms(10) + + except Exception as e: + self.logger.error(f"主循环异常: {e}") + self.error_count += 1 + time.sleep_ms(100) + + except Exception as e: + self.logger.error(f"主运行循环失败: {e}") + finally: + self._cleanup() + + def _recording_mode_loop(self): + """录音模式循环""" + try: + # 录音并发送给PC端 + audio_data = self._record_audio() + if audio_data: + self._send_audio_data(audio_data) + self.total_audio_packets += 1 + + # 更新性能统计 + self.performance_monitor.increment('audio_packets_sent') + + # 检查PC端指令 + self._check_pc_commands() + + except Exception as e: + self.logger.error(f"录音模式循环异常: {e}") + self.error_count += 1 + + def _locating_mode_loop(self): + """定位模式循环 - 先定位后识别""" + try: + # 录音 + audio_data = self._record_audio() + if not audio_data: + return + + # 添加到定位音频缓冲 + self.location_audio_buffer.extend(audio_data) + + # 限制缓冲大小 + if len(self.location_audio_buffer) > self.location_audio_buffer_size: + self.location_audio_buffer = self.location_audio_buffer[-self.location_audio_buffer_size:] + + # 检查是否有足够的音频数据进行声源定位 + if len(self.location_audio_buffer) >= self.audio_config.chunk_size: + # 1. 先进行声源定位 + location_data = self._perform_sound_source_location(self.location_audio_buffer) + + if location_data: + # 2. 存储定位结果和音频的映射关系 + audio_segment = self.location_audio_buffer.copy() + mapping_entry = { + 'location_data': location_data, + 'audio_data': audio_segment, + 'timestamp': time.time(), + 'processed': False # 标记是否已被PC端处理 + } + + # 添加到映射队列 + self._add_location_audio_mapping(mapping_entry) + + # 3. 将音频数据发送给PC端进行枪声识别 + self._send_audio_for_recognition(audio_segment) + + self.logger.debug(f"定位完成: X={location_data.x:.2f}, Y={location_data.y:.2f}, 音频已发送识别") + + # 清空音频缓冲,准备下一轮 + self.location_audio_buffer.clear() + + # 4. 检查PC端的枪声识别结果 + self._check_recognition_results() + + # 检查PC端指令 + self._check_pc_commands() + + except Exception as e: + self.logger.error(f"定位模式循环异常: {e}") + self.error_count += 1 + + def _send_gunshot_detection_result(self, detection_result: Dict[str, Any]): + """发送枪声检测结果给PC端""" + try: + if not self.location_socket: + return + + # 构建检测结果字符串 + # 格式: GUNSHOT_DETECTION:is_gunshot:confidence:timestamp + is_gunshot_str = "true" if detection_result['is_gunshot'] else "false" + confidence = detection_result.get('confidence', 0.0) + timestamp = detection_result.get('timestamp', time.time()) + + detection_str = f"GUNSHOT_DETECTION:{is_gunshot_str}:{confidence:.3f}:{timestamp}" + + # 发送数据 + self.location_socket.send(detection_str.encode('utf-8')) + + except Exception as e: + self.logger.error(f"发送枪声检测结果失败: {e}") + self.connection_status = ConnectionStatus.ERROR + + def _add_location_audio_mapping(self, mapping_entry: Dict[str, Any]): + """添加定位-音频映射关系""" + try: + self.location_audio_mappings.append(mapping_entry) + + # 限制队列大小 + if len(self.location_audio_mappings) > self.max_mapping_queue_size: + # 移除最老的映射关系 + removed = self.location_audio_mappings.pop(0) + self.logger.debug(f"移除过期映射关系: {removed['timestamp']}") + + self.logger.debug(f"添加映射关系: 时间戳={mapping_entry['timestamp']:.3f}") + + except Exception as e: + self.logger.error(f"添加映射关系失败: {e}") + + def _send_audio_for_recognition(self, audio_data: List[float]): + """发送音频数据给PC端进行枪声识别""" + try: + if not self.audio_socket: + return + + # 构建识别请求数据 + # 格式: RECOGNITION_REQUEST:timestamp:audio_data + timestamp = time.time() + + # 将音频数据转换为字节 + audio_bytes = np.array(audio_data, dtype=np.int16).tobytes() + + # 构建请求头 + request_header = f"RECOGNITION_REQUEST:{timestamp:.3f}:{len(audio_bytes)}" + + # 发送请求头 + self.audio_socket.send(request_header.encode('utf-8')) + time.sleep_ms(10) # 短暂等待 + + # 发送音频数据 + self.audio_socket.send(audio_bytes) + + self.logger.debug(f"发送识别请求: 时间戳={timestamp:.3f}, 数据大小={len(audio_bytes)}") + + except Exception as e: + self.logger.error(f"发送识别请求失败: {e}") + self.connection_status = ConnectionStatus.ERROR + + def _check_recognition_results(self): + """检查PC端的枪声识别结果""" + try: + if not self.cmd_socket: + return + + # 非阻塞接收识别结果 + try: + self.cmd_socket.settimeout(0.1) # 100ms超时 + data = self.cmd_socket.recv(1024) + + if data: + result_str = data.decode('utf-8').strip() + self._process_recognition_result(result_str) + + except socket.timeout: + # 超时继续 + pass + + except Exception as e: + self.logger.error(f"检查识别结果失败: {e}") + + def _process_recognition_result(self, result_str: str): + """处理PC端的识别结果""" + try: + # 解析识别结果格式: RECOGNITION_RESULT:timestamp:is_gunshot:confidence + if not result_str.startswith("RECOGNITION_RESULT:"): + return + + parts = result_str.split(':') + if len(parts) >= 4: + timestamp = float(parts[1]) + is_gunshot = parts[2].lower() == 'true' + confidence = float(parts[3]) + + # 存储识别结果 + self.recognition_results[timestamp] = { + 'is_gunshot': is_gunshot, + 'confidence': confidence, + 'processed': False + } + + self.logger.info(f"收到识别结果: 时间戳={timestamp:.3f}, 枪声={is_gunshot}, 置信度={confidence:.3f}") + + # 处理对应的定位数据 + self._process_matching_location(timestamp, is_gunshot, confidence) + + except Exception as e: + self.logger.error(f"处理识别结果失败: {e}") + + def _process_matching_location(self, timestamp: float, is_gunshot: bool, confidence: float): + """处理匹配的定位数据""" + try: + # 查找时间戳最接近的映射关系 + best_match = None + min_time_diff = float('inf') + + for mapping in self.location_audio_mappings: + if mapping['processed']: + continue + + time_diff = abs(mapping['timestamp'] - timestamp) + if time_diff < min_time_diff and time_diff < 1.0: # 1秒内的匹配 + min_time_diff = time_diff + best_match = mapping + + if best_match: + # 标记为已处理 + best_match['processed'] = True + self.recognition_results[timestamp]['processed'] = True + + if is_gunshot: + # 如果是枪声,发送对应的定位数据 + location_data = best_match['location_data'] + self._send_location_data(location_data) + self.total_location_packets += 1 + + # 更新性能统计 + self.performance_monitor.increment('location_packets_sent') + + self.logger.info(f"枪声确认!发送定位数据: X={location_data.x:.2f}, Y={location_data.y:.2f}, 置信度={confidence:.3f}") + else: + self.logger.debug(f"非枪声,忽略定位数据: 时间戳={timestamp:.3f}") + + # 清理已处理的映射关系 + self._cleanup_processed_mappings() + + except Exception as e: + self.logger.error(f"处理匹配定位数据失败: {e}") + + def _cleanup_processed_mappings(self): + """清理已处理的映射关系""" + try: + # 移除已处理的映射关系 + self.location_audio_mappings = [m for m in self.location_audio_mappings if not m['processed']] + + # 清理过期的识别结果(超过5秒) + current_time = time.time() + expired_timestamps = [ts for ts in self.recognition_results.keys() + if current_time - ts > 5.0] + for ts in expired_timestamps: + del self.recognition_results[ts] + + except Exception as e: + self.logger.error(f"清理映射关系失败: {e}") + + def _error_mode_loop(self): + """错误模式循环""" + try: + # 错误模式下尝试恢复 + if self.error_recovery_attempts < Constants.MAX_RETRY_ATTEMPTS: + self._attempt_recovery() + else: + # 达到最大重试次数,进入维护模式 + self._switch_mode(SystemMode.MAINTENANCE) + + time.sleep_ms(1000) # 错误模式下等待1秒 + + except Exception as e: + self.logger.error(f"错误模式循环异常: {e}") + + def _record_audio(self) -> Optional[List[float]]: + """录音""" + try: + # 从麦克风阵列获取音频数据 + # 这里需要根据实际的麦克风阵列API进行调整 + audio_data = mic.get_audio_data(self.audio_config.chunk_size) + + if audio_data and len(audio_data) > 0: + return audio_data + else: + return None + + except Exception as e: + self.logger.error(f"录音失败: {e}") + return None + + def _send_audio_data(self, audio_data: List[float]): + """发送音频数据""" + try: + if not self.audio_socket: + return + + # 转换为字节数据 + audio_bytes = np.array(audio_data, dtype=np.int16).tobytes() + + # 发送数据 + self.audio_socket.send(audio_bytes) + + except Exception as e: + self.logger.error(f"发送音频数据失败: {e}") + self.connection_status = ConnectionStatus.ERROR + + def _send_location_data(self, location_data: LocationData): + """发送定位数据""" + try: + if not self.location_socket: + return + + # 转换为字符串格式 + location_str = f"{location_data.x:.2f},{location_data.y:.2f},{location_data.strength:.2f},{location_data.angle:.2f}" + + # 发送数据 + self.location_socket.send(location_str.encode('utf-8')) + + except Exception as e: + self.logger.error(f"发送定位数据失败: {e}") + self.connection_status = ConnectionStatus.ERROR + + def _check_pc_commands(self): + """检查PC端指令""" + try: + if not self.cmd_socket: + return + + # 非阻塞接收指令 + try: + self.cmd_socket.settimeout(0.1) # 100ms超时 + data = self.cmd_socket.recv(1024) + + if data: + command = data.decode('utf-8').strip() + self._process_command(command) + + except socket.timeout: + # 超时继续 + pass + + except Exception as e: + self.logger.error(f"检查PC指令失败: {e}") + + def _process_command(self, command: str): + """处理PC端指令""" + try: + self.logger.info(f"收到PC指令: {command}") + + if command == "START_LOCATION": + self._switch_mode(SystemMode.LOCATING) + elif command == "STOP_LOCATION": + self._switch_mode(SystemMode.RECORDING) + elif command == "SHUTDOWN": + self._switch_mode(SystemMode.SHUTDOWN) + elif command == "HEARTBEAT": + self._send_heartbeat() + elif command.startswith("SET_CONFIG"): + self._process_config_command(command) + else: + self.logger.warning(f"未知指令: {command}") + + except Exception as e: + self.logger.error(f"处理指令失败: {e}") + + def _process_config_command(self, command: str): + """处理配置指令""" + try: + # 解析配置指令格式: SET_CONFIG:section:key:value + parts = command.split(':') + if len(parts) == 4: + section = parts[1] + key = parts[2] + value = parts[3] + + # 更新配置 + if self.config_manager.update_config(section, key, value): + self.logger.info(f"配置更新成功: {section}.{key} = {value}") + + # 重新加载配置 + self._reload_config() + else: + self.logger.error(f"配置更新失败: {section}.{key} = {value}") + + except Exception as e: + self.logger.error(f"处理配置指令失败: {e}") + + def _reload_config(self): + """重新加载配置""" + try: + self.network_config = self.config_manager.get_network_config() + self.audio_config = self.config_manager.get_audio_config() + self.hardware_config = self.config_manager.get_hardware_config() + self.system_config = self.config_manager.get_system_config() + + self.logger.info("配置重新加载完成") + + except Exception as e: + self.logger.error(f"重新加载配置失败: {e}") + + def _perform_sound_source_location(self, audio_data: List[float]) -> Optional[LocationData]: + """执行声源定位""" + try: + # 使用声源定位器进行定位 + if hasattr(self, 'sound_source_locator'): + location_data = self.sound_source_locator.process_audio_frame(audio_data) + return location_data + else: + # 如果没有专门的定位器,使用简单的麦克风方向检测 + return self._get_mic_direction() + + except Exception as e: + self.logger.error(f"声源定位失败: {e}") + return None + + def _get_mic_direction(self) -> Optional[LocationData]: + """获取麦克风方向(简单实现)""" + try: + # 获取麦克风阵列数据 + mic_data = mic.get_direction() + if mic_data: + # 解析麦克风数据 + # 这里需要根据实际的麦克风阵列API进行调整 + angle = mic_data.get('angle', 0) + strength = mic_data.get('strength', 0) + + # 转换为坐标 + distance = 5.0 # 假设距离5米 + x = distance * math.cos(math.radians(angle)) + y = distance * math.sin(math.radians(angle)) + + return LocationData( + x=x, + y=y, + strength=strength, + angle=angle, + timestamp=time.time(), + confidence=0.8, + quality=0.7, + noise_level=0.3, + source_type="gunshot" + ) + else: + return None + + except Exception as e: + self.logger.error(f"获取麦克风方向失败: {e}") + return None + + def _connect_wifi(self) -> bool: + """连接WiFi""" + try: + if self.wifi_status == WiFiStatus.CONNECTED: + return True + + self.wifi_status = WiFiStatus.CONNECTING + self.logger.info(f"正在连接WiFi: {self.network_config.wifi_ssid}") + + # 启用WiFi硬件 + if self.wifi_en: + self.wifi_en.value(1) + time.sleep_ms(1000) # 等待WiFi启动 + + # 连接WiFi + # 这里需要根据实际的WiFi API进行调整 + # self.nic = network.WLAN(network.STA_IF) + # self.nic.active(True) + # self.nic.connect(self.network_config.wifi_ssid, self.network_config.wifi_password) + + # 等待连接 + max_wait = int(self.network_config.connection_timeout * 1000) + wait_time = 0 + while wait_time < max_wait: + # if self.nic.isconnected(): + # self.wifi_status = WiFiStatus.CONNECTED + # self.logger.info("WiFi连接成功") + # return True + + time.sleep_ms(100) + wait_time += 100 + + self.wifi_status = WiFiStatus.ERROR + self.logger.error("WiFi连接超时") + return False + + except Exception as e: + self.wifi_status = WiFiStatus.ERROR + self.logger.error(f"WiFi连接失败: {e}") + return False + + def _setup_socket_connections(self) -> bool: + """建立Socket连接""" + try: + self.connection_status = ConnectionStatus.CONNECTING + self.logger.info("正在建立Socket连接...") + + # 连接音频Socket + self.audio_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.audio_socket.connect((self.network_config.pc_ip, self.network_config.pc_port_audio)) + self.audio_socket.settimeout(self.network_config.socket_timeout) + + # 连接指令Socket + self.cmd_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.cmd_socket.connect((self.network_config.pc_ip, self.network_config.pc_port_cmd)) + self.cmd_socket.settimeout(self.network_config.socket_timeout) + + # 连接定位Socket + self.location_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.location_socket.connect((self.network_config.pc_ip, self.network_config.pc_port_location)) + self.location_socket.settimeout(self.network_config.socket_timeout) + + self.connection_status = ConnectionStatus.CONNECTED + self.logger.info("所有Socket连接建立成功") + return True + + except Exception as e: + self.connection_status = ConnectionStatus.ERROR + self.logger.error(f"Socket连接失败: {e}") + return False + + def _cleanup(self): + """清理资源""" + try: + self.logger.info("开始清理资源...") + self.running = False + + # 关闭Socket连接 + for socket_name, sock in [('audio', self.audio_socket), + ('cmd', self.cmd_socket), + ('location', self.location_socket)]: + if sock: + try: + sock.close() + self.logger.info(f"关闭{socket_name} Socket") + except Exception as e: + self.logger.error(f"关闭{socket_name} Socket失败: {e}") + + # 关闭硬件 + self._shutdown_hardware() + + # 停止定时器 + if self.heartbeat_timer: + self.heartbeat_timer.stop() + if self.health_check_timer: + self.health_check_timer.stop() + + self.logger.info("资源清理完成") + + except Exception as e: + self.logger.error(f"清理资源失败: {e}") + +# ========== 声源定位核心算法 ========== +class KalmanFilter: + """卡尔曼滤波器,用于声源定位的噪声降低和精度提升""" + + def __init__(self, dim_x: int = 4, dim_z: int = 2): + """ + 初始化卡尔曼滤波器 + dim_x: 状态向量维度 (x, y, vx, vy) + dim_z: 观测向量维度 (x, y) + """ + self.dim_x = dim_x + self.dim_z = dim_z + + # 状态转移矩阵 F (假设匀速运动) + self.F = np.array([ + [1, 0, 1, 0], # x = x + vx + [0, 1, 0, 1], # y = y + vy + [0, 0, 1, 0], # vx = vx + [0, 0, 0, 1] # vy = vy + ]) + + # 观测矩阵 H (只能观测位置) + self.H = np.array([ + [1, 0, 0, 0], # 观测x + [0, 1, 0, 0] # 观测y + ]) + + # 状态协方差矩阵 P + self.P = np.eye(dim_x) * 1000 + + # 过程噪声协方差矩阵 Q + self.Q = np.eye(dim_x) * 0.1 + + # 观测噪声协方差矩阵 R + self.R = np.eye(dim_z) * 10 + + # 状态向量 x + self.x = np.zeros((dim_x, 1)) + + # 卡尔曼增益 + self.K = np.zeros((dim_x, dim_z)) + + self.logger = Logger("KalmanFilter") + + def predict(self, dt: float = 1.0): + """预测步骤""" + try: + # 更新状态转移矩阵中的时间步长 + self.F[0, 2] = dt + self.F[1, 3] = dt + + # 预测状态 + self.x = self.F @ self.x + + # 预测协方差 + self.P = self.F @ self.P @ self.F.T + self.Q + + except Exception as e: + self.logger.error(f"卡尔曼滤波预测失败: {e}") + + def update(self, measurement: np.ndarray): + """更新步骤""" + try: + # 计算卡尔曼增益 + S = self.H @ self.P @ self.H.T + self.R + self.K = self.P @ self.H.T @ np.linalg.inv(S) + + # 更新状态 + y = measurement.reshape(-1, 1) - self.H @ self.x + self.x = self.x + self.K @ y + + # 更新协方差 + I = np.eye(self.dim_x) + self.P = (I - self.K @ self.H) @ self.P + + except Exception as e: + self.logger.error(f"卡尔曼滤波更新失败: {e}") + + def get_state(self) -> Dict[str, float]: + """获取当前状态""" + return { + 'x': float(self.x[0, 0]), + 'y': float(self.x[1, 0]), + 'vx': float(self.x[2, 0]), + 'vy': float(self.x[3, 0]) + } + + def reset(self): + """重置滤波器""" + self.P = np.eye(self.dim_x) * 1000 + self.x = np.zeros((self.dim_x, 1)) + +class SoundSourceLocator: + """声源定位器,集成多种算法提升定位精度""" + + def __init__(self, config: HardwareConfig): + self.config = config + self.logger = Logger("SoundSourceLocator") + + # 卡尔曼滤波器 + self.kalman_filter = KalmanFilter() + + # 定位参数 + self.mic_positions = self._calculate_mic_positions() + self.sound_speed = 343.0 # 声速 (m/s) + self.sample_rate = 16000 + self.frame_size = 1024 + + # 噪声处理 + self.noise_threshold = 0.1 + self.signal_threshold = 0.3 + self.min_signal_duration = 0.1 # 最小信号持续时间 + + # 定位历史 + self.location_history = [] + self.max_history_size = 50 + + # 自适应参数 + self.adaptive_gain = 1.0 + self.adaptive_threshold = 0.2 + + # 多源检测 + self.max_sources = 3 + self.source_tracking = {} + + self.logger.info("声源定位器初始化完成") + + def _calculate_mic_positions(self) -> List[Tuple[float, float]]: + """计算麦克风阵列位置""" + # 假设麦克风阵列为圆形排列,半径为0.1米 + radius = 0.1 + mic_count = 4 + positions = [] + + for i in range(mic_count): + angle = 2 * math.pi * i / mic_count + x = radius * math.cos(angle) + y = radius * math.sin(angle) + positions.append((x, y)) + + return positions + + def process_audio_frame(self, audio_data: List[float]) -> Optional[LocationData]: + """处理音频帧,返回定位结果""" + try: + # 1. 信号预处理 + processed_data = self._preprocess_audio(audio_data) + if processed_data is None: + return None + + # 2. 时延估计 + delays = self._estimate_time_delays(processed_data) + if delays is None: + return None + + # 3. 声源定位 + raw_location = self._locate_source(delays) + if raw_location is None: + return None + + # 4. 卡尔曼滤波 + filtered_location = self._apply_kalman_filter(raw_location) + + # 5. 后处理 + final_location = self._post_process_location(filtered_location) + + # 6. 更新历史 + self._update_location_history(final_location) + + return final_location + + except Exception as e: + self.logger.error(f"音频帧处理失败: {e}") + return None + + def _preprocess_audio(self, audio_data: List[float]) -> Optional[List[List[float]]]: + """音频预处理""" + try: + # 检查数据有效性 + if len(audio_data) < self.frame_size * len(self.mic_positions): + return None + + # 分离各麦克风数据 + mic_data = [] + samples_per_mic = len(audio_data) // len(self.mic_positions) + + for i in range(len(self.mic_positions)): + start_idx = i * samples_per_mic + end_idx = start_idx + samples_per_mic + mic_data.append(audio_data[start_idx:end_idx]) + + # 应用窗函数 + window = np.hanning(self.frame_size) + for i in range(len(mic_data)): + if len(mic_data[i]) >= self.frame_size: + mic_data[i] = mic_data[i][:self.frame_size] * window + + # 噪声抑制 + for i in range(len(mic_data)): + mic_data[i] = self._noise_reduction(mic_data[i]) + + return mic_data + + except Exception as e: + self.logger.error(f"音频预处理失败: {e}") + return None + + def _noise_reduction(self, audio_data: List[float]) -> List[float]: + """噪声抑制""" + try: + # 计算信号能量 + energy = np.mean(np.array(audio_data) ** 2) + + # 自适应阈值 + threshold = self.adaptive_threshold * self.adaptive_gain + + # 如果信号能量低于阈值,认为是噪声 + if energy < threshold: + return [0.0] * len(audio_data) + + # 频谱减法降噪 + fft_data = np.fft.fft(audio_data) + magnitude = np.abs(fft_data) + phase = np.angle(fft_data) + + # 估计噪声谱 + noise_spectrum = self._estimate_noise_spectrum(magnitude) + + # 频谱减法 + clean_magnitude = magnitude - noise_spectrum + clean_magnitude = np.maximum(clean_magnitude, 0.1 * magnitude) + + # 重建信号 + clean_fft = clean_magnitude * np.exp(1j * phase) + clean_audio = np.real(np.fft.ifft(clean_fft)) + + return clean_audio.tolist() + + except Exception as e: + self.logger.error(f"噪声抑制失败: {e}") + return audio_data + + def _estimate_noise_spectrum(self, magnitude: np.ndarray) -> np.ndarray: + """估计噪声谱""" + # 简单的噪声谱估计,假设低频部分为噪声 + noise_spectrum = np.zeros_like(magnitude) + noise_spectrum[:len(magnitude)//4] = np.mean(magnitude[:len(magnitude)//4]) + return noise_spectrum + + def _estimate_time_delays(self, mic_data: List[List[float]]) -> Optional[List[float]]: + """估计时延""" + try: + if len(mic_data) < 2: + return None + + delays = [] + ref_mic = mic_data[0] + + for i in range(1, len(mic_data)): + # 计算互相关 + correlation = np.correlate(mic_data[i], ref_mic, mode='full') + + # 找到最大相关点 + max_idx = np.argmax(correlation) + + # 计算时延 + delay = (max_idx - len(ref_mic) + 1) / self.sample_rate + delays.append(delay) + + return delays + + except Exception as e: + self.logger.error(f"时延估计失败: {e}") + return None + + def _locate_source(self, delays: List[float]) -> Optional[LocationData]: + """声源定位""" + try: + if len(delays) < 2: + return None + + # 使用TDOA (Time Difference of Arrival) 方法 + # 构建线性方程组 + A = [] + b = [] + + for i in range(len(delays)): + dx = self.mic_positions[i+1][0] - self.mic_positions[0][0] + dy = self.mic_positions[i+1][1] - self.mic_positions[0][1] + dt = delays[i] + + A.append([2*dx, 2*dy]) + b.append(dx**2 + dy**2 - (self.sound_speed * dt)**2) + + # 最小二乘解 + A = np.array(A) + b = np.array(b) + + try: + x, residuals, rank, s = np.linalg.lstsq(A, b, rcond=None) + source_x, source_y = x[0], x[1] + except: + # 如果最小二乘失败,使用几何方法 + source_x, source_y = self._geometric_localization(delays) + + # 计算信号强度 + strength = self._calculate_signal_strength(delays) + + # 计算置信度 + confidence = self._calculate_confidence(delays, source_x, source_y) + + return LocationData( + x=source_x, + y=source_y, + strength=strength, + angle=math.degrees(math.atan2(source_y, source_x)), + timestamp=time.time(), + confidence=confidence, + quality=self._calculate_quality(delays), + noise_level=self._estimate_noise_level(delays), + source_type="speech" + ) + + except Exception as e: + self.logger.error(f"声源定位失败: {e}") + return None + + def _geometric_localization(self, delays: List[float]) -> Tuple[float, float]: + """几何定位方法""" + try: + # 使用双曲线交点法 + if len(delays) >= 2: + # 简化的几何定位 + r1 = abs(delays[0]) * self.sound_speed + r2 = abs(delays[1]) * self.sound_speed + + # 假设声源在麦克风阵列中心附近 + source_x = (r1 - r2) / 2 + source_y = math.sqrt(max(0, r1**2 - source_x**2)) + + return source_x, source_y + else: + return 0.0, 0.0 + + except Exception as e: + self.logger.error(f"几何定位失败: {e}") + return 0.0, 0.0 + + def _calculate_signal_strength(self, delays: List[float]) -> float: + """计算信号强度""" + try: + # 基于时延一致性计算信号强度 + if len(delays) < 2: + return 0.0 + + # 计算时延的标准差 + delay_std = np.std(delays) + + # 信号强度与标准差成反比 + strength = max(0.0, 1.0 - delay_std / 0.01) + + return strength + + except Exception as e: + self.logger.error(f"信号强度计算失败: {e}") + return 0.0 + + def _calculate_confidence(self, delays: List[float], x: float, y: float) -> float: + """计算定位置信度""" + try: + # 基于多个因素计算置信度 + factors = [] + + # 1. 时延一致性 + if len(delays) > 1: + delay_consistency = 1.0 - min(1.0, np.std(delays) / 0.01) + factors.append(delay_consistency) + + # 2. 距离合理性 + distance = math.sqrt(x**2 + y**2) + distance_factor = 1.0 - min(1.0, distance / 10.0) # 假设最大距离10米 + factors.append(distance_factor) + + # 3. 信号强度 + strength_factor = self._calculate_signal_strength(delays) + factors.append(strength_factor) + + # 综合置信度 + confidence = np.mean(factors) if factors else 0.0 + + return max(0.0, min(1.0, confidence)) + + except Exception as e: + self.logger.error(f"置信度计算失败: {e}") + return 0.0 + + def _calculate_quality(self, delays: List[float]) -> float: + """计算定位质量""" + try: + # 基于时延估计的质量 + if len(delays) < 2: + return 0.0 + + # 计算时延的SNR + signal_power = np.mean(np.array(delays) ** 2) + noise_power = np.var(delays) + + if noise_power > 0: + snr = 10 * math.log10(signal_power / noise_power) + quality = min(1.0, max(0.0, (snr + 20) / 40)) # 映射到0-1 + else: + quality = 1.0 + + return quality + + except Exception as e: + self.logger.error(f"质量计算失败: {e}") + return 0.0 + + def _estimate_noise_level(self, delays: List[float]) -> float: + """估计噪声水平""" + try: + if len(delays) < 2: + return 1.0 + + # 基于时延变化估计噪声 + noise_level = np.std(delays) / 0.01 # 归一化 + return min(1.0, max(0.0, noise_level)) + + except Exception as e: + self.logger.error(f"噪声水平估计失败: {e}") + return 1.0 + + def _apply_kalman_filter(self, location: LocationData) -> LocationData: + """应用卡尔曼滤波""" + try: + # 预测步骤 + self.kalman_filter.predict() + + # 更新步骤 + measurement = np.array([location.x, location.y]) + self.kalman_filter.update(measurement) + + # 获取滤波后的状态 + filtered_state = self.kalman_filter.get_state() + + # 更新定位数据 + location.x = filtered_state['x'] + location.y = filtered_state['y'] + location.angle = math.degrees(math.atan2(location.y, location.x)) + + return location + + except Exception as e: + self.logger.error(f"卡尔曼滤波失败: {e}") + return location + + def _post_process_location(self, location: LocationData) -> LocationData: + """后处理定位结果""" + try: + # 1. 异常值检测 + if self._is_outlier(location): + location = self._get_robust_location() + + # 2. 平滑处理 + location = self._smooth_location(location) + + # 3. 多源检测 + location = self._detect_multiple_sources(location) + + # 4. 自适应参数更新 + self._update_adaptive_parameters(location) + + return location + + except Exception as e: + self.logger.error(f"后处理失败: {e}") + return location + + def _is_outlier(self, location: LocationData) -> bool: + """检测异常值""" + try: + if len(self.location_history) < 3: + return False + + # 计算与历史位置的距离 + recent_locations = self.location_history[-3:] + distances = [] + + for hist_loc in recent_locations: + dist = math.sqrt((location.x - hist_loc.x)**2 + (location.y - hist_loc.y)**2) + distances.append(dist) + + # 如果距离过大,认为是异常值 + avg_distance = np.mean(distances) + return avg_distance > 2.0 # 2米阈值 + + except Exception as e: + self.logger.error(f"异常值检测失败: {e}") + return False + + def _get_robust_location(self) -> LocationData: + """获取鲁棒定位结果""" + try: + if len(self.location_history) < 2: + return LocationData(0, 0, 0, 0, time.time()) + + # 使用中位数滤波 + recent_locations = self.location_history[-5:] + x_values = [loc.x for loc in recent_locations] + y_values = [loc.y for loc in recent_locations] + + robust_x = np.median(x_values) + robust_y = np.median(y_values) + + return LocationData( + x=robust_x, + y=robust_y, + strength=0.5, + angle=math.degrees(math.atan2(robust_y, robust_x)), + timestamp=time.time(), + confidence=0.5, + quality=0.5, + noise_level=0.5, + source_type="estimated" + ) + + except Exception as e: + self.logger.error(f"鲁棒定位失败: {e}") + return LocationData(0, 0, 0, 0, time.time()) + + def _smooth_location(self, location: LocationData) -> LocationData: + """平滑定位结果""" + try: + if len(self.location_history) < 2: + return location + + # 指数平滑 + alpha = 0.7 # 平滑系数 + last_location = self.location_history[-1] + + smoothed_x = alpha * location.x + (1 - alpha) * last_location.x + smoothed_y = alpha * location.y + (1 - alpha) * last_location.y + + location.x = smoothed_x + location.y = smoothed_y + location.angle = math.degrees(math.atan2(location.y, location.x)) + + return location + + except Exception as e: + self.logger.error(f"平滑处理失败: {e}") + return location + + def _detect_multiple_sources(self, location: LocationData) -> LocationData: + """多源检测""" + try: + # 简单的多源检测逻辑 + current_time = time.time() + + # 检查是否有多个声源 + if len(self.source_tracking) > 0: + # 更新现有声源 + for source_id, source_info in list(self.source_tracking.items()): + if current_time - source_info['last_seen'] > 2.0: # 2秒超时 + del self.source_tracking[source_id] + else: + # 检查是否与当前检测匹配 + dist = math.sqrt((location.x - source_info['x'])**2 + + (location.y - source_info['y'])**2) + if dist < 1.0: # 1米内认为是同一声源 + source_info['x'] = location.x + source_info['y'] = location.y + source_info['last_seen'] = current_time + location.source_type = f"source_{source_id}" + return location + + # 添加新声源 + if len(self.source_tracking) < self.max_sources: + source_id = len(self.source_tracking) + 1 + self.source_tracking[source_id] = { + 'x': location.x, + 'y': location.y, + 'last_seen': current_time + } + location.source_type = f"source_{source_id}" + + return location + + except Exception as e: + self.logger.error(f"多源检测失败: {e}") + return location + + def _update_adaptive_parameters(self, location: LocationData): + """更新自适应参数""" + try: + # 根据定位质量调整参数 + if location.quality > 0.8: + self.adaptive_gain *= 1.05 # 提高增益 + elif location.quality < 0.3: + self.adaptive_gain *= 0.95 # 降低增益 + + # 限制增益范围 + self.adaptive_gain = max(0.1, min(2.0, self.adaptive_gain)) + + # 根据噪声水平调整阈值 + if location.noise_level > 0.7: + self.adaptive_threshold *= 1.1 + elif location.noise_level < 0.3: + self.adaptive_threshold *= 0.9 + + # 限制阈值范围 + self.adaptive_threshold = max(0.05, min(0.5, self.adaptive_threshold)) + + except Exception as e: + self.logger.error(f"自适应参数更新失败: {e}") + + def _update_location_history(self, location: LocationData): + """更新定位历史""" + try: + self.location_history.append(location) + + # 限制历史记录大小 + if len(self.location_history) > self.max_history_size: + self.location_history = self.location_history[-self.max_history_size:] + + except Exception as e: + self.logger.error(f"历史记录更新失败: {e}") + + def get_location_statistics(self) -> Dict[str, Any]: + """获取定位统计信息""" + try: + if len(self.location_history) < 2: + return {} + + # 计算定位精度统计 + x_values = [loc.x for loc in self.location_history] + y_values = [loc.y for loc in self.location_history] + confidence_values = [loc.confidence for loc in self.location_history] + quality_values = [loc.quality for loc in self.location_history] + + stats = { + 'total_locations': len(self.location_history), + 'avg_confidence': np.mean(confidence_values), + 'avg_quality': np.mean(quality_values), + 'x_std': np.std(x_values), + 'y_std': np.std(y_values), + 'position_stability': 1.0 / (1.0 + np.std(x_values) + np.std(y_values)), + 'adaptive_gain': self.adaptive_gain, + 'adaptive_threshold': self.adaptive_threshold, + 'active_sources': len(self.source_tracking) + } + + return stats + + except Exception as e: + self.logger.error(f"统计信息计算失败: {e}") + return {} + + def reset(self): + """重置定位器""" + try: + self.kalman_filter.reset() + self.location_history.clear() + self.source_tracking.clear() + self.adaptive_gain = 1.0 + self.adaptive_threshold = 0.2 + + self.logger.info("声源定位器已重置") + + except Exception as e: + self.logger.error(f"定位器重置失败: {e}") + +# ========== 枪声检测类 ========== +class GunshotDetector: + """枪声检测器,用于在定位模式下过滤非枪声信号""" + + def __init__(self, config: AudioConfig): + self.config = config + self.logger = Logger("GunshotDetector") + + # 检测参数 + self.detection_threshold = 0.3 # 检测阈值 + self.min_duration = 0.05 # 最小持续时间(秒) + self.max_duration = 0.5 # 最大持续时间(秒) + self.sample_rate = config.sample_rate + self.frame_size = config.chunk_size + + # 特征提取参数 + self.energy_threshold = 1000 # 能量阈值 + self.spectral_centroid_range = (1000, 8000) # 频谱质心范围 + self.zero_crossing_threshold = 0.1 # 过零率阈值 + + # 检测历史 + self.detection_history = [] + self.max_history_size = 50 + + # 自适应参数 + self.adaptive_threshold = self.detection_threshold + self.noise_floor = 100 + self.signal_ceiling = 30000 + + self.logger.info("枪声检测器初始化完成") + + def detect_gunshot(self, audio_data: List[float]) -> Dict[str, Any]: + """检测音频中是否包含枪声""" + try: + if len(audio_data) < self.frame_size: + return {'is_gunshot': False, 'confidence': 0.0, 'features': {}} + + # 1. 提取特征 + features = self._extract_features(audio_data) + + # 2. 计算检测分数 + detection_score = self._calculate_detection_score(features) + + # 3. 判断是否为枪声 + is_gunshot = detection_score > self.adaptive_threshold + + # 4. 更新自适应参数 + self._update_adaptive_parameters(features, detection_score) + + # 5. 更新检测历史 + self._update_detection_history(is_gunshot, detection_score, features) + + result = { + 'is_gunshot': is_gunshot, + 'confidence': detection_score, + 'features': features, + 'threshold': self.adaptive_threshold, + 'timestamp': time.time() + } + + if is_gunshot: + self.logger.info(f"检测到枪声!置信度: {detection_score:.3f}") + + return result + + except Exception as e: + self.logger.error(f"枪声检测失败: {e}") + return {'is_gunshot': False, 'confidence': 0.0, 'features': {}} + + def _extract_features(self, audio_data: List[float]) -> Dict[str, float]: + """提取音频特征""" + try: + audio_array = np.array(audio_data, dtype=np.float32) + + # 1. 能量特征 + energy = np.mean(audio_array ** 2) + rms = np.sqrt(energy) + + # 2. 频谱特征 + fft_data = np.fft.fft(audio_array) + magnitude = np.abs(fft_data) + + # 频谱质心 + freqs = np.fft.fftfreq(len(audio_array), 1/self.sample_rate) + spectral_centroid = np.sum(freqs * magnitude) / np.sum(magnitude) + + # 频谱带宽 + spectral_bandwidth = np.sqrt(np.sum(((freqs - spectral_centroid) ** 2) * magnitude) / np.sum(magnitude)) + + # 3. 时域特征 + # 过零率 + zero_crossings = np.sum(np.diff(np.sign(audio_array)) != 0) + zero_crossing_rate = zero_crossings / len(audio_array) + + # 峰值因子 + peak_factor = np.max(np.abs(audio_array)) / rms if rms > 0 else 0 + + # 4. 包络特征 + # 希尔伯特变换获取包络 + analytic_signal = np.fft.hilbert(audio_array) + envelope = np.abs(analytic_signal) + envelope_mean = np.mean(envelope) + envelope_std = np.std(envelope) + + features = { + 'energy': energy, + 'rms': rms, + 'spectral_centroid': spectral_centroid, + 'spectral_bandwidth': spectral_bandwidth, + 'zero_crossing_rate': zero_crossing_rate, + 'peak_factor': peak_factor, + 'envelope_mean': envelope_mean, + 'envelope_std': envelope_std + } + + return features + + except Exception as e: + self.logger.error(f"特征提取失败: {e}") + return {} + + def _calculate_detection_score(self, features: Dict[str, float]) -> float: + """计算检测分数""" + try: + if not features: + return 0.0 + + score = 0.0 + weights = { + 'energy': 0.3, + 'spectral_centroid': 0.25, + 'peak_factor': 0.2, + 'envelope_std': 0.15, + 'zero_crossing_rate': 0.1 + } + + # 1. 能量分数 + if 'energy' in features: + energy_score = min(1.0, features['energy'] / self.signal_ceiling) + score += weights['energy'] * energy_score + + # 2. 频谱质心分数 + if 'spectral_centroid' in features: + centroid = features['spectral_centroid'] + min_centroid, max_centroid = self.spectral_centroid_range + if min_centroid <= centroid <= max_centroid: + centroid_score = 1.0 + else: + centroid_score = 0.0 + score += weights['spectral_centroid'] * centroid_score + + # 3. 峰值因子分数 + if 'peak_factor' in features: + peak_factor = features['peak_factor'] + if peak_factor > 5.0: # 枪声通常有较高的峰值因子 + peak_score = min(1.0, peak_factor / 20.0) + else: + peak_score = 0.0 + score += weights['peak_factor'] * peak_score + + # 4. 包络标准差分数 + if 'envelope_std' in features: + envelope_std = features['envelope_std'] + if envelope_std > 1000: # 枪声包络变化较大 + envelope_score = min(1.0, envelope_std / 5000) + else: + envelope_score = 0.0 + score += weights['envelope_std'] * envelope_score + + # 5. 过零率分数 + if 'zero_crossing_rate' in features: + zcr = features['zero_crossing_rate'] + if zcr < self.zero_crossing_threshold: # 枪声过零率较低 + zcr_score = 1.0 - (zcr / self.zero_crossing_threshold) + else: + zcr_score = 0.0 + score += weights['zero_crossing_rate'] * zcr_score + + return min(1.0, max(0.0, score)) + + except Exception as e: + self.logger.error(f"检测分数计算失败: {e}") + return 0.0 + + def _update_adaptive_parameters(self, features: Dict[str, float], detection_score: float): + """更新自适应参数""" + try: + # 更新噪声水平 + if 'rms' in features: + rms = features['rms'] + if rms < self.signal_ceiling: + self.noise_floor = 0.9 * self.noise_floor + 0.1 * rms + + # 更新检测阈值 + if detection_score > 0.5: + # 检测到强信号,降低阈值 + self.adaptive_threshold *= 0.95 + elif detection_score < 0.1: + # 检测到弱信号,提高阈值 + self.adaptive_threshold *= 1.05 + + # 限制阈值范围 + self.adaptive_threshold = max(0.1, min(0.8, self.adaptive_threshold)) + + except Exception as e: + self.logger.error(f"自适应参数更新失败: {e}") + + def _update_detection_history(self, is_gunshot: bool, confidence: float, features: Dict[str, float]): + """更新检测历史""" + try: + history_entry = { + 'is_gunshot': is_gunshot, + 'confidence': confidence, + 'features': features, + 'timestamp': time.time() + } + + self.detection_history.append(history_entry) + + # 限制历史记录大小 + if len(self.detection_history) > self.max_history_size: + self.detection_history = self.detection_history[-self.max_history_size:] + + except Exception as e: + self.logger.error(f"检测历史更新失败: {e}") + + def get_detection_stats(self) -> Dict[str, Any]: + """获取检测统计信息""" + try: + if not self.detection_history: + return {} + + total_detections = len(self.detection_history) + gunshot_detections = sum(1 for entry in self.detection_history if entry['is_gunshot']) + + confidences = [entry['confidence'] for entry in self.detection_history] + + stats = { + 'total_detections': total_detections, + 'gunshot_detections': gunshot_detections, + 'detection_rate': gunshot_detections / total_detections if total_detections > 0 else 0, + 'avg_confidence': np.mean(confidences) if confidences else 0, + 'max_confidence': np.max(confidences) if confidences else 0, + 'adaptive_threshold': self.adaptive_threshold, + 'noise_floor': self.noise_floor + } + + return stats + + except Exception as e: + self.logger.error(f"获取检测统计失败: {e}") + return {} + + def reset(self): + """重置检测器""" + try: + self.detection_history.clear() + self.adaptive_threshold = self.detection_threshold + self.noise_floor = 100 + self.logger.info("枪声检测器已重置") + except Exception as e: + self.logger.error(f"检测器重置失败: {e}") + +def main(): + """主函数""" + print("=== 声源定位系统 - 开发板端(K210) ===") + print("正在初始化...") + + try: + board = DevelopmentBoard() + board.run() + except Exception as e: + print(f"程序启动失败: {e}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/声源定位代码/back-code/pc_server.py b/src/声源定位代码/back-code/pc_server.py new file mode 100644 index 0000000..d84eaf4 --- /dev/null +++ b/src/声源定位代码/back-code/pc_server.py @@ -0,0 +1,2078 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +PC端服务器程序 - 声源定位系统 +功能: +1. 接收开发板发送的音频数据 +2. 使用audio-classification进行枪声识别 +3. 当识别到枪声时,发送指令给开发板切换到定位模式 +4. 接收开发板发送的声源定位数据并可视化 +5. 实时显示声源位置和轨迹 + +作者: 声源定位系统开发团队 +版本: 2.0.0 +日期: 2025 +""" + +import socket +import threading +import time +import wave +import tempfile +import os +import sys +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.animation import FuncAnimation +import queue +import json +import logging +import configparser +from datetime import datetime +from typing import Optional, Dict, Any, Tuple, List +from dataclasses import dataclass +from enum import Enum +import traceback +import signal +import atexit + +# Flask相关导入 +try: + from flask import Flask, jsonify + from flask_cors import CORS + FLASK_AVAILABLE = True +except ImportError: + print("警告: Flask模块未找到,HTTP API功能将不可用") + FLASK_AVAILABLE = False + +# 添加audio-classification项目路径 +sys.path.append(os.path.join(os.path.dirname(__file__), 'audio-classification')) + +try: + from macls.predict import MAClsPredictor + AUDIO_CLASSIFICATION_AVAILABLE = True +except ImportError: + print("警告: audio-classification模块未找到,将使用模拟识别") + AUDIO_CLASSIFICATION_AVAILABLE = False + +# ========== 枚举定义 ========== +class SystemMode(Enum): + """系统运行模式枚举""" + LISTENING = "LISTENING" # 监听模式 + LOCATING = "LOCATING" # 定位模式 + ERROR = "ERROR" # 错误模式 + SHUTDOWN = "SHUTDOWN" # 关闭模式 + +class ConnectionStatus(Enum): + """连接状态枚举""" + DISCONNECTED = "DISCONNECTED" + CONNECTING = "CONNECTING" + CONNECTED = "CONNECTED" + ERROR = "ERROR" + +# ========== 数据类定义 ========== +@dataclass +class LocationData: + """定位数据结构""" + x: float + y: float + strength: float + angle: float + timestamp: float + confidence: float = 1.0 + + def __post_init__(self): + """数据验证""" + if not isinstance(self.x, (int, float)) or not isinstance(self.y, (int, float)): + raise ValueError("坐标必须是数值类型") + if not isinstance(self.strength, (int, float)) or self.strength < 0: + raise ValueError("强度必须是非负数值") + if not isinstance(self.angle, (int, float)): + raise ValueError("角度必须是数值类型") + +@dataclass +class AudioConfig: + """音频配置""" + sample_rate: int = 16000 + channels: int = 1 + chunk_size: int = 1024 + format: str = "int16" + + def validate(self) -> bool: + """验证配置有效性""" + if self.sample_rate <= 0: + raise ValueError("采样率必须大于0") + if self.channels not in [1, 2]: + raise ValueError("声道数必须是1或2") + if self.chunk_size <= 0: + raise ValueError("音频块大小必须大于0") + return True + +@dataclass +class NetworkConfig: + """网络配置""" + host: str = "0.0.0.0" + port_audio: int = 12346 + port_cmd: int = 12347 + port_location: int = 12348 + timeout: float = 30.0 + buffer_size: int = 4096 + + def validate(self) -> bool: + """验证配置有效性""" + if not (1024 <= self.port_audio <= 65535): + raise ValueError("音频端口必须在1024-65535范围内") + if not (1024 <= self.port_cmd <= 65535): + raise ValueError("指令端口必须在1024-65535范围内") + if not (1024 <= self.port_location <= 65535): + raise ValueError("定位端口必须在1024-65535范围内") + if self.timeout <= 0: + raise ValueError("超时时间必须大于0") + return True + +# ========== 日志配置 ========== +def setup_logging(log_level: str = "INFO", log_file: str = "pc_server.log") -> logging.Logger: + """设置日志系统""" + # 创建日志目录 + log_dir = "logs" + os.makedirs(log_dir, exist_ok=True) + + # 配置日志格式 + log_format = "%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s" + date_format = "%Y-%m-%d %H:%M:%S" + + # 创建日志记录器 + logger = logging.getLogger("PCServer") + logger.setLevel(getattr(logging, log_level.upper())) + + # 清除现有的处理器 + logger.handlers.clear() + + # 文件处理器 + file_handler = logging.FileHandler( + os.path.join(log_dir, log_file), + encoding='utf-8' + ) + file_handler.setLevel(logging.DEBUG) + file_formatter = logging.Formatter(log_format, date_format) + file_handler.setFormatter(file_formatter) + logger.addHandler(file_handler) + + # 控制台处理器 + console_handler = logging.StreamHandler() + console_handler.setLevel(logging.INFO) + console_formatter = logging.Formatter( + "%(asctime)s - %(levelname)s - %(message)s", + date_format + ) + console_handler.setFormatter(console_formatter) + logger.addHandler(console_handler) + + return logger + +# ========== 配置管理 ========== +class ConfigManager: + """配置管理器""" + + def __init__(self, config_file: str = "config.ini"): + self.config_file = config_file + self.config = configparser.ConfigParser() + self.logger = logging.getLogger("ConfigManager") + self.load_config() + + def load_config(self) -> None: + """加载配置文件""" + try: + if os.path.exists(self.config_file): + self.config.read(self.config_file, encoding='utf-8') + self.logger.info(f"配置文件加载成功: {self.config_file}") + else: + self.create_default_config() + except Exception as e: + self.logger.error(f"加载配置文件失败: {e}") + self.create_default_config() + + def create_default_config(self) -> None: + """创建默认配置""" + self.config['NETWORK'] = { + 'host': '0.0.0.0', + 'port_audio': '12346', + 'port_cmd': '12347', + 'port_location': '12348', + 'timeout': '30.0', + 'buffer_size': '4096' + } + + self.config['AUDIO'] = { + 'sample_rate': '16000', + 'channels': '1', + 'chunk_size': '1024', + 'format': 'int16' + } + + self.config['RECOGNITION'] = { + 'gunshot_threshold': '0.7', + 'recognition_interval': '3.0', + 'configs_path': 'audio-classification/configs/cam++.yml', + 'model_path': 'audio-classification/models/CAMPPlus_Fbank/best_model/' + } + + self.config['VISUALIZATION'] = { + 'plot_interval_ms': '100', + 'plot_range': '15.0', + 'point_size': '200', + 'max_history_points': '100' + } + + self.config['KALMAN'] = { + 'q_x': '5.0', + 'r_x': '0.01', + 'q_y': '5.0', + 'r_y': '0.01', + 'q_strength': '5.0', + 'r_strength': '0.01', + 'q_angle': '5.0', + 'r_angle': '0.01' + } + + self.config['HTTP_API'] = { + 'enabled': 'True', + 'host': '0.0.0.0', + 'port': '5000', + 'cors_enabled': 'True' + } + + self.save_config() + + def save_config(self) -> None: + """保存配置文件""" + try: + with open(self.config_file, 'w', encoding='utf-8') as f: + self.config.write(f) + self.logger.info(f"配置文件保存成功: {self.config_file}") + except Exception as e: + self.logger.error(f"保存配置文件失败: {e}") + + def get_network_config(self) -> NetworkConfig: + """获取网络配置""" + try: + return NetworkConfig( + host=self.config.get('NETWORK', 'host'), + port_audio=self.config.getint('NETWORK', 'port_audio'), + port_cmd=self.config.getint('NETWORK', 'port_cmd'), + port_location=self.config.getint('NETWORK', 'port_location'), + timeout=self.config.getfloat('NETWORK', 'timeout'), + buffer_size=self.config.getint('NETWORK', 'buffer_size') + ) + except Exception as e: + self.logger.error(f"获取网络配置失败: {e}") + return NetworkConfig() + + def get_audio_config(self) -> AudioConfig: + """获取音频配置""" + try: + return AudioConfig( + sample_rate=self.config.getint('AUDIO', 'sample_rate'), + channels=self.config.getint('AUDIO', 'channels'), + chunk_size=self.config.getint('AUDIO', 'chunk_size'), + format=self.config.get('AUDIO', 'format') + ) + except Exception as e: + self.logger.error(f"获取音频配置失败: {e}") + return AudioConfig() + +# ========== 卡尔曼滤波器类 ========== +class KalmanFilter: + """卡尔曼滤波器类""" + + def __init__(self, initial_value: float = 0.0, q: float = 5.0, r: float = 0.01): + """ + 初始化卡尔曼滤波器 + + Args: + initial_value: 初始值 + q: 过程噪声协方差 + r: 测量噪声协方差 + """ + self.x_hat = initial_value # 状态估计 + self.p = 1000.0 # 估计误差协方差 + self.q = q # 过程噪声协方差 + self.r = r # 测量噪声协方差 + self.k = 0.0 # 卡尔曼增益 + + def update(self, measurement: float) -> float: + """ + 更新卡尔曼滤波器 + + Args: + measurement: 测量值 + + Returns: + 滤波后的值 + """ + try: + # 预测步骤 + p_pred = self.p + self.q + + # 更新步骤 + self.k = p_pred / (p_pred + self.r) + self.x_hat = self.x_hat + self.k * (measurement - self.x_hat) + self.p = (1 - self.k) * p_pred + + return self.x_hat + except Exception as e: + logging.error(f"卡尔曼滤波更新失败: {e}") + return measurement + + def reset(self, initial_value: float = 0.0) -> None: + """重置滤波器""" + self.x_hat = initial_value + self.p = 1000.0 + self.k = 0.0 + +class MultiKalmanFilter: + """多变量卡尔曼滤波器管理器""" + + def __init__(self, config: Dict[str, float]): + """ + 初始化多变量卡尔曼滤波器 + + Args: + config: 配置字典,包含各变量的Q和R值 + """ + self.filters = { + 'x': KalmanFilter(q=config.get('q_x', 5.0), r=config.get('r_x', 0.01)), + 'y': KalmanFilter(q=config.get('q_y', 5.0), r=config.get('r_y', 0.01)), + 'strength': KalmanFilter(q=config.get('q_strength', 5.0), r=config.get('r_strength', 0.01)), + 'angle': KalmanFilter(q=config.get('q_angle', 5.0), r=config.get('r_angle', 0.01)) + } + self.logger = logging.getLogger("MultiKalmanFilter") + + def filter_location_data(self, location_data: LocationData) -> LocationData: + """ + 对定位数据进行卡尔曼滤波 + + Args: + location_data: 原始定位数据 + + Returns: + 滤波后的定位数据 + """ + try: + filtered_x = self.filters['x'].update(location_data.x) + filtered_y = self.filters['y'].update(location_data.y) + filtered_strength = self.filters['strength'].update(location_data.strength) + filtered_angle = self.filters['angle'].update(location_data.angle) + + return LocationData( + x=filtered_x, + y=filtered_y, + strength=filtered_strength, + angle=filtered_angle, + timestamp=location_data.timestamp, + confidence=location_data.confidence + ) + except Exception as e: + self.logger.error(f"卡尔曼滤波失败: {e}") + return location_data + + def reset_all(self) -> None: + """重置所有滤波器""" + for filter_name, kalman_filter in self.filters.items(): + kalman_filter.reset() + self.logger.info("所有卡尔曼滤波器已重置") + +# ========== 声源定位后处理 ========== +class LocationPostProcessor: + """声源定位后处理,包括轨迹平滑、异常值剔除、历史统计等""" + def __init__(self, max_history: int = 100): + self.history: List[LocationData] = [] + self.max_history = max_history + self.logger = logging.getLogger("LocationPostProcessor") + + def process(self, location: LocationData) -> LocationData: + """对定位数据进行后处理""" + try: + # 1. 异常值剔除 + if self.is_outlier(location): + self.logger.warning(f"检测到异常定位点: x={location.x:.2f}, y={location.y:.2f}") + location = self.get_robust_location() + # 2. 轨迹平滑 + location = self.smooth_location(location) + # 3. 更新历史 + self.update_history(location) + return location + except Exception as e: + self.logger.error(f"定位后处理失败: {e}") + return location + + def is_outlier(self, location: LocationData) -> bool: + if len(self.history) < 3: + return False + recent = self.history[-3:] + dists = [np.hypot(location.x - l.x, location.y - l.y) for l in recent] + return np.mean(dists) > 5.0 # 5米阈值 + + def get_robust_location(self) -> LocationData: + if not self.history: + return LocationData(0, 0, 0, 0, time.time()) + xs = [l.x for l in self.history[-5:]] + ys = [l.y for l in self.history[-5:]] + return LocationData( + x=float(np.median(xs)), + y=float(np.median(ys)), + strength=0.5, + angle=0.0, + timestamp=time.time(), + confidence=0.5 + ) + + def smooth_location(self, location: LocationData) -> LocationData: + if not self.history: + return location + alpha = 0.7 + last = self.history[-1] + location.x = alpha * location.x + (1 - alpha) * last.x + location.y = alpha * location.y + (1 - alpha) * last.y + return location + + def update_history(self, location: LocationData): + self.history.append(location) + if len(self.history) > self.max_history: + self.history = self.history[-self.max_history:] + +# ========== 音频处理优化 ========== +class AudioProcessor: + """优化的音频处理器,支持批量处理、性能监控和智能缓冲""" + + def __init__(self, config: AudioConfig, recognition_config: Dict[str, Any]): + self.config = config + self.recognition_config = recognition_config + self.logger = logging.getLogger("AudioProcessor") + + # 音频缓冲管理 + self.audio_buffer = [] + self.buffer_lock = threading.Lock() + self.max_buffer_size = int(config.sample_rate * recognition_config['recognition_interval'] * 2) + self.min_buffer_size = int(config.sample_rate * recognition_config['recognition_interval'] * 0.5) + + # 性能监控 + self.processing_stats = { + 'total_audio_bytes': 0, + 'total_audio_frames': 0, + 'recognition_attempts': 0, + 'gunshot_detections': 0, + 'processing_times': [], + 'buffer_overflow_count': 0, + 'last_recognition_time': 0 + } + + # 音频质量检测 + self.quality_thresholds = { + 'min_rms': 50, # 最小RMS值 + 'max_rms': 30000, # 最大RMS值 + 'min_nonzero_ratio': 0.1, # 最小非零比例 + 'max_silence_ratio': 0.8 # 最大静音比例 + } + + # 预测器 + self.predictor = None + self._init_predictor() + + self.logger.info("音频处理器初始化完成") + + def _init_predictor(self): + """初始化音频分类预测器""" + if not AUDIO_CLASSIFICATION_AVAILABLE: + self.logger.warning("audio-classification模块未找到,将使用模拟识别") + return + + try: + configs_path = os.path.abspath(self.recognition_config['configs_path']) + model_path = os.path.abspath(self.recognition_config['model_path']) + + if not os.path.exists(configs_path): + self.logger.error(f"配置文件不存在: {configs_path}") + return + + if not os.path.exists(model_path): + self.logger.error(f"模型路径不存在: {model_path}") + return + + self.predictor = MAClsPredictor( + configs=configs_path, + model_path=model_path, + use_gpu=self.recognition_config['use_gpu'] + ) + + self.logger.info("音频分类预测器初始化成功") + + except Exception as e: + self.logger.error(f"音频分类预测器初始化失败: {e}") + self.predictor = None + + def add_audio_data(self, audio_data: bytes) -> bool: + """添加音频数据到缓冲区""" + try: + with self.buffer_lock: + # 转换为numpy数组 + audio_array = np.frombuffer(audio_data, dtype=np.int16) + + # 更新统计 + self.processing_stats['total_audio_bytes'] += len(audio_data) + self.processing_stats['total_audio_frames'] += len(audio_array) + + # 添加到缓冲区 + self.audio_buffer.extend(audio_array) + + # 检查缓冲区大小 + if len(self.audio_buffer) > self.max_buffer_size: + # 保留最新的数据 + self.audio_buffer = self.audio_buffer[-self.max_buffer_size:] + self.processing_stats['buffer_overflow_count'] += 1 + self.logger.warning("音频缓冲区溢出,丢弃旧数据") + + return True + + except Exception as e: + self.logger.error(f"添加音频数据失败: {e}") + return False + + def should_process_recognition(self) -> bool: + """判断是否应该进行识别""" + try: + current_time = time.time() + + # 检查时间间隔 + if (current_time - self.processing_stats['last_recognition_time'] < + self.recognition_config['recognition_interval']): + return False + + # 检查缓冲区大小 + with self.buffer_lock: + return len(self.audio_buffer) >= self.min_buffer_size + + except Exception as e: + self.logger.error(f"判断识别条件失败: {e}") + return False + + def process_recognition(self) -> Optional[Dict[str, Any]]: + """执行音频识别""" + try: + start_time = time.time() + + with self.buffer_lock: + # 获取音频数据 + if len(self.audio_buffer) < self.min_buffer_size: + return None + + # 提取识别所需的数据 + recognition_samples = int(self.config.sample_rate * self.recognition_config['recognition_interval']) + audio_segment = np.array(self.audio_buffer[-recognition_samples:]) + + # 清空缓冲区 + self.audio_buffer = [] + + # 检查音频质量 + if not self._check_audio_quality(audio_segment): + self.logger.debug("音频质量不满足识别要求") + return None + + # 执行识别 + result = self._perform_recognition(audio_segment) + + # 更新统计 + processing_time = time.time() - start_time + self.processing_stats['processing_times'].append(processing_time) + self.processing_stats['recognition_attempts'] += 1 + self.processing_stats['last_recognition_time'] = time.time() + + # 保持处理时间历史记录 + if len(self.processing_stats['processing_times']) > 100: + self.processing_stats['processing_times'] = self.processing_stats['processing_times'][-100:] + + if result and result.get('is_gunshot', False): + self.processing_stats['gunshot_detections'] += 1 + + self.logger.info(f"音频识别完成: {result}, 耗时: {processing_time:.3f}秒") + return result + + except Exception as e: + self.logger.error(f"音频识别失败: {e}") + return None + + def _check_audio_quality(self, audio_segment: np.ndarray) -> bool: + """检查音频质量""" + try: + if len(audio_segment) == 0: + return False + + # 计算RMS值 + rms = np.sqrt(np.mean(audio_segment.astype(np.float32) ** 2)) + + # 检查RMS范围 + if not (self.quality_thresholds['min_rms'] <= rms <= self.quality_thresholds['max_rms']): + return False + + # 检查非零比例 + nonzero_ratio = np.count_nonzero(audio_segment) / len(audio_segment) + if nonzero_ratio < self.quality_thresholds['min_nonzero_ratio']: + return False + + # 检查静音比例 + silence_threshold = 100 + silence_ratio = np.sum(np.abs(audio_segment) < silence_threshold) / len(audio_segment) + if silence_ratio > self.quality_thresholds['max_silence_ratio']: + return False + + return True + + except Exception as e: + self.logger.error(f"音频质量检查失败: {e}") + return False + + def _perform_recognition(self, audio_segment: np.ndarray) -> Optional[Dict[str, Any]]: + """执行实际的音频识别""" + try: + if self.predictor: + return self._perform_real_recognition(audio_segment) + else: + return self._perform_simulated_recognition(audio_segment) + + except Exception as e: + self.logger.error(f"执行识别失败: {e}") + return None + + def _perform_real_recognition(self, audio_segment: np.ndarray) -> Dict[str, Any]: + """执行真实音频识别""" + try: + # 保存为临时文件 + with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_file: + temp_path = temp_file.name + + # 保存音频文件 + with wave.open(temp_path, 'wb') as wav_file: + wav_file.setnchannels(self.config.channels) + wav_file.setsampwidth(2) # 16位 + wav_file.setframerate(self.config.sample_rate) + wav_file.writeframes(audio_segment.tobytes()) + + # 进行预测 + label, score = self.predictor.predict(audio_data=temp_path) + + # 清理临时文件 + try: + os.unlink(temp_path) + except Exception as e: + self.logger.warning(f"清理临时文件失败: {e}") + + # 判断是否为枪声 + is_gunshot = self._is_gunshot(label, score) + + return { + 'label': label, + 'score': score, + 'is_gunshot': is_gunshot, + 'confidence': score, + 'timestamp': time.time() + } + + except Exception as e: + self.logger.error(f"真实音频识别失败: {e}") + raise + + def _perform_simulated_recognition(self, audio_segment: np.ndarray) -> Dict[str, Any]: + """执行模拟音频识别""" + try: + # 模拟识别延迟 + time.sleep(0.05) + + # 基于音频特征进行简单判断 + rms = np.sqrt(np.mean(audio_segment.astype(np.float32) ** 2)) + + # 模拟检测逻辑 + detection_probability = 0.02 # 2%基础概率 + + # 根据RMS值调整概率 + if rms > 1000: + detection_probability += 0.03 + if rms > 5000: + detection_probability += 0.05 + + # 随机检测 + is_gunshot = np.random.random() < detection_probability + + return { + 'label': 'simulated_gunshot' if is_gunshot else 'simulated_normal', + 'score': 0.8 if is_gunshot else 0.2, + 'is_gunshot': is_gunshot, + 'confidence': 0.8 if is_gunshot else 0.2, + 'timestamp': time.time() + } + + except Exception as e: + self.logger.error(f"模拟音频识别失败: {e}") + return { + 'label': 'error', + 'score': 0.0, + 'is_gunshot': False, + 'confidence': 0.0, + 'timestamp': time.time() + } + + def _is_gunshot(self, label: str, score: float) -> bool: + """判断是否为枪声""" + try: + # 检查置信度阈值 + if score < self.recognition_config['gunshot_threshold']: + return False + + # 检查标签关键词 + gunshot_keywords = ['gun', 'shot', 'fire', 'gunshot', 'firearm', 'weapon', 'bang', 'explosion'] + label_lower = label.lower() + + for keyword in gunshot_keywords: + if keyword in label_lower: + return True + + return False + + except Exception as e: + self.logger.error(f"枪声判断失败: {e}") + return False + + def get_performance_stats(self) -> Dict[str, Any]: + """获取性能统计""" + try: + processing_times = self.processing_stats['processing_times'] + + stats = { + 'total_audio_bytes': self.processing_stats['total_audio_bytes'], + 'total_audio_frames': self.processing_stats['total_audio_frames'], + 'recognition_attempts': self.processing_stats['recognition_attempts'], + 'gunshot_detections': self.processing_stats['gunshot_detections'], + 'detection_rate': (self.processing_stats['gunshot_detections'] / + max(self.processing_stats['recognition_attempts'], 1)), + 'buffer_overflow_count': self.processing_stats['buffer_overflow_count'], + 'current_buffer_size': len(self.audio_buffer), + 'avg_processing_time': np.mean(processing_times) if processing_times else 0, + 'max_processing_time': np.max(processing_times) if processing_times else 0, + 'min_processing_time': np.min(processing_times) if processing_times else 0 + } + + return stats + + except Exception as e: + self.logger.error(f"获取性能统计失败: {e}") + return {} + +# ========== 通信优化 ========== +class CommunicationManager: + """优化的通信管理器,支持连接池、重试机制和性能监控""" + + def __init__(self, network_config: NetworkConfig): + self.network_config = network_config + self.logger = logging.getLogger("CommunicationManager") + + # 连接状态 + self.connections = { + 'audio': None, + 'cmd': None, + 'location': None + } + + # 连接统计 + self.connection_stats = { + 'total_sent': 0, + 'total_received': 0, + 'connection_attempts': 0, + 'connection_failures': 0, + 'last_heartbeat': 0 + } + + # 重试配置 + self.retry_config = { + 'max_retries': 3, + 'retry_delay': 1.0, + 'backoff_factor': 2.0 + } + + self.logger.info("通信管理器初始化完成") + + def accept_all_connections(self) -> bool: + """接受所有客户端连接""" + try: + self.logger.info("等待客户端连接...") + + # 并行接受连接 + connection_threads = [] + for conn_type in ['audio', 'cmd', 'location']: + thread = threading.Thread( + target=self._accept_connection, + args=(conn_type,), + name=f"Accept_{conn_type.capitalize()}", + daemon=True + ) + thread.start() + connection_threads.append(thread) + + # 等待所有连接完成 + for thread in connection_threads: + thread.join(timeout=30.0) + if thread.is_alive(): + self.logger.error(f"连接线程 {thread.name} 超时") + return False + + # 检查连接状态 + all_connected = all(conn is not None for conn in self.connections.values()) + + if all_connected: + self.logger.info("所有客户端连接成功") + self.connection_stats['last_heartbeat'] = time.time() + return True + else: + self.logger.error("部分客户端连接失败") + return False + + except Exception as e: + self.logger.error(f"接受连接失败: {e}") + return False + + def _accept_connection(self, conn_type: str): + """接受单个连接""" + try: + server_map = { + 'audio': self.network_config.port_audio, + 'cmd': self.network_config.port_cmd, + 'location': self.network_config.port_location + } + + port = server_map[conn_type] + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + server.settimeout(self.network_config.timeout) + + server.bind((self.network_config.host, port)) + server.listen(1) + + self.logger.info(f"等待{conn_type}客户端连接: {self.network_config.host}:{port}") + + client, addr = server.accept() + client.settimeout(self.network_config.timeout) + + self.connections[conn_type] = client + self.connection_stats['connection_attempts'] += 1 + + self.logger.info(f"{conn_type}客户端连接成功: {addr}") + + server.close() + + except Exception as e: + self.logger.error(f"接受{conn_type}连接失败: {e}") + self.connection_stats['connection_failures'] += 1 + self.connections[conn_type] = None + + def send_command(self, command: str, retry: bool = True) -> bool: + """发送指令到开发板""" + try: + if not self.connections['cmd']: + self.logger.error("指令连接未建立") + return False + + # 构建完整指令 + full_command = { + 'command': command, + 'timestamp': time.time(), + 'sequence': self.connection_stats['total_sent'] + } + + command_data = json.dumps(full_command).encode('utf-8') + + # 发送指令 + if retry: + return self._send_with_retry(command_data) + else: + self.connections['cmd'].send(command_data) + self.connection_stats['total_sent'] += 1 + return True + + except Exception as e: + self.logger.error(f"发送指令失败: {e}") + return False + + def _send_with_retry(self, data: bytes) -> bool: + """带重试机制的发送""" + for attempt in range(self.retry_config['max_retries']): + try: + self.connections['cmd'].send(data) + self.connection_stats['total_sent'] += 1 + return True + + except Exception as e: + self.logger.warning(f"发送失败 (尝试 {attempt + 1}/{self.retry_config['max_retries']}): {e}") + + if attempt < self.retry_config['max_retries'] - 1: + delay = self.retry_config['retry_delay'] * (self.retry_config['backoff_factor'] ** attempt) + time.sleep(delay) + + self.logger.error("发送失败,已达到最大重试次数") + return False + + def receive_audio_data(self) -> Optional[bytes]: + """接收音频数据""" + try: + if not self.connections['audio']: + return None + + data = self.connections['audio'].recv(self.network_config.buffer_size) + if data: + self.connection_stats['total_received'] += len(data) + return data + + except socket.timeout: + return None + except Exception as e: + self.logger.error(f"接收音频数据失败: {e}") + return None + + def receive_location_data(self) -> Optional[bytes]: + """接收定位数据""" + try: + if not self.connections['location']: + return None + + data = self.connections['location'].recv(self.network_config.buffer_size) + if data: + self.connection_stats['total_received'] += len(data) + return data + + except socket.timeout: + return None + except Exception as e: + self.logger.error(f"接收定位数据失败: {e}") + return None + + def send_heartbeat(self) -> bool: + """发送心跳""" + try: + heartbeat_data = { + 'type': 'heartbeat', + 'timestamp': time.time(), + 'stats': self.connection_stats.copy() + } + + return self.send_command(json.dumps(heartbeat_data), retry=False) + + except Exception as e: + self.logger.error(f"发送心跳失败: {e}") + return False + + def get_connection_stats(self) -> Dict[str, Any]: + """获取连接统计""" + try: + current_time = time.time() + + return { + 'connections': {k: v is not None for k, v in self.connections.items()}, + 'stats': self.connection_stats.copy(), + 'uptime': current_time - self.connection_stats['last_heartbeat'], + 'data_rate': self.connection_stats['total_received'] / max(current_time - self.connection_stats['last_heartbeat'], 1) + } + + except Exception as e: + self.logger.error(f"获取连接统计失败: {e}") + return {} + + def close_all_connections(self): + """关闭所有连接""" + try: + for conn_type, connection in self.connections.items(): + if connection: + try: + connection.close() + self.logger.info(f"关闭{conn_type}连接") + except Exception as e: + self.logger.error(f"关闭{conn_type}连接失败: {e}") + finally: + self.connections[conn_type] = None + + except Exception as e: + self.logger.error(f"关闭连接失败: {e}") + +# ========== 全局变量 ========== +logger = setup_logging() +config_manager = ConfigManager() +kalman_filter = MultiKalmanFilter({ + 'q_x': 5.0, 'r_x': 0.01, + 'q_y': 5.0, 'r_y': 0.01, + 'q_strength': 5.0, 'r_strength': 0.01, + 'q_angle': 5.0, 'r_angle': 0.01 +}) +location_post_processor = LocationPostProcessor() + +# ========== 主服务器类 ========== +class PCServer: + """PC端服务器主类""" + + def __init__(self): + """初始化PC服务器""" + self.logger = logging.getLogger("PCServer") + self.logger.info("开始初始化PC服务器...") + + # 系统状态 + self.running = True + self.current_mode = SystemMode.LISTENING + self.connection_status = { + 'audio': ConnectionStatus.DISCONNECTED, + 'cmd': ConnectionStatus.DISCONNECTED, + 'location': ConnectionStatus.DISCONNECTED + } + + # 配置 + self.network_config = config_manager.get_network_config() + self.audio_config = config_manager.get_audio_config() + self.recognition_config = self._load_recognition_config() + self.visualization_config = self._load_visualization_config() + self.http_api_config = self._load_http_api_config() + + # 验证配置 + self._validate_configs() + + # 初始化核心组件 + self.audio_processor = AudioProcessor(self.audio_config, self.recognition_config) + self.communication_manager = CommunicationManager(self.network_config) + + # 网络相关 + self.audio_server = None + self.cmd_server = None + self.location_server = None + + # 定位数据 + self.location_queue = queue.Queue(maxsize=1000) + self.location_history = [] + self.current_location = None + self.location_data_count = 0 + + # 新增:开发板枪声检测统计 + self.board_gunshot_stats = { + 'total_detections': 0, + 'gunshot_detections': 0, + 'detection_rate': 0.0, + 'avg_confidence': 0.0, + 'last_detection_time': 0 + } + + # 线程管理 + self.threads = [] + self.thread_lock = threading.Lock() + + # 性能监控 + self.performance_stats = { + 'start_time': time.time(), + 'audio_packets_received': 0, + 'location_packets_received': 0, + 'recognition_attempts': 0, + 'errors': 0, + 'board_gunshot_detections': 0 # 新增:开发板枪声检测次数 + } + + # HTTP API相关 + self.flask_app = None + self.flask_thread = None + if FLASK_AVAILABLE and self.http_api_config['enabled']: + self._init_flask_app() + + # 初始化各个模块 + try: + self._init_network_servers() + self._init_visualization() + self._init_data_structures() + + self.logger.info("PC服务器初始化完成") + self.logger.info(f"当前模式: {self.current_mode.value}") + self.logger.info(f"网络配置: {self.network_config}") + self.logger.info(f"音频配置: {self.audio_config}") + + except Exception as e: + self.logger.error(f"PC服务器初始化失败: {e}") + self.logger.error(traceback.format_exc()) + self.current_mode = SystemMode.ERROR + raise + + def _load_recognition_config(self) -> Dict[str, Any]: + """加载识别配置""" + try: + return { + 'gunshot_threshold': config_manager.config.getfloat('RECOGNITION', 'gunshot_threshold'), + 'recognition_interval': config_manager.config.getfloat('RECOGNITION', 'recognition_interval'), + 'configs_path': config_manager.config.get('RECOGNITION', 'configs_path'), + 'model_path': config_manager.config.get('RECOGNITION', 'model_path'), + 'use_gpu': True, + 'batch_size': 1 + } + except Exception as e: + self.logger.error(f"加载识别配置失败: {e}") + return { + 'gunshot_threshold': 0.7, + 'recognition_interval': 3.0, + 'configs_path': 'audio-classification/configs/cam++.yml', + 'model_path': 'audio-classification/models/CAMPPlus_Fbank/best_model/', + 'use_gpu': True, + 'batch_size': 1 + } + + def _load_visualization_config(self) -> Dict[str, Any]: + """加载可视化配置""" + try: + return { + 'plot_interval_ms': config_manager.config.getint('VISUALIZATION', 'plot_interval_ms'), + 'plot_range': config_manager.config.getfloat('VISUALIZATION', 'plot_range'), + 'point_size': config_manager.config.getint('VISUALIZATION', 'point_size'), + 'max_history_points': config_manager.config.getint('VISUALIZATION', 'max_history_points') + } + except Exception as e: + self.logger.error(f"加载可视化配置失败: {e}") + return { + 'plot_interval_ms': 100, + 'plot_range': 15.0, + 'point_size': 200, + 'max_history_points': 100 + } + + def _load_http_api_config(self) -> Dict[str, Any]: + """加载HTTP API配置""" + try: + return { + 'enabled': config_manager.config.getboolean('HTTP_API', 'enabled'), + 'host': config_manager.config.get('HTTP_API', 'host'), + 'port': config_manager.config.getint('HTTP_API', 'port'), + 'cors_enabled': config_manager.config.getboolean('HTTP_API', 'cors_enabled') + } + except Exception as e: + self.logger.error(f"加载HTTP API配置失败: {e}") + return { + 'enabled': True, + 'host': '0.0.0.0', + 'port': 5000, + 'cors_enabled': True + } + + def _validate_configs(self) -> None: + """验证配置有效性""" + try: + self.network_config.validate() + self.audio_config.validate() + + # 验证识别配置 + if self.recognition_config['gunshot_threshold'] < 0 or self.recognition_config['gunshot_threshold'] > 1: + raise ValueError("枪声识别阈值必须在0-1之间") + if self.recognition_config['recognition_interval'] <= 0: + raise ValueError("识别间隔必须大于0") + + # 验证可视化配置 + if self.visualization_config['plot_interval_ms'] <= 0: + raise ValueError("绘图间隔必须大于0") + if self.visualization_config['plot_range'] <= 0: + raise ValueError("绘图范围必须大于0") + if self.visualization_config['max_history_points'] <= 0: + raise ValueError("历史点数量必须大于0") + + self.logger.info("配置验证通过") + + except Exception as e: + self.logger.error(f"配置验证失败: {e}") + raise + + def _init_network_servers(self) -> None: + """初始化网络服务器""" + try: + # 音频接收服务器 + self.audio_server = self._create_server_socket( + self.network_config.host, + self.network_config.port_audio, + "音频接收" + ) + + # 指令发送服务器 + self.cmd_server = self._create_server_socket( + self.network_config.host, + self.network_config.port_cmd, + "指令发送" + ) + + # 定位数据接收服务器 + self.location_server = self._create_server_socket( + self.network_config.host, + self.network_config.port_location, + "定位数据接收" + ) + + self.logger.info("所有网络服务器初始化成功") + + except Exception as e: + self.logger.error(f"网络服务器初始化失败: {e}") + self.logger.error(traceback.format_exc()) + self._cleanup_network_servers() + raise + + def _create_server_socket(self, host: str, port: int, server_name: str) -> socket.socket: + """创建服务器套接字""" + try: + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + server.settimeout(self.network_config.timeout) + + server.bind((host, port)) + server.listen(1) + + self.logger.info(f"{server_name}服务器启动: {host}:{port}") + return server + + except Exception as e: + self.logger.error(f"创建{server_name}服务器失败: {e}") + raise + + def _init_visualization(self) -> None: + """初始化可视化""" + try: + # 设置中文字体 + plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans'] + plt.rcParams['axes.unicode_minus'] = False + + # 创建图形 + self.fig, self.ax = plt.subplots(figsize=(12, 10)) + self.ax.set_title("实时声源定位地图", fontsize=16, fontweight='bold') + self.ax.set_xlabel("X 坐标 (米)", fontsize=12) + self.ax.set_ylabel("Y 坐标 (米)", fontsize=12) + self.ax.set_xlim(-self.visualization_config['plot_range'], self.visualization_config['plot_range']) + self.ax.set_ylim(-self.visualization_config['plot_range'], self.visualization_config['plot_range']) + self.ax.grid(True, alpha=0.3) + + # 坐标轴辅助线 + self.ax.axhline(0, color='gray', linestyle='--', alpha=0.5) + self.ax.axvline(0, color='gray', linestyle='--', alpha=0.5) + + # 探测器位置标记 + self.ax.scatter([0], [0], c='red', s=100, marker='s', + label='声源探测器位置', edgecolors='black', linewidth=2) + + # 初始化散点图 + self.scat = self.ax.scatter([], [], c=[], cmap='viridis', + s=self.visualization_config['point_size'], + alpha=0.8, vmin=0, vmax=10, + edgecolors='black', linewidth=1) + + # 添加颜色条 + cbar = plt.colorbar(self.scat, ax=self.ax) + cbar.set_label('信号强度', fontsize=10) + + # 添加图例 + self.ax.legend(loc='upper right', fontsize=10) + + # 创建动画 + self.ani = FuncAnimation( + self.fig, + self.update_plot, + interval=self.visualization_config['plot_interval_ms'], + cache_frame_data=False, + blit=True + ) + + self.logger.info("可视化系统初始化成功") + + except Exception as e: + self.logger.error(f"可视化系统初始化失败: {e}") + self.logger.error(traceback.format_exc()) + raise + + def _init_data_structures(self) -> None: + """初始化数据结构""" + try: + # 清空历史数据 + self.location_history.clear() + self.audio_processor.audio_buffer.clear() + + # 重置计数器 + self.recognition_count = 0 + self.gunshot_detected_count = 0 + self.location_data_count = 0 + + # 重置性能统计 + self.performance_stats = { + 'start_time': time.time(), + 'audio_packets_received': 0, + 'location_packets_received': 0, + 'recognition_attempts': 0, + 'errors': 0, + 'board_gunshot_detections': 0 # 新增:开发板枪声检测次数 + } + + self.logger.info("数据结构初始化完成") + + except Exception as e: + self.logger.error(f"数据结构初始化失败: {e}") + raise + + def _cleanup_network_servers(self) -> None: + """清理网络服务器资源""" + servers = [ + (self.audio_server, "音频服务器"), + (self.cmd_server, "指令服务器"), + (self.location_server, "定位服务器") + ] + + for server, name in servers: + if server: + try: + server.close() + self.logger.info(f"{name}已关闭") + except Exception as e: + self.logger.error(f"关闭{name}失败: {e}") + + def accept_connections(self): + """接受客户端连接""" + try: + success = self.communication_manager.accept_all_connections() + if success: + # 更新连接状态 + for conn_type in ['audio', 'cmd', 'location']: + if self.communication_manager.connections[conn_type]: + self.connection_status[conn_type] = ConnectionStatus.CONNECTED + + self.logger.info("所有客户端连接成功") + else: + raise Exception("部分客户端连接失败") + + except Exception as e: + self.logger.error(f"接受连接失败: {e}") + self.logger.error(traceback.format_exc()) + self.performance_stats['errors'] += 1 + raise + + def start_audio_processing(self): + """启动音频处理线程""" + try: + audio_thread = threading.Thread( + target=self._audio_processing_worker, + name="AudioProcessor", + daemon=True + ) + audio_thread.start() + + with self.thread_lock: + self.threads.append(audio_thread) + + self.logger.info("音频处理线程启动成功") + + except Exception as e: + self.logger.error(f"启动音频处理线程失败: {e}") + raise + + def _audio_processing_worker(self): + """音频处理工作线程""" + self.logger.info("音频处理线程开始运行") + + try: + while self.running and self.current_mode == SystemMode.LISTENING: + try: + # 接收音频数据 + audio_data = self.communication_manager.receive_audio_data() + + if not audio_data: + self.logger.warning("音频客户端断开连接") + self.connection_status['audio'] = ConnectionStatus.DISCONNECTED + break + + # 检查是否是识别请求 + if self._is_recognition_request(audio_data): + self._handle_recognition_request(audio_data) + continue + + # 更新性能统计 + self.performance_stats['audio_packets_received'] += 1 + + # 添加到音频处理器 + if not self.audio_processor.add_audio_data(audio_data): + self.logger.warning("音频数据添加失败") + continue + + # 检查是否需要进行识别 + if self.audio_processor.should_process_recognition(): + result = self.audio_processor.process_recognition() + + if result and result.get('is_gunshot', False): + self.logger.warning(f"检测到枪声!置信度: {result.get('score', 0):.4f}") + self._switch_to_location_mode() + + except socket.timeout: + # 超时继续循环 + continue + except Exception as e: + self.logger.error(f"音频处理错误: {e}") + self.performance_stats['errors'] += 1 + time.sleep(0.1) # 短暂等待后继续 + + except Exception as e: + self.logger.error(f"音频处理线程异常: {e}") + self.logger.error(traceback.format_exc()) + self.performance_stats['errors'] += 1 + finally: + self.logger.info("音频处理线程结束") + + def _is_recognition_request(self, audio_data: bytes) -> bool: + """检查是否是识别请求""" + try: + # 检查数据开头是否包含识别请求标识 + data_str = audio_data.decode('utf-8', errors='ignore') + return data_str.startswith("RECOGNITION_REQUEST:") + except: + return False + + def _handle_recognition_request(self, audio_data: bytes): + """处理识别请求""" + try: + # 解析请求头 + data_str = audio_data.decode('utf-8', errors='ignore') + if not data_str.startswith("RECOGNITION_REQUEST:"): + return + + # 格式: RECOGNITION_REQUEST:timestamp:data_size + parts = data_str.split(':') + if len(parts) >= 3: + timestamp = float(parts[1]) + data_size = int(parts[2]) + + self.logger.info(f"收到识别请求: 时间戳={timestamp:.3f}, 数据大小={data_size}") + + # 等待接收音频数据 + audio_segment = self._receive_audio_segment(data_size) + if audio_segment is not None: + # 进行枪声识别 + recognition_result = self._perform_audio_recognition(audio_segment) + + # 发送识别结果给开发板 + self._send_recognition_result(timestamp, recognition_result) + + except Exception as e: + self.logger.error(f"处理识别请求失败: {e}") + + def _receive_audio_segment(self, data_size: int) -> Optional[bytes]: + """接收音频数据段""" + try: + # 从音频socket接收指定大小的数据 + received_data = b'' + remaining_size = data_size + + while remaining_size > 0: + chunk = self.communication_manager.audio_socket.recv(min(remaining_size, 4096)) + if not chunk: + break + received_data += chunk + remaining_size -= len(chunk) + + if len(received_data) == data_size: + return received_data + else: + self.logger.warning(f"音频数据接收不完整: 期望{data_size}, 实际{len(received_data)}") + return None + + except Exception as e: + self.logger.error(f"接收音频数据段失败: {e}") + return None + + def _perform_audio_recognition(self, audio_data: bytes) -> Dict[str, Any]: + """执行音频识别""" + try: + # 将字节数据转换为numpy数组 + audio_array = np.frombuffer(audio_data, dtype=np.int16).astype(np.float32) / 32768.0 + + # 检查音频质量 + if not self.audio_processor._check_audio_quality(audio_array): + return {'is_gunshot': False, 'confidence': 0.0, 'reason': 'poor_quality'} + + # 执行识别 + result = self.audio_processor._perform_recognition(audio_array) + + if result: + return { + 'is_gunshot': result.get('is_gunshot', False), + 'confidence': result.get('score', 0.0), + 'label': result.get('label', 'unknown') + } + else: + return {'is_gunshot': False, 'confidence': 0.0, 'reason': 'recognition_failed'} + + except Exception as e: + self.logger.error(f"音频识别失败: {e}") + return {'is_gunshot': False, 'confidence': 0.0, 'reason': 'error'} + + def _send_recognition_result(self, timestamp: float, result: Dict[str, Any]): + """发送识别结果给开发板""" + try: + if not self.communication_manager.cmd_socket: + return + + # 构建识别结果字符串 + # 格式: RECOGNITION_RESULT:timestamp:is_gunshot:confidence + is_gunshot = result.get('is_gunshot', False) + confidence = result.get('confidence', 0.0) + + result_str = f"RECOGNITION_RESULT:{timestamp:.3f}:{str(is_gunshot).lower()}:{confidence:.3f}" + + # 发送结果 + self.communication_manager.cmd_socket.send(result_str.encode('utf-8')) + + self.logger.info(f"发送识别结果: 时间戳={timestamp:.3f}, 枪声={is_gunshot}, 置信度={confidence:.3f}") + + except Exception as e: + self.logger.error(f"发送识别结果失败: {e}") + + def _switch_to_location_mode(self): + """切换到定位模式""" + try: + if self.current_mode == SystemMode.LISTENING: + self.current_mode = SystemMode.LOCATING + self.logger.info("切换到定位模式") + + # 发送定位指令给开发板 + if self.communication_manager.send_command("START_LOCATION"): + self.logger.info("定位指令发送成功") + else: + self.logger.error("定位指令发送失败") + + # 启动定位数据接收线程 + self._start_location_processing() + + except Exception as e: + self.logger.error(f"切换到定位模式失败: {e}") + self.logger.error(traceback.format_exc()) + self.performance_stats['errors'] += 1 + + def _start_location_processing(self): + """启动定位数据处理""" + try: + location_thread = threading.Thread( + target=self._location_processing_worker, + name="LocationProcessor", + daemon=True + ) + location_thread.start() + + with self.thread_lock: + self.threads.append(location_thread) + + self.logger.info("定位数据处理线程启动成功") + + except Exception as e: + self.logger.error(f"启动定位数据处理失败: {e}") + raise + + def _location_processing_worker(self): + """定位数据处理工作线程""" + self.logger.info("定位数据处理线程开始运行") + + try: + while self.running and self.current_mode == SystemMode.LOCATING: + try: + # 接收定位数据 + data = self.communication_manager.receive_location_data() + + if not data: + self.logger.warning("定位数据客户端断开连接") + self.connection_status['location'] = ConnectionStatus.DISCONNECTED + break + + # 更新性能统计 + self.performance_stats['location_packets_received'] += 1 + + # 解析数据 + self._process_location_data(data) + + except socket.timeout: + # 超时继续循环 + continue + except Exception as e: + self.logger.error(f"定位数据处理错误: {e}") + self.performance_stats['errors'] += 1 + time.sleep(0.1) # 短暂等待后继续 + + except Exception as e: + self.logger.error(f"定位数据处理线程异常: {e}") + self.logger.error(traceback.format_exc()) + self.performance_stats['errors'] += 1 + finally: + self.logger.info("定位数据处理线程结束") + + def _process_location_data(self, data: bytes): + """处理定位数据""" + try: + data_str = data.decode('utf-8').strip() + if not data_str: + return + + # 检查是否是枪声检测结果数据(保留兼容性) + if data_str.startswith("GUNSHOT_DETECTION:"): + self._process_gunshot_detection_data(data_str) + return + + # 解析定位数据 + location_data = self._parse_location_data(data_str) + if location_data: + # 应用卡尔曼滤波 + filtered_data = self._apply_kalman_filter(location_data) + # 后处理(平滑、异常值剔除等) + processed_data = self.location_post_processor.process(filtered_data) + # 将数据放入队列 + self.location_queue.put(processed_data) + self.location_data_count += 1 + # 添加到历史记录 + self._add_to_history(processed_data) + self.logger.debug(f"接收定位数据(后处理): X={processed_data.x:.2f}, Y={processed_data.y:.2f}, " + f"强度={processed_data.strength:.2f}, 角度={processed_data.angle:.2f}") + except Exception as e: + self.logger.error(f"处理定位数据失败: {e}") + self.performance_stats['errors'] += 1 + + def _process_gunshot_detection_data(self, data_str: str): + """处理开发板枪声检测数据""" + try: + # 解析格式: GUNSHOT_DETECTION:is_gunshot:confidence:timestamp + parts = data_str.split(':') + if len(parts) >= 4: + is_gunshot = parts[1].lower() == 'true' + confidence = float(parts[2]) + timestamp = float(parts[3]) + + # 更新统计 + self.board_gunshot_stats['total_detections'] += 1 + if is_gunshot: + self.board_gunshot_stats['gunshot_detections'] += 1 + self.performance_stats['board_gunshot_detections'] += 1 + self.board_gunshot_stats['last_detection_time'] = timestamp + + self.logger.info(f"开发板检测到枪声!置信度: {confidence:.3f}") + + # 更新检测率 + total = self.board_gunshot_stats['total_detections'] + gunshots = self.board_gunshot_stats['gunshot_detections'] + self.board_gunshot_stats['detection_rate'] = gunshots / total if total > 0 else 0.0 + + # 更新平均置信度 + if 'avg_confidence' not in self.board_gunshot_stats: + self.board_gunshot_stats['avg_confidence'] = confidence + else: + # 指数移动平均 + alpha = 0.1 + self.board_gunshot_stats['avg_confidence'] = ( + alpha * confidence + + (1 - alpha) * self.board_gunshot_stats['avg_confidence'] + ) + + self.logger.debug(f"开发板枪声检测统计: 总数={total}, 枪声={gunshots}, " + f"检测率={self.board_gunshot_stats['detection_rate']:.3f}, " + f"平均置信度={self.board_gunshot_stats['avg_confidence']:.3f}") + + except Exception as e: + self.logger.error(f"处理开发板枪声检测数据失败: {e}") + self.performance_stats['errors'] += 1 + + def _parse_location_data(self, data_str: str) -> Optional[LocationData]: + """解析定位数据""" + try: + parts = data_str.split(',') + if len(parts) != 4: + self.logger.warning(f"定位数据格式错误,期望4个值,实际{len(parts)}个: {data_str}") + return None + + x, y, strength, angle = map(float, parts) + + # 数据范围验证 + if not (-50 <= x <= 50 and -50 <= y <= 50): + self.logger.warning(f"坐标超出合理范围: x={x}, y={y}") + return None + + if not (0 <= strength <= 100): + self.logger.warning(f"强度值超出合理范围: {strength}") + return None + + if not (0 <= angle <= 360): + self.logger.warning(f"角度值超出合理范围: {angle}") + return None + + return LocationData( + x=x, y=y, strength=strength, angle=angle, + timestamp=time.time() + ) + + except ValueError as e: + self.logger.error(f"解析定位数据失败: {e}, 数据: {data_str}") + return None + except Exception as e: + self.logger.error(f"解析定位数据异常: {e}") + return None + + def _apply_kalman_filter(self, location_data: LocationData) -> LocationData: + """应用卡尔曼滤波""" + try: + return kalman_filter.filter_location_data(location_data) + except Exception as e: + self.logger.error(f"卡尔曼滤波失败: {e}") + return location_data + + def _add_to_history(self, location_data: LocationData): + """添加到历史记录""" + try: + self.location_history.append(location_data) + + # 限制历史记录大小 + max_history = self.visualization_config['max_history_points'] + if len(self.location_history) > max_history: + self.location_history = self.location_history[-max_history:] + + except Exception as e: + self.logger.error(f"添加历史记录失败: {e}") + + def update_plot(self, frame): + """更新可视化图表""" + try: + # 获取最新的定位数据 + if not self.location_queue.empty(): + location_data = self.location_queue.get_nowait() + self.current_location = location_data + + # 更新散点图数据 + if self.location_history: + x_coords = [data.x for data in self.location_history] + y_coords = [data.y for data in self.location_history] + strengths = [data.strength for data in self.location_history] + + # 更新散点图 + self.scat.set_offsets(np.column_stack([x_coords, y_coords])) + self.scat.set_array(np.array(strengths)) + + # 更新标题显示最新位置 + latest = self.location_history[-1] + self.ax.set_title(f"实时声源定位地图 - 最新位置: X={latest.x:.2f}, Y={latest.y:.2f}, " + f"强度={latest.strength:.2f}, 角度={latest.angle:.2f}") + + # 更新性能统计显示 + self._update_performance_display() + + return [self.scat] + + except Exception as e: + self.logger.error(f"更新可视化失败: {e}") + return [self.scat] + + def _update_performance_display(self): + """更新性能统计显示""" + try: + # 计算实时统计 + current_time = time.time() + uptime = current_time - self.performance_stats['start_time'] + + # 计算数据接收率 + audio_rate = self.performance_stats['audio_packets_received'] / max(uptime, 1) + location_rate = self.performance_stats['location_packets_received'] / max(uptime, 1) + + # 更新状态栏 + status_text = (f"运行时间: {uptime:.1f}s | " + f"音频包: {self.performance_stats['audio_packets_received']} " + f"({audio_rate:.1f}/s) | " + f"定位包: {self.performance_stats['location_packets_received']} " + f"({location_rate:.1f}/s) | " + f"错误: {self.performance_stats['errors']} | " + f"模式: {self.current_mode.value}") + + # 添加开发板枪声检测统计 + if self.current_mode == SystemMode.LOCATING: + board_stats = self.board_gunshot_stats + status_text += f" | 开发板检测: {board_stats['gunshot_detections']}/{board_stats['total_detections']} " + status_text += f"({board_stats['detection_rate']:.1%})" + + # 在图形上显示状态信息 + if hasattr(self, 'status_text_obj'): + self.status_text_obj.remove() + + self.status_text_obj = self.fig.text( + 0.02, 0.02, status_text, + fontsize=8, family='monospace', + bbox=dict(boxstyle="round,pad=0.3", facecolor="white", alpha=0.8) + ) + + except Exception as e: + self.logger.error(f"更新性能显示失败: {e}") + + def get_system_status(self) -> Dict[str, Any]: + """获取系统状态信息""" + uptime = time.time() - self.performance_stats['start_time'] + + return { + 'mode': self.current_mode.value, + 'uptime': uptime, + 'connection_status': {k: v.value for k, v in self.connection_status.items()}, + 'performance_stats': self.performance_stats.copy(), + 'audio_processor_stats': self.audio_processor.get_performance_stats(), + 'communication_stats': self.communication_manager.get_connection_stats(), + 'location_stats': { + 'total_packets': self.location_data_count, + 'history_size': len(self.location_history), + 'queue_size': self.location_queue.qsize() + }, + 'board_gunshot_stats': self.board_gunshot_stats.copy() # 新增:开发板枪声检测统计 + } + + def run(self): + """运行服务器""" + try: + self.logger.info("=== 声源定位系统 - PC端服务器启动 ===") + self.logger.info(f"当前模式: {self.current_mode.value}") + self.logger.info(f"网络配置: {self.network_config}") + self.logger.info(f"音频配置: {self.audio_config}") + + # 接受客户端连接 + self.accept_connections() + + # 启动音频处理线程 + self.start_audio_processing() + + # 启动Flask服务器 + self._start_flask_server() + + # 显示可视化界面 + self.logger.info("启动可视化界面...") + plt.show() + + except KeyboardInterrupt: + self.logger.info("收到中断信号,正在关闭...") + except Exception as e: + self.logger.error(f"服务器运行异常: {e}") + self.logger.error(traceback.format_exc()) + finally: + self.cleanup() + + def cleanup(self): + """清理资源""" + try: + self.logger.info("开始清理资源...") + self.running = False + + # 关闭通信管理器 + self.communication_manager.close_all_connections() + + # 关闭服务器 + for server_name, server in [('audio', self.audio_server), + ('cmd', self.cmd_server), + ('location', self.location_server)]: + if server: + try: + server.close() + self.logger.info(f"关闭{server_name}服务器") + except Exception as e: + self.logger.error(f"关闭{server_name}服务器失败: {e}") + + # 等待线程结束 + self.logger.info("等待线程结束...") + for thread in self.threads: + if thread.is_alive(): + thread.join(timeout=2.0) + if thread.is_alive(): + self.logger.warning(f"线程 {thread.name} 未能正常结束") + + # 保存最终统计信息 + self._save_final_stats() + + # 停止Flask服务器 + self._stop_flask_server() + + self.logger.info("资源清理完成") + + except Exception as e: + self.logger.error(f"清理资源失败: {e}") + + def _save_final_stats(self): + """保存最终统计信息""" + try: + stats = self.get_system_status() + + # 保存到文件 + stats_file = f"logs/system_stats_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json" + os.makedirs(os.path.dirname(stats_file), exist_ok=True) + + with open(stats_file, 'w', encoding='utf-8') as f: + json.dump(stats, f, indent=2, ensure_ascii=False, default=str) + + self.logger.info(f"系统统计信息已保存到: {stats_file}") + + except Exception as e: + self.logger.error(f"保存统计信息失败: {e}") + + def _init_flask_app(self): + """初始化Flask应用""" + try: + self.flask_app = Flask(__name__) + + # 启用CORS + if self.http_api_config['cors_enabled']: + CORS(self.flask_app) + + # 设置路由 + self._setup_flask_routes() + + self.logger.info("Flask应用初始化成功") + + except Exception as e: + self.logger.error(f"Flask应用初始化失败: {e}") + self.flask_app = None + + def _setup_flask_routes(self): + """设置Flask路由""" + try: + @self.flask_app.route("/") + def index(): + return jsonify({ + "message": "声源定位系统HTTP API", + "version": "2.0.0", + "status": "running", + "endpoints": { + "/data": "获取最新定位数据", + "/status": "获取系统状态", + "/stats": "获取性能统计", + "/board_stats": "获取开发板枪声检测统计" # 新增 + } + }) + + @self.flask_app.route("/data") + def get_data(): + """获取最新声源定位数据""" + try: + if self.current_location: + return jsonify({ + "X": float(self.current_location.x), + "Y": float(self.current_location.y), + "strength": float(self.current_location.strength), + "angle": float(self.current_location.angle), + "timestamp": self.current_location.timestamp, + "confidence": float(self.current_location.confidence) + }) + else: + return jsonify({ + "X": 0.0, + "Y": 0.0, + "strength": 0.0, + "angle": 0.0, + "timestamp": time.time(), + "confidence": 0.0 + }) + except Exception as e: + self.logger.error(f"获取定位数据失败: {e}") + return jsonify({"error": "获取数据失败"}), 500 + + @self.flask_app.route("/status") + def get_status(): + """获取系统状态""" + try: + status = self.get_system_status() + return jsonify(status) + except Exception as e: + self.logger.error(f"获取系统状态失败: {e}") + return jsonify({"error": "获取状态失败"}), 500 + + @self.flask_app.route("/stats") + def get_stats(): + """获取性能统计""" + try: + stats = { + "system_stats": self.get_system_status(), + "audio_processor_stats": self.audio_processor.get_performance_stats(), + "communication_stats": self.communication_manager.get_connection_stats() + } + return jsonify(stats) + except Exception as e: + self.logger.error(f"获取性能统计失败: {e}") + return jsonify({"error": "获取统计失败"}), 500 + + @self.flask_app.route("/board_stats") + def get_board_stats(): + """获取开发板枪声检测统计""" + try: + return jsonify(self.board_gunshot_stats) + except Exception as e: + self.logger.error(f"获取开发板统计失败: {e}") + return jsonify({"error": "获取统计失败"}), 500 + + self.logger.info("Flask路由设置完成") + + except Exception as e: + self.logger.error(f"设置Flask路由失败: {e}") + + def _start_flask_server(self): + """启动Flask服务器""" + try: + if self.flask_app: + self.flask_thread = threading.Thread( + target=self._run_flask_server, + name="FlaskServer", + daemon=True + ) + self.flask_thread.start() + self.logger.info(f"Flask服务器启动成功: http://{self.http_api_config['host']}:{self.http_api_config['port']}") + else: + self.logger.warning("Flask应用未初始化,跳过HTTP API启动") + + except Exception as e: + self.logger.error(f"启动Flask服务器失败: {e}") + + def _run_flask_server(self): + """运行Flask服务器""" + try: + self.flask_app.run( + host=self.http_api_config['host'], + port=self.http_api_config['port'], + debug=False, + use_reloader=False + ) + except Exception as e: + self.logger.error(f"Flask服务器运行失败: {e}") + + def _stop_flask_server(self): + """停止Flask服务器""" + try: + if self.flask_thread and self.flask_thread.is_alive(): + # Flask服务器会在主线程结束时自动停止 + self.logger.info("Flask服务器已停止") + except Exception as e: + self.logger.error(f"停止Flask服务器失败: {e}") + +def main(): + """主函数""" + print("=== 声源定位系统 - PC端服务器 ===") + print("版本: 2.0.0") + print("作者: 声源定位系统开发团队") + print("正在初始化...") + + try: + # 创建并运行服务器 + server = PCServer() + server.run() + + except KeyboardInterrupt: + logger.info("程序被用户中断") + except Exception as e: + logger.error(f"程序启动失败: {e}") + logger.error(traceback.format_exc()) + print(f"程序启动失败: {e}") + print("请检查配置文件和网络连接") + return 1 + + return 0 + +if __name__ == "__main__": + try: + exit_code = main() + sys.exit(exit_code) + except Exception as e: + print(f"程序异常退出: {e}") + sys.exit(1) \ No newline at end of file diff --git a/src/声源定位代码/config.ini b/src/声源定位代码/config.ini new file mode 100644 index 0000000..7ce3cc0 --- /dev/null +++ b/src/声源定位代码/config.ini @@ -0,0 +1,35 @@ +[NETWORK] +host = 0.0.0.0 +port_audio = 12346 +port_cmd = 12347 +port_location = 12348 +timeout = 30.0 +buffer_size = 4096 + +[AUDIO] +sample_rate = 16000 +channels = 1 +chunk_size = 1024 +format = int16 + +[RECOGNITION] +gunshot_threshold = 0.7 +recognition_interval = 3.0 +configs_path = audio-classification/configs/cam++.yml +model_path = audio-classification/models/CAMPPlus_Fbank/best_model/ + +[VISUALIZATION] +plot_interval_ms = 100 +plot_range = 15.0 +point_size = 200 +max_history_points = 100 + +[KALMAN] +q_x = 5.0 +r_x = 0.01 +q_y = 5.0 +r_y = 0.01 +q_strength = 5.0 +r_strength = 0.01 +q_angle = 5.0 +r_angle = 0.01 \ No newline at end of file diff --git a/src/声源定位代码/front-code/sound-vue-frontend/.gitignore b/src/声源定位代码/front-code/sound-vue-frontend/.gitignore new file mode 100644 index 0000000..d6294d5 --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/.gitignore @@ -0,0 +1,52 @@ +# Vue.js 项目的 .gitignore 文件 + +# 依赖目录 +node_modules/ + +# 构建输出目录 +/dist +/build + +# 本地环境配置文件 +.env.local +.env.*.local + +# 日志文件 +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# 编辑器目录和文件 +.idea/ +.vscode/ +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# 系统文件 +.DS_Store +Thumbs.db + +# 测试覆盖率报告 +/coverage + +# 特定于 Vue CLI 的文件 +.history/ +.firebase/ +.firebase.json +.firebaserc + +# 缓存目录 +.npm/ +.eslintcache +.stylelintcache +.history/ +.cache/ + +# 临时文件 +*.tmp +*.temp +*.bak diff --git a/src/声源定位代码/front-code/sound-vue-frontend/README.md b/src/声源定位代码/front-code/sound-vue-frontend/README.md new file mode 100644 index 0000000..d9f55cf --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/README.md @@ -0,0 +1,38 @@ +# 声源定位系统前端 + +基于 Vue.js 和 ECharts 实现的声源定位可视化系统,与 Flask 后端通信获取实时声源数据。 + +## 功能特点 + +- 实时显示声源位置 (X, Y 坐标) +- 可视化声源强度和方向 +- 支持开始/停止监听控制 +- 专业企业级 UI 设计 + +## 项目设置 + +### 安装依赖 +``` +npm install +``` + +### 开发环境运行 +``` +npm run serve +``` + +### 生产环境构建 +``` +npm run build +``` + +## 配置说明 + +后端 API 地址可在 `App.vue` 中的 `API_BASE_URL` 变量修改。 + +## 使用方法 + +1. 确保 Flask 后端已启动并在指定端口运行 +2. 启动前端应用 +3. 点击"开始监听"按钮开始获取实时数据 +4. 声源位置、强度和方向将在可视化图表中实时显示 diff --git a/src/声源定位代码/front-code/sound-vue-frontend/index.html b/src/声源定位代码/front-code/sound-vue-frontend/index.html new file mode 100644 index 0000000..76d63b8 --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + 声源定位系统 + + +
+ + + diff --git a/src/声源定位代码/front-code/sound-vue-frontend/package-lock.json b/src/声源定位代码/front-code/sound-vue-frontend/package-lock.json new file mode 100644 index 0000000..f80dd28 --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/package-lock.json @@ -0,0 +1,19934 @@ +{ + "name": "sound-vue-frontend", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "sound-vue-frontend", + "version": "0.1.0", + "dependencies": { + "axios": "^1.3.4", + "core-js": "^3.8.3", + "echarts": "^5.4.1", + "element-plus": "^2.3.0", + "vue": "^3.2.13" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "eslint": "^7.32.0", + "eslint-plugin-vue": "^8.0.3" + } + }, + "node_modules/@achrinza/node-ipc": { + "version": "9.2.9", + "resolved": "https://registry.npmjs.org/@achrinza/node-ipc/-/node-ipc-9.2.9.tgz", + "integrity": "sha512-7s0VcTwiK/0tNOVdSX9FWMeFdOEcsAOz9HesBldXxFMaGvIak7KC2z9tV9EgsQXn6KUsWsfIkViMNuIo0GoZDQ==", + "dev": true, + "dependencies": { + "@node-ipc/js-queue": "2.0.3", + "event-pubsub": "4.3.0", + "js-message": "1.0.7" + }, + "engines": { + "node": "8 || 9 || 10 || 11 || 12 || 13 || 14 || 15 || 16 || 17 || 18 || 19 || 20 || 21 || 22" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz", + "integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", + "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helpers": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz", + "integrity": "sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==", + "dev": true, + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", + "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", + "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", + "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", + "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", + "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.27.1.tgz", + "integrity": "sha512-DTxe4LBPrtFdsWzgpmbBKevg3e9PBy+dXRt19kSbucbZvL2uqtdqwwpluL1jfxYE0wIDTFp1nTy/q6gNLsxXrg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-decorators": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz", + "integrity": "sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz", + "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.1.tgz", + "integrity": "sha512-QEcFlMl9nGTgh1rn2nIeU5bkfb9BAjaQcWbiP4LvKxUot52ABcTkpcyJ7f2Q2U2RuQ84BNLgts3jRme2dTx6Fw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", + "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz", + "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.1.tgz", + "integrity": "sha512-ttDCqhfvpE9emVkXbPD8vyxxh4TWYACVybGkDj+oReOGwnp066ITEivDlLwe0b1R0+evJ13IXQuLNB5w1fhC5Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.2.tgz", + "integrity": "sha512-AIUHD7xJ1mCrj3uPozvtngY3s0xpv7Nu7DoUSnzNY6Xam1Cy4rUznR//pvMHOhQ4AvbCexhbqXCtpxGHOGOO6g==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz", + "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.1.tgz", + "integrity": "sha512-B19lbbL7PMrKr52BNPjCqg1IyNUIjTcxKj8uX9zHO+PmWN93s19NDr/f69mIkEp2x9nmDJ08a7lgHaTTzvW7mw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.1.tgz", + "integrity": "sha512-TqGF3desVsTcp3WrJGj4HfKokfCXCLcHpt4PJF0D8/iT6LPd9RS82Upw3KPeyr6B22Lfd3DO8MVrmp0oRkUDdw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.2.tgz", + "integrity": "sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.27.1", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.27.1", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.27.2", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.27.1", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.40.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", + "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz", + "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz", + "integrity": "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.0.tgz", + "integrity": "sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==", + "dependencies": { + "@floating-ui/core": "^1.7.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==" + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@node-ipc/js-queue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@node-ipc/js-queue/-/js-queue-2.0.3.tgz", + "integrity": "sha512-fL1wpr8hhD5gT2dA1qifeVaoDFlQR5es8tFuKqjHX+kdOtdNHnxkVZbtIrR2rxnMFvehkjaZRNV2H/gPXlb0hw==", + "dev": true, + "dependencies": { + "easy-stack": "1.0.1" + }, + "engines": { + "node": ">=1.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.7", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "node_modules/@soda/friendly-errors-webpack-plugin": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz", + "integrity": "sha512-h2ooWqP8XuFqTXT+NyAFbrArzfQA7R6HTezADrvD9Re8fxMLTPPniLdqVTdDaO0eIoLaAwKT+d6w+5GeTk7Vbg==", + "dev": true, + "dependencies": { + "chalk": "^3.0.0", + "error-stack-parser": "^2.0.6", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@soda/get-current-script": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@soda/get-current-script/-/get-current-script-1.0.2.tgz", + "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", + "dev": true + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.12", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", + "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", + "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.16", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", + "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", + "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, + "node_modules/@types/node": { + "version": "22.15.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz", + "integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==", + "dev": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", + "integrity": "sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==", + "dev": true + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.4.0.tgz", + "integrity": "sha512-mCokbouEQ/ocRce/FpKCRItGo+013tHg7tixg3DUNS+6bmIchPt66012kBMm476vyEIJPafrvOf4E5OYj3shSw==", + "dev": true + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.4.0.tgz", + "integrity": "sha512-9zAHmwgMWlaN6qRKdrg1uKsBKHvnUU+Py+MOCTuYZBoZsopa90Di10QRjB+YPnVss0BZbG/H5XFwJY1fTxJWhA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.9", + "@babel/types": "^7.26.9", + "@vue/babel-helper-vue-transform-on": "1.4.0", + "@vue/babel-plugin-resolve-type": "1.4.0", + "@vue/shared": "^3.5.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.4.0.tgz", + "integrity": "sha512-4xqDRRbQQEWHQyjlYSgZsWj44KfiF6D+ktCuXyZ8EnVDYV3pztmXJDf1HveAjUAXxAnR8daCQT51RneWWxtTyQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/parser": "^7.26.9", + "@vue/compiler-sfc": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-plugin-transform-vue-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.4.0.tgz", + "integrity": "sha512-Fmastxw4MMx0vlgLS4XBX0XiBbUFzoMGeVXuMV08wyOfXdikAFqBTuYPR0tlk+XskL19EzHc39SgjrPGY23JnA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-preset-app": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-5.0.8.tgz", + "integrity": "sha512-yl+5qhpjd8e1G4cMXfORkkBlvtPCIgmRf3IYCWYDKIQ7m+PPa5iTm4feiNmCMD6yGqQWMhhK/7M3oWGL9boKwg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.16", + "@babel/helper-compilation-targets": "^7.12.16", + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-proposal-class-properties": "^7.12.13", + "@babel/plugin-proposal-decorators": "^7.12.13", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/plugin-transform-runtime": "^7.12.15", + "@babel/preset-env": "^7.12.16", + "@babel/runtime": "^7.12.13", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.1.2", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.8.3", + "core-js-compat": "^3.8.3", + "semver": "^7.3.4" + }, + "peerDependencies": { + "@babel/core": "*", + "core-js": "^3", + "vue": "^2 || ^3.2.13" + }, + "peerDependenciesMeta": { + "core-js": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-preset-app/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/babel-preset-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.4.0.tgz", + "integrity": "sha512-QmfRpssBOPZWL5xw7fOuHNifCQcNQC1PrOo/4fu6xlhlKJJKSA3HqX92Nvgyx8fqHZTUGMPHmFA+IDqwXlqkSA==", + "dev": true, + "dependencies": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "@vue/babel-sugar-composition-api-inject-h": "^1.4.0", + "@vue/babel-sugar-composition-api-render-instance": "^1.4.0", + "@vue/babel-sugar-functional-vue": "^1.4.0", + "@vue/babel-sugar-inject-h": "^1.4.0", + "@vue/babel-sugar-v-model": "^1.4.0", + "@vue/babel-sugar-v-on": "^1.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "vue": "*" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-sugar-composition-api-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.4.0.tgz", + "integrity": "sha512-VQq6zEddJHctnG4w3TfmlVp5FzDavUSut/DwR0xVoe/mJKXyMcsIibL42wPntozITEoY90aBV0/1d2KjxHU52g==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-composition-api-render-instance": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.4.0.tgz", + "integrity": "sha512-6ZDAzcxvy7VcnCjNdHJ59mwK02ZFuP5CnucloidqlZwVQv5CQLijc3lGpR7MD3TWFi78J7+a8J56YxbCtHgT9Q==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-functional-vue": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.4.0.tgz", + "integrity": "sha512-lTEB4WUFNzYt2In6JsoF9sAYVTo84wC4e+PoZWSgM6FUtqRJz7wMylaEhSRgG71YF+wfLD6cc9nqVeXN2rwBvw==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.4.0.tgz", + "integrity": "sha512-muwWrPKli77uO2fFM7eA3G1lAGnERuSz2NgAxuOLzrsTlQl8W4G+wwbM4nB6iewlKbwKRae3nL03UaF5ffAPMA==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-model": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.4.0.tgz", + "integrity": "sha512-0t4HGgXb7WHYLBciZzN5s0Hzqan4Ue+p/3FdQdcaHAb7s5D9WZFGoSxEZHrR1TFVZlAPu1bejTKGeAzaaG3NCQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-on": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.4.0.tgz", + "integrity": "sha512-m+zud4wKLzSKgQrWwhqRObWzmTuyzl6vOP7024lrpeJM4x2UhQtRDLgYjXAw9xBXjCwS0pP9kXjg91F9ZNo9JA==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/cli-overlay": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.8.tgz", + "integrity": "sha512-KmtievE/B4kcXp6SuM2gzsnSd8WebkQpg3XaB6GmFh1BJGRqa1UiW9up7L/Q67uOdTigHxr5Ar2lZms4RcDjwQ==", + "dev": true + }, + "node_modules/@vue/cli-plugin-babel": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-babel/-/cli-plugin-babel-5.0.8.tgz", + "integrity": "sha512-a4qqkml3FAJ3auqB2kN2EMPocb/iu0ykeELwed+9B1c1nQ1HKgslKMHMPavYx3Cd/QAx2mBD4hwKBqZXEI/CsQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.16", + "@vue/babel-preset-app": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "babel-loader": "^8.2.2", + "thread-loader": "^3.0.0", + "webpack": "^5.54.0" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-plugin-eslint": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-5.0.8.tgz", + "integrity": "sha512-d11+I5ONYaAPW1KyZj9GlrV/E6HZePq5L5eAF5GgoVdu6sxr6bDgEoxzhcS1Pk2eh8rn1MxG/FyyR+eCBj/CNg==", + "dev": true, + "dependencies": { + "@vue/cli-shared-utils": "^5.0.8", + "eslint-webpack-plugin": "^3.1.0", + "globby": "^11.0.2", + "webpack": "^5.54.0", + "yorkie": "^2.0.0" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0", + "eslint": ">=7.5.0" + } + }, + "node_modules/@vue/cli-plugin-router": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-5.0.8.tgz", + "integrity": "sha512-Gmv4dsGdAsWPqVijz3Ux2OS2HkMrWi1ENj2cYL75nUeL+Xj5HEstSqdtfZ0b1q9NCce+BFB6QnHfTBXc/fCvMg==", + "dev": true, + "dependencies": { + "@vue/cli-shared-utils": "^5.0.8" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-plugin-vuex": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.8.tgz", + "integrity": "sha512-HSYWPqrunRE5ZZs8kVwiY6oWcn95qf/OQabwLfprhdpFWAGtLStShjsGED2aDpSSeGAskQETrtR/5h7VqgIlBA==", + "dev": true, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-service": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-5.0.8.tgz", + "integrity": "sha512-nV7tYQLe7YsTtzFrfOMIHc5N2hp5lHG2rpYr0aNja9rNljdgcPZLyQRb2YRivTHqTv7lI962UXFURcpStHgyFw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.12.16", + "@soda/friendly-errors-webpack-plugin": "^1.8.0", + "@soda/get-current-script": "^1.0.2", + "@types/minimist": "^1.2.0", + "@vue/cli-overlay": "^5.0.8", + "@vue/cli-plugin-router": "^5.0.8", + "@vue/cli-plugin-vuex": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "@vue/component-compiler-utils": "^3.3.0", + "@vue/vue-loader-v15": "npm:vue-loader@^15.9.7", + "@vue/web-component-wrapper": "^1.3.0", + "acorn": "^8.0.5", + "acorn-walk": "^8.0.2", + "address": "^1.1.2", + "autoprefixer": "^10.2.4", + "browserslist": "^4.16.3", + "case-sensitive-paths-webpack-plugin": "^2.3.0", + "cli-highlight": "^2.1.10", + "clipboardy": "^2.3.0", + "cliui": "^7.0.4", + "copy-webpack-plugin": "^9.0.1", + "css-loader": "^6.5.0", + "css-minimizer-webpack-plugin": "^3.0.2", + "cssnano": "^5.0.0", + "debug": "^4.1.1", + "default-gateway": "^6.0.3", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "hash-sum": "^2.0.0", + "html-webpack-plugin": "^5.1.0", + "is-file-esm": "^1.0.0", + "launch-editor-middleware": "^2.2.1", + "lodash.defaultsdeep": "^4.6.1", + "lodash.mapvalues": "^4.6.0", + "mini-css-extract-plugin": "^2.5.3", + "minimist": "^1.2.5", + "module-alias": "^2.2.2", + "portfinder": "^1.0.26", + "postcss": "^8.2.6", + "postcss-loader": "^6.1.1", + "progress-webpack-plugin": "^1.0.12", + "ssri": "^8.0.1", + "terser-webpack-plugin": "^5.1.1", + "thread-loader": "^3.0.0", + "vue-loader": "^17.0.0", + "vue-style-loader": "^4.1.3", + "webpack": "^5.54.0", + "webpack-bundle-analyzer": "^4.4.0", + "webpack-chain": "^6.5.1", + "webpack-dev-server": "^4.7.3", + "webpack-merge": "^5.7.3", + "webpack-virtual-modules": "^0.4.2", + "whatwg-fetch": "^3.6.2" + }, + "bin": { + "vue-cli-service": "bin/vue-cli-service.js" + }, + "engines": { + "node": "^12.0.0 || >= 14.0.0" + }, + "peerDependencies": { + "vue-template-compiler": "^2.0.0", + "webpack-sources": "*" + }, + "peerDependenciesMeta": { + "cache-loader": { + "optional": true + }, + "less-loader": { + "optional": true + }, + "pug-plain-loader": { + "optional": true + }, + "raw-loader": { + "optional": true + }, + "sass-loader": { + "optional": true + }, + "stylus-loader": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/@vue/cli-shared-utils": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.8.tgz", + "integrity": "sha512-uK2YB7bBVuQhjOJF+O52P9yFMXeJVj7ozqJkwYE9PlMHL1LMHjtCYm4cSdOebuPzyP+/9p0BimM/OqxsevIopQ==", + "dev": true, + "dependencies": { + "@achrinza/node-ipc": "^9.2.5", + "chalk": "^4.1.2", + "execa": "^1.0.0", + "joi": "^17.4.0", + "launch-editor": "^2.2.1", + "lru-cache": "^6.0.0", + "node-fetch": "^2.6.7", + "open": "^8.0.2", + "ora": "^5.3.0", + "read-pkg": "^5.1.1", + "semver": "^7.3.4", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "dependencies": { + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/component-compiler-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", + "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", + "dev": true, + "dependencies": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "optionalDependencies": { + "prettier": "^1.18.2 || ^2.0.0" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "node_modules/@vue/component-compiler-utils/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/@vue/reactivity": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "dependencies": { + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "dependencies": { + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "vue": "3.5.13" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==" + }, + "node_modules/@vue/vue-loader-v15": { + "name": "vue-loader", + "version": "15.11.1", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.11.1.tgz", + "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==", + "dev": true, + "dependencies": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "peerDependencies": { + "css-loader": "*", + "webpack": "^3.0.0 || ^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "cache-loader": { + "optional": true + }, + "prettier": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/@vue/vue-loader-v15/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/@vue/web-component-wrapper": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz", + "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", + "dev": true + }, + "node_modules/@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "dependencies": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "dependencies": { + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", + "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.4", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", + "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.4" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", + "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001716", + "electron-to-chromium": "^1.5.149", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001718", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", + "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz", + "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", + "dev": true, + "dependencies": { + "arch": "^2.1.1", + "execa": "^1.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog", + "dev": true, + "dependencies": { + "bluebird": "^3.1.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.1", + "globby": "^11.0.3", + "normalize-path": "^3.0.0", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz", + "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.42.0.tgz", + "integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.24.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dev": true, + "dependencies": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dev": true, + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/default-gateway/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-gateway/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/easy-stack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", + "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.152", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.152.tgz", + "integrity": "sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg==", + "dev": true + }, + "node_modules/element-plus": { + "version": "2.9.10", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.10.tgz", + "integrity": "sha512-W2v9jWnm1kl/zm4bSvCh8aFCVlxvhG3fmqiDZwyd6WQiWGE595J/mpjcCggEr+49QDgIymhXrpPMOPPSARUbng==", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.13", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-plugin-vue/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-pubsub": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", + "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/execa/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "dependencies": { + "ci-info": "^1.5.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-file-esm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-file-esm/-/is-file-esm-1.0.0.tgz", + "integrity": "sha512-rZlaNKb4Mr8WlRu2A9XdeoKgnO5aA53XdPHgCKVyCrQ/rWi89RET1+bq37Ru46obaQXeiX4vmFIm1vks41hoSA==", + "dev": true, + "dependencies": { + "read-pkg-up": "^7.0.1" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-message": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", + "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==", + "dev": true, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/launch-editor": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", + "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/launch-editor-middleware": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.10.0.tgz", + "integrity": "sha512-RzZu7MeVlE3p1H6Sadc2BhuDGAj7bkeDCBpNq/zSENP4ohJGhso00k5+iYaRwKshIpiOAhMmimce+5D389xmSg==", + "dev": true, + "dependencies": { + "launch-editor": "^2.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/loader-utils/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", + "dev": true + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "node_modules/lodash.mapvalues": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ==", + "dev": true, + "dependencies": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/module-alias": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==", + "dev": true + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/portfinder": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.37.tgz", + "integrity": "sha512-yuGIEjDAYnnOex9ddMnKZEMFE0CcGo6zbfzDklkmT1m5z734ss6JMzN9rNB3+RR7iS+F10D4/BVIaXOyh8PQKw==", + "dev": true, + "dependencies": { + "async": "^3.2.6", + "debug": "^4.3.6" + }, + "engines": { + "node": ">= 10.12" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dev": true, + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dev": true, + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dev": true, + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/progress-webpack-plugin": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/progress-webpack-plugin/-/progress-webpack-plugin-1.0.16.tgz", + "integrity": "sha512-sdiHuuKOzELcBANHfrupYo+r99iPRyOnw15qX+rNlVUqXGfjXdH4IgxriKwG1kNJwVswKQHMdj1hYZMcb9jFaA==", + "dev": true, + "dependencies": { + "chalk": "^2.1.0", + "figures": "^2.0.0", + "log-update": "^2.3.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "peerDependencies": { + "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/progress-webpack-plugin/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/progress-webpack-plugin/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/progress-webpack-plugin/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/progress-webpack-plugin/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", + "dev": true + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.39.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.1.tgz", + "integrity": "sha512-Mm6+uad0ZuDtcV8/4uOZQDQ8RuiC5Pu+iZRedJtF7yA/27sPL7d++In/AJKpWZlU3SYMPPkVfwetn6sgZ66pUA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/thread-loader": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/thread-loader/-/thread-loader-3.0.4.tgz", + "integrity": "sha512-ByaL2TPb+m6yArpqQUZvP+5S1mZtXsEP7nWKKlAUTm7fCml8kB5s1uI3+eHRP2bk5mVYfRSBI7FFf+tWEyLZwA==", + "dev": true, + "dependencies": { + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.1.0", + "loader-utils": "^2.0.0", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.27.0 || ^5.0.0" + } + }, + "node_modules/thread-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/thread-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vue": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", + "dev": true + }, + "node_modules/vue-loader": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.4.2.tgz", + "integrity": "sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "watchpack": "^2.4.0" + }, + "peerDependencies": { + "webpack": "^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/vue-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/vue-style-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", + "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", + "dev": true, + "dependencies": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + } + }, + "node_modules/vue-style-loader/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/webpack": { + "version": "5.99.8", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.8.tgz", + "integrity": "sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.2", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-chain": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-6.5.1.tgz", + "integrity": "sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz", + "integrity": "sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==", + "dev": true + }, + "node_modules/webpack/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yorkie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz", + "integrity": "sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "execa": "^0.8.0", + "is-ci": "^1.0.10", + "normalize-path": "^1.0.0", + "strip-indent": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/yorkie/node_modules/execa": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", + "integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/yorkie/node_modules/normalize-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz", + "integrity": "sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/yorkie/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "dependencies": { + "tslib": "2.3.0" + } + } + }, + "dependencies": { + "@achrinza/node-ipc": { + "version": "9.2.9", + "resolved": "https://registry.npmjs.org/@achrinza/node-ipc/-/node-ipc-9.2.9.tgz", + "integrity": "sha512-7s0VcTwiK/0tNOVdSX9FWMeFdOEcsAOz9HesBldXxFMaGvIak7KC2z9tV9EgsQXn6KUsWsfIkViMNuIo0GoZDQ==", + "dev": true, + "requires": { + "@node-ipc/js-queue": "2.0.3", + "event-pubsub": "4.3.0", + "js-message": "1.0.7" + } + }, + "@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + } + }, + "@babel/compat-data": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz", + "integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==", + "dev": true + }, + "@babel/core": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", + "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helpers": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + } + }, + "@babel/generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", + "dev": true, + "requires": { + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz", + "integrity": "sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==", + "dev": true, + "requires": { + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", + "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "requires": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-module-transforms": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", + "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "requires": { + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" + }, + "@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==" + }, + "@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "dev": true, + "requires": { + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/helpers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", + "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", + "dev": true, + "requires": { + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", + "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", + "requires": { + "@babel/types": "^7.27.1" + } + }, + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + } + }, + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", + "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.27.1.tgz", + "integrity": "sha512-DTxe4LBPrtFdsWzgpmbBKevg3e9PBy+dXRt19kSbucbZvL2uqtdqwwpluL1jfxYE0wIDTFp1nTy/q6gNLsxXrg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-decorators": "^7.27.1" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "requires": {} + }, + "@babel/plugin-syntax-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz", + "integrity": "sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz", + "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.1.tgz", + "integrity": "sha512-QEcFlMl9nGTgh1rn2nIeU5bkfb9BAjaQcWbiP4LvKxUot52ABcTkpcyJ7f2Q2U2RuQ84BNLgts3jRme2dTx6Fw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", + "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz", + "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.1.tgz", + "integrity": "sha512-ttDCqhfvpE9emVkXbPD8vyxxh4TWYACVybGkDj+oReOGwnp066ITEivDlLwe0b1R0+evJ13IXQuLNB5w1fhC5Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.2.tgz", + "integrity": "sha512-AIUHD7xJ1mCrj3uPozvtngY3s0xpv7Nu7DoUSnzNY6Xam1Cy4rUznR//pvMHOhQ4AvbCexhbqXCtpxGHOGOO6g==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz", + "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.1.tgz", + "integrity": "sha512-B19lbbL7PMrKr52BNPjCqg1IyNUIjTcxKj8uX9zHO+PmWN93s19NDr/f69mIkEp2x9nmDJ08a7lgHaTTzvW7mw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.1.tgz", + "integrity": "sha512-TqGF3desVsTcp3WrJGj4HfKokfCXCLcHpt4PJF0D8/iT6LPd9RS82Upw3KPeyr6B22Lfd3DO8MVrmp0oRkUDdw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/preset-env": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.2.tgz", + "integrity": "sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.27.1", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.27.1", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.27.2", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.27.1", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.40.0", + "semver": "^6.3.1" + } + }, + "@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "dev": true + }, + "@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + } + }, + "@babel/traverse": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", + "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", + "debug": "^4.3.1", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "requires": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + } + }, + "@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==" + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@element-plus/icons-vue": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz", + "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==", + "requires": {} + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@floating-ui/core": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz", + "integrity": "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==", + "requires": { + "@floating-ui/utils": "^0.2.9" + } + }, + "@floating-ui/dom": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.0.tgz", + "integrity": "sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==", + "requires": { + "@floating-ui/core": "^1.7.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==" + }, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "@node-ipc/js-queue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@node-ipc/js-queue/-/js-queue-2.0.3.tgz", + "integrity": "sha512-fL1wpr8hhD5gT2dA1qifeVaoDFlQR5es8tFuKqjHX+kdOtdNHnxkVZbtIrR2rxnMFvehkjaZRNV2H/gPXlb0hw==", + "dev": true, + "requires": { + "easy-stack": "1.0.1" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true + }, + "@popperjs/core": { + "version": "npm:@sxzz/popperjs-es@2.11.7", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==" + }, + "@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "@soda/friendly-errors-webpack-plugin": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz", + "integrity": "sha512-h2ooWqP8XuFqTXT+NyAFbrArzfQA7R6HTezADrvD9Re8fxMLTPPniLdqVTdDaO0eIoLaAwKT+d6w+5GeTk7Vbg==", + "dev": true, + "requires": { + "chalk": "^3.0.0", + "error-stack-parser": "^2.0.6", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + } + }, + "@soda/get-current-script": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@soda/get-current-script/-/get-current-script-1.0.2.tgz", + "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", + "dev": true + }, + "@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true + }, + "@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/eslint": { + "version": "8.56.12", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", + "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true + }, + "@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + }, + "dependencies": { + "@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + } + } + }, + "@types/express-serve-static-core": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", + "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "@types/http-proxy": { + "version": "1.17.16", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", + "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "@types/lodash": { + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", + "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==" + }, + "@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "requires": { + "@types/lodash": "*" + } + }, + "@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, + "@types/node": { + "version": "22.15.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz", + "integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==", + "dev": true, + "requires": { + "undici-types": "~6.21.0" + } + }, + "@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "@types/qs": { + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "requires": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" + }, + "@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", + "integrity": "sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==", + "dev": true + }, + "@vue/babel-helper-vue-transform-on": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.4.0.tgz", + "integrity": "sha512-mCokbouEQ/ocRce/FpKCRItGo+013tHg7tixg3DUNS+6bmIchPt66012kBMm476vyEIJPafrvOf4E5OYj3shSw==", + "dev": true + }, + "@vue/babel-plugin-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.4.0.tgz", + "integrity": "sha512-9zAHmwgMWlaN6qRKdrg1uKsBKHvnUU+Py+MOCTuYZBoZsopa90Di10QRjB+YPnVss0BZbG/H5XFwJY1fTxJWhA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.9", + "@babel/types": "^7.26.9", + "@vue/babel-helper-vue-transform-on": "1.4.0", + "@vue/babel-plugin-resolve-type": "1.4.0", + "@vue/shared": "^3.5.13" + } + }, + "@vue/babel-plugin-resolve-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.4.0.tgz", + "integrity": "sha512-4xqDRRbQQEWHQyjlYSgZsWj44KfiF6D+ktCuXyZ8EnVDYV3pztmXJDf1HveAjUAXxAnR8daCQT51RneWWxtTyQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.26.2", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/parser": "^7.26.9", + "@vue/compiler-sfc": "^3.5.13" + } + }, + "@vue/babel-plugin-transform-vue-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.4.0.tgz", + "integrity": "sha512-Fmastxw4MMx0vlgLS4XBX0XiBbUFzoMGeVXuMV08wyOfXdikAFqBTuYPR0tlk+XskL19EzHc39SgjrPGY23JnA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + } + }, + "@vue/babel-preset-app": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-5.0.8.tgz", + "integrity": "sha512-yl+5qhpjd8e1G4cMXfORkkBlvtPCIgmRf3IYCWYDKIQ7m+PPa5iTm4feiNmCMD6yGqQWMhhK/7M3oWGL9boKwg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.16", + "@babel/helper-compilation-targets": "^7.12.16", + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-proposal-class-properties": "^7.12.13", + "@babel/plugin-proposal-decorators": "^7.12.13", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/plugin-transform-runtime": "^7.12.15", + "@babel/preset-env": "^7.12.16", + "@babel/runtime": "^7.12.13", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.1.2", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.8.3", + "core-js-compat": "^3.8.3", + "semver": "^7.3.4" + }, + "dependencies": { + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "@vue/babel-preset-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.4.0.tgz", + "integrity": "sha512-QmfRpssBOPZWL5xw7fOuHNifCQcNQC1PrOo/4fu6xlhlKJJKSA3HqX92Nvgyx8fqHZTUGMPHmFA+IDqwXlqkSA==", + "dev": true, + "requires": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "@vue/babel-sugar-composition-api-inject-h": "^1.4.0", + "@vue/babel-sugar-composition-api-render-instance": "^1.4.0", + "@vue/babel-sugar-functional-vue": "^1.4.0", + "@vue/babel-sugar-inject-h": "^1.4.0", + "@vue/babel-sugar-v-model": "^1.4.0", + "@vue/babel-sugar-v-on": "^1.4.0" + } + }, + "@vue/babel-sugar-composition-api-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.4.0.tgz", + "integrity": "sha512-VQq6zEddJHctnG4w3TfmlVp5FzDavUSut/DwR0xVoe/mJKXyMcsIibL42wPntozITEoY90aBV0/1d2KjxHU52g==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-composition-api-render-instance": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.4.0.tgz", + "integrity": "sha512-6ZDAzcxvy7VcnCjNdHJ59mwK02ZFuP5CnucloidqlZwVQv5CQLijc3lGpR7MD3TWFi78J7+a8J56YxbCtHgT9Q==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-functional-vue": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.4.0.tgz", + "integrity": "sha512-lTEB4WUFNzYt2In6JsoF9sAYVTo84wC4e+PoZWSgM6FUtqRJz7wMylaEhSRgG71YF+wfLD6cc9nqVeXN2rwBvw==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.4.0.tgz", + "integrity": "sha512-muwWrPKli77uO2fFM7eA3G1lAGnERuSz2NgAxuOLzrsTlQl8W4G+wwbM4nB6iewlKbwKRae3nL03UaF5ffAPMA==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-v-model": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.4.0.tgz", + "integrity": "sha512-0t4HGgXb7WHYLBciZzN5s0Hzqan4Ue+p/3FdQdcaHAb7s5D9WZFGoSxEZHrR1TFVZlAPu1bejTKGeAzaaG3NCQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + } + }, + "@vue/babel-sugar-v-on": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.4.0.tgz", + "integrity": "sha512-m+zud4wKLzSKgQrWwhqRObWzmTuyzl6vOP7024lrpeJM4x2UhQtRDLgYjXAw9xBXjCwS0pP9kXjg91F9ZNo9JA==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0" + } + }, + "@vue/cli-overlay": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.8.tgz", + "integrity": "sha512-KmtievE/B4kcXp6SuM2gzsnSd8WebkQpg3XaB6GmFh1BJGRqa1UiW9up7L/Q67uOdTigHxr5Ar2lZms4RcDjwQ==", + "dev": true + }, + "@vue/cli-plugin-babel": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-babel/-/cli-plugin-babel-5.0.8.tgz", + "integrity": "sha512-a4qqkml3FAJ3auqB2kN2EMPocb/iu0ykeELwed+9B1c1nQ1HKgslKMHMPavYx3Cd/QAx2mBD4hwKBqZXEI/CsQ==", + "dev": true, + "requires": { + "@babel/core": "^7.12.16", + "@vue/babel-preset-app": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "babel-loader": "^8.2.2", + "thread-loader": "^3.0.0", + "webpack": "^5.54.0" + } + }, + "@vue/cli-plugin-eslint": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-5.0.8.tgz", + "integrity": "sha512-d11+I5ONYaAPW1KyZj9GlrV/E6HZePq5L5eAF5GgoVdu6sxr6bDgEoxzhcS1Pk2eh8rn1MxG/FyyR+eCBj/CNg==", + "dev": true, + "requires": { + "@vue/cli-shared-utils": "^5.0.8", + "eslint-webpack-plugin": "^3.1.0", + "globby": "^11.0.2", + "webpack": "^5.54.0", + "yorkie": "^2.0.0" + } + }, + "@vue/cli-plugin-router": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-5.0.8.tgz", + "integrity": "sha512-Gmv4dsGdAsWPqVijz3Ux2OS2HkMrWi1ENj2cYL75nUeL+Xj5HEstSqdtfZ0b1q9NCce+BFB6QnHfTBXc/fCvMg==", + "dev": true, + "requires": { + "@vue/cli-shared-utils": "^5.0.8" + } + }, + "@vue/cli-plugin-vuex": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.8.tgz", + "integrity": "sha512-HSYWPqrunRE5ZZs8kVwiY6oWcn95qf/OQabwLfprhdpFWAGtLStShjsGED2aDpSSeGAskQETrtR/5h7VqgIlBA==", + "dev": true, + "requires": {} + }, + "@vue/cli-service": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-5.0.8.tgz", + "integrity": "sha512-nV7tYQLe7YsTtzFrfOMIHc5N2hp5lHG2rpYr0aNja9rNljdgcPZLyQRb2YRivTHqTv7lI962UXFURcpStHgyFw==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.12.16", + "@soda/friendly-errors-webpack-plugin": "^1.8.0", + "@soda/get-current-script": "^1.0.2", + "@types/minimist": "^1.2.0", + "@vue/cli-overlay": "^5.0.8", + "@vue/cli-plugin-router": "^5.0.8", + "@vue/cli-plugin-vuex": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "@vue/component-compiler-utils": "^3.3.0", + "@vue/vue-loader-v15": "npm:vue-loader@^15.9.7", + "@vue/web-component-wrapper": "^1.3.0", + "acorn": "^8.0.5", + "acorn-walk": "^8.0.2", + "address": "^1.1.2", + "autoprefixer": "^10.2.4", + "browserslist": "^4.16.3", + "case-sensitive-paths-webpack-plugin": "^2.3.0", + "cli-highlight": "^2.1.10", + "clipboardy": "^2.3.0", + "cliui": "^7.0.4", + "copy-webpack-plugin": "^9.0.1", + "css-loader": "^6.5.0", + "css-minimizer-webpack-plugin": "^3.0.2", + "cssnano": "^5.0.0", + "debug": "^4.1.1", + "default-gateway": "^6.0.3", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "hash-sum": "^2.0.0", + "html-webpack-plugin": "^5.1.0", + "is-file-esm": "^1.0.0", + "launch-editor-middleware": "^2.2.1", + "lodash.defaultsdeep": "^4.6.1", + "lodash.mapvalues": "^4.6.0", + "mini-css-extract-plugin": "^2.5.3", + "minimist": "^1.2.5", + "module-alias": "^2.2.2", + "portfinder": "^1.0.26", + "postcss": "^8.2.6", + "postcss-loader": "^6.1.1", + "progress-webpack-plugin": "^1.0.12", + "ssri": "^8.0.1", + "terser-webpack-plugin": "^5.1.1", + "thread-loader": "^3.0.0", + "vue-loader": "^17.0.0", + "vue-style-loader": "^4.1.3", + "webpack": "^5.54.0", + "webpack-bundle-analyzer": "^4.4.0", + "webpack-chain": "^6.5.1", + "webpack-dev-server": "^4.7.3", + "webpack-merge": "^5.7.3", + "webpack-virtual-modules": "^0.4.2", + "whatwg-fetch": "^3.6.2" + } + }, + "@vue/cli-shared-utils": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.8.tgz", + "integrity": "sha512-uK2YB7bBVuQhjOJF+O52P9yFMXeJVj7ozqJkwYE9PlMHL1LMHjtCYm4cSdOebuPzyP+/9p0BimM/OqxsevIopQ==", + "dev": true, + "requires": { + "@achrinza/node-ipc": "^9.2.5", + "chalk": "^4.1.2", + "execa": "^1.0.0", + "joi": "^17.4.0", + "launch-editor": "^2.2.1", + "lru-cache": "^6.0.0", + "node-fetch": "^2.6.7", + "open": "^8.0.2", + "ora": "^5.3.0", + "read-pkg": "^5.1.1", + "semver": "^7.3.4", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@vue/compiler-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "requires": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "@vue/compiler-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "requires": { + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "@vue/compiler-sfc": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "requires": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" + } + }, + "@vue/compiler-ssr": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "requires": { + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "@vue/component-compiler-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", + "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", + "dev": true, + "requires": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "prettier": "^1.18.2 || ^2.0.0", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "requires": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + } + } + }, + "@vue/reactivity": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "requires": { + "@vue/shared": "3.5.13" + } + }, + "@vue/runtime-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "requires": { + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "@vue/runtime-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "requires": { + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" + } + }, + "@vue/server-renderer": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "requires": { + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "@vue/shared": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==" + }, + "@vue/vue-loader-v15": { + "version": "npm:vue-loader@15.11.1", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.11.1.tgz", + "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==", + "dev": true, + "requires": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + } + } + }, + "@vue/web-component-wrapper": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz", + "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", + "dev": true + }, + "@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "requires": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "dependencies": { + "vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "requires": {} + } + } + }, + "@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==" + }, + "@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "requires": { + "vue-demi": "*" + }, + "dependencies": { + "vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "requires": {} + } + } + }, + "@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "dependencies": { + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + } + } + }, + "acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "requires": { + "acorn": "^8.11.0" + } + }, + "address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true + }, + "async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "requires": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + } + }, + "axios": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", + "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.4", + "semver": "^6.3.1" + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", + "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.6.4" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "requires": { + "fill-range": "^7.1.1" + } + }, + "browserslist": { + "version": "4.24.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", + "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001716", + "electron-to-chromium": "^1.5.149", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + } + }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, + "call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001718", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", + "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", + "dev": true + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true + }, + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true + }, + "clipboardy": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz", + "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", + "dev": true, + "requires": { + "arch": "^2.1.1", + "execa": "^1.0.0", + "is-wsl": "^2.1.1" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true + }, + "consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "dev": true, + "requires": { + "bluebird": "^3.1.1" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "copy-webpack-plugin": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==", + "dev": true, + "requires": { + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.1", + "globby": "^11.0.3", + "normalize-path": "^3.0.0", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "core-js": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz", + "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==" + }, + "core-js-compat": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.42.0.tgz", + "integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==", + "dev": true, + "requires": { + "browserslist": "^4.24.4" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "requires": {} + }, + "css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "dependencies": { + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dev": true, + "requires": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dev": true, + "requires": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + } + }, + "cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dev": true, + "requires": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + } + }, + "cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "dev": true, + "requires": {} + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + } + }, + "csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, + "debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "dev": true + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + }, + "dependencies": { + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + } + } + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "easy-stack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", + "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==", + "dev": true + }, + "echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "requires": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.5.152", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.152.tgz", + "integrity": "sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg==", + "dev": true + }, + "element-plus": { + "version": "2.9.10", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.10.tgz", + "integrity": "sha512-W2v9jWnm1kl/zm4bSvCh8aFCVlxvhG3fmqiDZwyd6WQiWGE595J/mpjcCggEr+49QDgIymhXrpPMOPPSARUbng==", + "requires": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.13", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + } + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "requires": { + "stackframe": "^1.3.4" + } + }, + "es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true + }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-plugin-vue": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", + "dev": true, + "requires": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "dependencies": { + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "requires": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "event-pubsub": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", + "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true + }, + "fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + } + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==" + }, + "form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + } + } + }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "requires": { + "duplexer": "^0.1.2" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "dev": true + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "requires": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + } + }, + "html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "dev": true + }, + "html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "dev": true, + "requires": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "requires": {} + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "requires": { + "ci-info": "^1.5.0" + } + }, + "is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "requires": { + "hasown": "^2.0.2" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-file-esm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-file-esm/-/is-file-esm-1.0.0.tgz", + "integrity": "sha512-rZlaNKb4Mr8WlRu2A9XdeoKgnO5aA53XdPHgCKVyCrQ/rWi89RET1+bq37Ru46obaQXeiX4vmFIm1vks41hoSA==", + "dev": true, + "requires": { + "read-pkg-up": "^7.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "js-message": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", + "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true + }, + "launch-editor": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", + "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", + "dev": true, + "requires": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "launch-editor-middleware": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.10.0.tgz", + "integrity": "sha512-RzZu7MeVlE3p1H6Sadc2BhuDGAj7bkeDCBpNq/zSENP4ohJGhso00k5+iYaRwKshIpiOAhMmimce+5D389xmSg==", + "dev": true, + "requires": { + "launch-editor": "^2.10.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "requires": {} + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "lodash.mapvalues": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + } + } + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", + "dev": true, + "requires": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "module-alias": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==", + "dev": true + }, + "mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true + }, + "normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "requires": { + "path-key": "^2.0.0" + }, + "dependencies": { + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + } + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "requires": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, + "optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + } + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "portfinder": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.37.tgz", + "integrity": "sha512-yuGIEjDAYnnOex9ddMnKZEMFE0CcGo6zbfzDklkmT1m5z734ss6JMzN9rNB3+RR7iS+F10D4/BVIaXOyh8PQKw==", + "dev": true, + "requires": { + "async": "^3.2.6", + "debug": "^4.3.6" + } + }, + "postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "requires": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + } + }, + "postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "dev": true, + "requires": {} + }, + "postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "dev": true, + "requires": {} + }, + "postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "dev": true, + "requires": {} + }, + "postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "dev": true, + "requires": {} + }, + "postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + } + }, + "postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dev": true, + "requires": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + } + } + }, + "postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^7.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + } + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "dev": true, + "requires": {} + }, + "postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dev": true, + "requires": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dev": true, + "requires": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + } + }, + "postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true + }, + "pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "progress-webpack-plugin": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/progress-webpack-plugin/-/progress-webpack-plugin-1.0.16.tgz", + "integrity": "sha512-sdiHuuKOzELcBANHfrupYo+r99iPRyOnw15qX+rNlVUqXGfjXdH4IgxriKwG1kNJwVswKQHMdj1hYZMcb9jFaA==", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "figures": "^2.0.0", + "log-update": "^2.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + } + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "requires": { + "side-channel": "^1.0.6" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, + "regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "requires": { + "jsesc": "~3.0.2" + }, + "dependencies": { + "jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true + }, + "renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "requires": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + }, + "reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "requires": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "requires": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + } + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true + }, + "side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + } + }, + "side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + } + }, + "side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "requires": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + } + }, + "side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "requires": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "requires": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "terser": { + "version": "5.39.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.1.tgz", + "integrity": "sha512-Mm6+uad0ZuDtcV8/4uOZQDQ8RuiC5Pu+iZRedJtF7yA/27sPL7d++In/AJKpWZlU3SYMPPkVfwetn6sgZ66pUA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "thread-loader": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/thread-loader/-/thread-loader-3.0.4.tgz", + "integrity": "sha512-ByaL2TPb+m6yArpqQUZvP+5S1mZtXsEP7nWKKlAUTm7fCml8kB5s1uI3+eHRP2bk5mVYfRSBI7FFf+tWEyLZwA==", + "dev": true, + "requires": { + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.1.0", + "loader-utils": "^2.0.0", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "requires": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, + "vue": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "requires": { + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "dependencies": { + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", + "dev": true + }, + "vue-loader": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.4.2.tgz", + "integrity": "sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "watchpack": "^2.4.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "vue-style-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", + "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", + "dev": true, + "requires": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + } + } + }, + "vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", + "dev": true + }, + "watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "webpack": { + "version": "5.99.8", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.8.tgz", + "integrity": "sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.2", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "webpack-chain": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-6.5.1.tgz", + "integrity": "sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==", + "dev": true, + "requires": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^2.0.1" + } + }, + "webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dev": true, + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "dev": true, + "requires": {} + } + } + }, + "webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "webpack-virtual-modules": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz", + "integrity": "sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==", + "dev": true + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "requires": {} + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, + "yorkie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz", + "integrity": "sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==", + "dev": true, + "requires": { + "execa": "^0.8.0", + "is-ci": "^1.0.10", + "normalize-path": "^1.0.0", + "strip-indent": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", + "integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "normalize-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz", + "integrity": "sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + } + } + }, + "zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "requires": { + "tslib": "2.3.0" + } + } + } +} diff --git a/src/声源定位代码/front-code/sound-vue-frontend/package.json b/src/声源定位代码/front-code/sound-vue-frontend/package.json new file mode 100644 index 0000000..8d8a753 --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/package.json @@ -0,0 +1,38 @@ +{ + "name": "sound-vue-frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "axios": "^1.3.4", + "core-js": "^3.8.3", + "echarts": "^5.4.1", + "element-plus": "^2.3.0", + "vue": "^3.2.13" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "eslint": "^7.32.0", + "eslint-plugin-vue": "^8.0.3" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/vue3-essential", + "eslint:recommended" + ], + "parserOptions": { + "ecmaVersion": 2020 + }, + "rules": {} + } +} diff --git a/src/声源定位代码/front-code/sound-vue-frontend/src/App.vue b/src/声源定位代码/front-code/sound-vue-frontend/src/App.vue new file mode 100644 index 0000000..2bbe379 --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/src/App.vue @@ -0,0 +1,344 @@ + + + + + diff --git a/src/声源定位代码/front-code/sound-vue-frontend/src/assets/main.css b/src/声源定位代码/front-code/sound-vue-frontend/src/assets/main.css new file mode 100644 index 0000000..d9adb15 --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/src/assets/main.css @@ -0,0 +1,19 @@ +/* 基础样式重置 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + color: #2c3e50; + background-color: #f5f7fa; +} + +#app { + width: 100%; + min-height: 100vh; +} diff --git a/src/声源定位代码/front-code/sound-vue-frontend/src/components/SourceDataService.js b/src/声源定位代码/front-code/sound-vue-frontend/src/components/SourceDataService.js new file mode 100644 index 0000000..8ea1718 --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/src/components/SourceDataService.js @@ -0,0 +1,11 @@ +// 声源数据接口服务 +import axios from 'axios'; + +const API_BASE_URL = 'http://127.0.0.1:5000'; // 根据实际后端地址进行配置 + +export default { + // 获取最新声源数据 + getSourceData() { + return axios.get(`${API_BASE_URL}/data`); + } +}; diff --git a/src/声源定位代码/front-code/sound-vue-frontend/src/main.js b/src/声源定位代码/front-code/sound-vue-frontend/src/main.js new file mode 100644 index 0000000..8c18c11 --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/src/main.js @@ -0,0 +1,8 @@ +import { createApp } from 'vue' +import App from './App.vue' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' + +const app = createApp(App) +app.use(ElementPlus) +app.mount('#app') diff --git a/src/声源定位代码/front-code/sound-vue-frontend/vue.config.js b/src/声源定位代码/front-code/sound-vue-frontend/vue.config.js new file mode 100644 index 0000000..d840b2c --- /dev/null +++ b/src/声源定位代码/front-code/sound-vue-frontend/vue.config.js @@ -0,0 +1,13 @@ +module.exports = { + devServer: { + proxy: { + '/api': { + target: 'http://localhost:5000', + changeOrigin: true, + pathRewrite: { + '^/api': '' + } + } + } + } +} diff --git a/src/声源定位代码/mic-code/Maix/Maix_config.c b/src/声源定位代码/mic-code/Maix/Maix_config.c new file mode 100644 index 0000000..15a70bd --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/Maix_config.c @@ -0,0 +1,423 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/objlist.h" +#include "py/objstringio.h" +#include "py/parsenum.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/objmodule.h" +#include "py/objstringio.h" +#include "mphalport.h" +#include "vfs_internal.h" + +#include "Maix_config.h" + +// static void unit_test_json_config(); + +mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) +{ + size_t max = dict->map.alloc; + mp_map_t *map = &dict->map; + + for (size_t i = *cur; i < max; i++) + { + if (mp_map_slot_is_filled(map, i)) + { + *cur = i + 1; + return &(map->table[i]); + } + } + + return NULL; +} + +#define MAIX_CONFIG_PATH "/flash/config.json" + +typedef struct +{ + mp_obj_base_t base; + mp_obj_t cache; + mp_obj_t args[3]; +} maix_config_t; + +static maix_config_t *config_obj = NULL; + +static mp_obj_t maix_config_cache() +{ + // printf("%s\r\n", __func__); + typedef struct + { + mp_obj_base_t base; + } fs_info_t; + + int err = 0; + fs_info_t *cfg = vfs_internal_open(MAIX_CONFIG_PATH, "rb", &err); + if (err != 0) + { + // printf("no config time:%ld\r\n", systick_current_millis()); + } + else + { + // printf("exist config time:%ld\r\n", systick_current_millis()); + config_obj->args[2] = MP_OBJ_FROM_PTR(&(cfg->base)); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) + { + config_obj->cache = mp_call_method_n_kw(1, 0, config_obj->args); + nlr_pop(); + vfs_internal_close(cfg, &err); + return mp_const_true; + } + else + { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } + vfs_internal_close(cfg, &err); + } + return mp_const_false; +} + +mp_obj_t maix_config_get_value(mp_obj_t key, mp_obj_t def_value) +{ + // printf("%s\r\n", __func__); + if (config_obj != NULL) + { + if (false == mp_obj_is_type(config_obj->cache, &mp_type_dict)) + { + // maybe gc.collect() + if (mp_const_false == maix_config_cache()) + { + return def_value; + } + } + // mp_printf(&mp_plat_print, "print(config_obj->cache)\r\n"); + // mp_obj_print_helper(&mp_plat_print, config_obj->cache, PRINT_STR); + // mp_printf(&mp_plat_print, "\r\n"); + // mp_check_self(mp_obj_is_dict_type(config_obj->cache)); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(config_obj->cache); + mp_map_elem_t *elem = mp_map_lookup(&self->map, key, MP_MAP_LOOKUP); + if (elem == NULL || elem->value == MP_OBJ_NULL) + { + return def_value; // not exist + } + else + { + return elem->value; + } + } + return def_value; +} +MP_DEFINE_CONST_FUN_OBJ_2(maix_config_get_value_obj, maix_config_get_value); + +mp_obj_t maix_config_init() +{ + // printf("%s\r\n", __func__); + // unit_test_json_config(); + static maix_config_t tmp; + mp_obj_t module_obj = mp_module_get(MP_QSTR_ujson); + if (module_obj != MP_OBJ_NULL) + { + // mp_printf(&mp_plat_print, "import josn\r\n"); + mp_load_method_maybe(module_obj, MP_QSTR_load, tmp.args); + if (tmp.args[0] != MP_OBJ_NULL) + { + config_obj = &tmp; + return maix_config_cache(); + // return mp_const_true; + } + } + mp_printf(&mp_plat_print, "[%s]|(%s)\r\n", __func__, "fail"); + return mp_const_false; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(maix_config_init_obj, maix_config_init); + +static const mp_map_elem_t locals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_config)}, + {MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&maix_config_init_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_value), MP_ROM_PTR(&maix_config_get_value_obj)}, +}; + +STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); + +const mp_obj_type_t Maix_config_type = { + .base = {&mp_type_type}, + .name = MP_QSTR_config, + .locals_dict = (mp_obj_dict_t *)&locals_dict}; + +#ifdef UNIT_TEST + +/* +{ + "config_name": "config.json", + "lcd":{ + "RST_IO":16, + "DCX_IO":32 + }, + "freq_cpu": 416000000, + "freq_pll1": 400000000, + "kpu_div": 1 +} +*/ + +static void unit_test_json_config() +{ + // unit_test get string + { + const char key[] = "config_name"; + mp_obj_t tmp = maix_config_get_value(mp_obj_new_str(key, sizeof(key) - 1), mp_obj_new_str("None Cfg", 8)); + if (mp_obj_is_str(tmp)) + { + const char *value = mp_obj_str_get_str(tmp); + mp_printf(&mp_plat_print, "%s %s\r\n", key, value); + } + } + + // get lcd dict key-value + { + const char key[] = "lcd"; + mp_obj_t tmp = maix_config_get_value(mp_obj_new_str(key, sizeof(key) - 1), mp_obj_new_dict(0)); + if (mp_obj_is_type(tmp, &mp_type_dict)) + { + mp_obj_dict_t *self = MP_OBJ_TO_PTR(tmp); + size_t cur = 0; + mp_map_elem_t *next = NULL; + bool first = true; + while ((next = dict_iter_next(self, &cur)) != NULL) + { + if (!first) + { + mp_print_str(&mp_plat_print, ", "); + } + first = false; + mp_obj_print_helper(&mp_plat_print, next->key, PRINT_STR); + mp_print_str(&mp_plat_print, ": "); + mp_obj_print_helper(&mp_plat_print, next->value, PRINT_STR); + } + } + } +} + +static void unit_test_json_config() +{ + mp_obj_t module_obj = mp_module_get(MP_QSTR_ujson); + if (module_obj != MP_OBJ_NULL) + { + mp_printf(&mp_plat_print, "import josn\r\n"); + mp_obj_t dest[3]; + mp_load_method_maybe(module_obj, MP_QSTR_loads, dest); + if (dest[0] != MP_OBJ_NULL) + { + const char json[] = "{\"a\":1,\"b\":2,\"c\":3,\"d\":4,\"e\":\"helloworld\"}"; + mp_printf(&mp_plat_print, "nresult = josn.loads(%s)\r\n", json); + dest[2] = mp_obj_new_str(json, sizeof(json) - 1); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) + { + mp_obj_t result = mp_call_method_n_kw(1, 0, dest); + mp_printf(&mp_plat_print, "print(result)\r\n"); + mp_obj_print_helper(&mp_plat_print, result, PRINT_STR); + mp_printf(&mp_plat_print, "\r\n"); + const char goal[] = "e"; + //mp_check_self(mp_obj_is_dict_type(result)); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(result); + mp_map_elem_t *elem = mp_map_lookup(&self->map, mp_obj_new_str(goal, sizeof(goal) - 1), MP_MAP_LOOKUP); + mp_obj_t value; + if (elem == NULL || elem->value == MP_OBJ_NULL) + { + // not exist + } + else + { + value = elem->value; + //mp_check_self(mp_obj_is_str_type(value)); + mp_printf(&mp_plat_print, "print(result.get('%s'))\r\n", goal); + mp_obj_print_helper(&mp_plat_print, value, PRINT_STR); + mp_printf(&mp_plat_print, "\r\n"); + } + nlr_pop(); + } + else + { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } + } + mp_load_method_maybe(module_obj, MP_QSTR_load, dest); + if (dest[0] != MP_OBJ_NULL) + { + const char json[] = "{\"a\":1,\"b\":2,\"c\":3,\"d\":4,\"e\":\"helloworld\"}"; + mp_printf(&mp_plat_print, "nresult = josn.load(%s)\r\n", json); + mp_obj_t obj = mp_obj_new_str(json, sizeof(json) - 1); + size_t len; + const char *buf = mp_obj_str_get_data(obj, &len); + vstr_t vstr = {len, len, (char *)buf, true}; + mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL}; + dest[2] = MP_OBJ_FROM_PTR(&sio); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) + { + mp_obj_t result = mp_call_method_n_kw(1, 0, dest); + mp_printf(&mp_plat_print, "print(result)\r\n"); + mp_obj_print_helper(&mp_plat_print, result, PRINT_STR); + mp_printf(&mp_plat_print, "\r\n"); + const char goal[] = "a"; + //mp_check_self(mp_obj_is_dict_type(result)); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(result); + mp_map_elem_t *elem = mp_map_lookup(&self->map, mp_obj_new_str(goal, sizeof(goal) - 1), MP_MAP_LOOKUP); + mp_obj_t value; + if (elem == NULL || elem->value == MP_OBJ_NULL) + { + // not exist + } + else + { + value = elem->value; + //mp_check_self(mp_obj_is_str_type(value)); + mp_printf(&mp_plat_print, "print(result.get('%s'))\r\n", goal); + mp_obj_print_helper(&mp_plat_print, value, PRINT_STR); + mp_printf(&mp_plat_print, "\r\n"); + } + nlr_pop(); + } + else + { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } + } + typedef struct + { + mp_obj_base_t base; + } fs_info_t; + { + + int err = 0; + fs_info_t *cfg = vfs_internal_open("/flash/config.json", "rb", &err); + if (err != 0) + { + printf("no config time:%ld\r\n", systick_current_millis()); + } + else + { + // mp_stream_p_t* stream = (mp_stream_p_t*)cfg->base.type->protocol; + printf("exist config time:%ld\r\n", systick_current_millis()); + mp_load_method_maybe(module_obj, MP_QSTR_load, dest); + if (dest[0] != MP_OBJ_NULL) + { + dest[2] = MP_OBJ_FROM_PTR(&(cfg->base)); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) + { + mp_obj_t result = mp_call_method_n_kw(1, 0, dest); + mp_printf(&mp_plat_print, "print(result)\r\n"); + mp_obj_print_helper(&mp_plat_print, result, PRINT_STR); + mp_printf(&mp_plat_print, "\r\n"); + const char goal[] = "a"; + //mp_check_self(mp_obj_is_dict_type(result)); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(result); + mp_map_elem_t *elem = mp_map_lookup(&self->map, mp_obj_new_str(goal, sizeof(goal) - 1), MP_MAP_LOOKUP); + mp_obj_t value; + if (elem == NULL || elem->value == MP_OBJ_NULL) + { + // not exist + } + else + { + value = elem->value; + //mp_check_self(mp_obj_is_str_type(value)); + mp_printf(&mp_plat_print, "print(result.get('%s'))\r\n", goal); + mp_obj_print_helper(&mp_plat_print, value, PRINT_STR); + mp_printf(&mp_plat_print, "\r\n"); + } + nlr_pop(); + } + else + { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } + + vfs_internal_close(cfg, &err); + } + } + } + + { + + int err = 0; + fs_info_t *cfg = vfs_internal_open("/flash/config.json", "rb", &err); + if (err != 0) + { + printf("no config time:%ld\r\n", systick_current_millis()); + } + else + { + // mp_stream_p_t* stream = (mp_stream_p_t*)cfg->base.type->protocol; + printf("exist config time:%ld\r\n", systick_current_millis()); + mp_load_method_maybe(module_obj, MP_QSTR_load, dest); + if (dest[0] != MP_OBJ_NULL) + { + dest[2] = MP_OBJ_FROM_PTR(&(cfg->base)); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) + { + mp_obj_t result = mp_call_method_n_kw(1, 0, dest); + mp_printf(&mp_plat_print, "print(result)\r\n"); + mp_obj_print_helper(&mp_plat_print, result, PRINT_STR); + mp_printf(&mp_plat_print, "\r\n"); + const char goal[] = "e"; + //mp_check_self(mp_obj_is_dict_type(result)); + mp_obj_dict_t *self = MP_OBJ_TO_PTR(result); + mp_map_elem_t *elem = mp_map_lookup(&self->map, mp_obj_new_str(goal, sizeof(goal) - 1), MP_MAP_LOOKUP); + mp_obj_t value; + if (elem == NULL || elem->value == MP_OBJ_NULL) + { + // not exist + } + else + { + value = elem->value; + //mp_check_self(mp_obj_is_str_type(value)); + mp_printf(&mp_plat_print, "print(result.get('%s'))\r\n", goal); + mp_obj_print_helper(&mp_plat_print, value, PRINT_STR); + mp_printf(&mp_plat_print, "\r\n"); + } + nlr_pop(); + } + else + { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } + + vfs_internal_close(cfg, &err); + } + } + } + } +} + +#endif diff --git a/src/声源定位代码/mic-code/Maix/Maix_fft.c b/src/声源定位代码/mic-code/Maix/Maix_fft.c new file mode 100644 index 0000000..8093996 --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/Maix_fft.c @@ -0,0 +1,195 @@ +/* +* Copyright 2019 Sipeed Co.,Ltd. + +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include + +#include "dmac.h" +#include "hal_fft.h" +#include "i2s.h" +#include "math.h" + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/objarray.h" +#include "py/binary.h" +#include "mphalport.h" +#include "modMaix.h" + +#define MAX_SAMPLE_RATE 65535 +#define MAX_BUFFER_LEN 1024 + +const mp_obj_type_t Maix_fft_type; + +STATIC mp_obj_t Maix_fft_run(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) + { + //----------parse parameter--------------- + enum{ARG_byte, + ARG_points, + ARG_shift, + ARG_direction, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_byte, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_points, MP_ARG_INT, {.u_int = 64} }, + { MP_QSTR_shift, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_direction, MP_ARG_INT, {.u_int = FFT_DIR_FORWARD} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint32_t points = args[ARG_points].u_int; + uint32_t shift = args[ARG_shift].u_int; + uint32_t direction = args[ARG_direction].u_int; + + if(points != 64 && points != 128 && points != 256 && points != 512) + { + mp_raise_ValueError("[MAIXPY]FFT:invalid points"); + } + + uint32_t byte_len = 0; + uint32_t* byte_addr = NULL; + + if( args[ARG_byte].u_obj != mp_const_none) + { + mp_obj_t byte = args[ARG_byte].u_obj; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(byte, &bufinfo, MP_BUFFER_READ); + byte_len = bufinfo.len; + byte_addr = (uint32_t*)bufinfo.buf; + } + else + { + mp_raise_ValueError("[MAIXPY]FFT:invalid byte"); + } + if(byte_len % 4 != 0) + { + mp_raise_ValueError("[MAIXPY]FFT:Buffer length must be a multiple of 4"); + } + // how to get the length of i2s buffer? + if(byte_len < points * 4) + { + mp_printf(&mp_plat_print, "[MAIXPY]FFT:Zero padding\n"); + memset(byte_addr+byte_len, 0, points * 4 - byte_len );//Zero padding + } + + //------------------get data---------------------- + uint64_t* buffer_input = (uint64_t*)m_new(uint64_t, points);//m_new + uint64_t* buffer_output = (uint64_t*)m_new(uint64_t ,points);//m_new + fft_data_t * input_data = NULL; + fft_data_t * output_data = NULL; + for(int i = 0; i < points / 2; ++i) + { + input_data = (fft_data_t *)&buffer_input[i]; + input_data->R1 = byte_addr[2*i]; + input_data->I1 = 0; + input_data->R2 = byte_addr[2*i+1]; + input_data->I2 = 0; + } + //run fft + fft_complex_uint16_dma(DMAC_CHANNEL3, DMAC_CHANNEL4,shift,direction,buffer_input,points,buffer_output); + //return a list + mp_obj_list_t* ret_list = (mp_obj_list_t*)m_new(mp_obj_list_t,sizeof(mp_obj_list_t));//m_new + mp_obj_list_init(ret_list, 0); + mp_obj_t tuple_1[2]; + mp_obj_t tuple_2[2]; + for (int i = 0; i < points / 2; i++) + { + output_data = (fft_data_t*)&buffer_output[i]; + tuple_1[0] = mp_obj_new_int(output_data->R1); + tuple_1[1] = mp_obj_new_int(output_data->I1); + mp_obj_list_append(ret_list, mp_obj_new_tuple(MP_ARRAY_SIZE(tuple_1), tuple_1)); + + tuple_2[0] = mp_obj_new_int(output_data->R2); + tuple_2[1] = mp_obj_new_int(output_data->I2); + mp_obj_list_append(ret_list, mp_obj_new_tuple(MP_ARRAY_SIZE(tuple_2), tuple_2)); + } + return MP_OBJ_FROM_PTR(ret_list); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(Maix_fft_run_obj,1, Maix_fft_run); + +STATIC mp_obj_t Maix_fft_freq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) + { + //----------parse parameter--------------- + enum{ARG_points, + ARG_sample_rate, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_points, MP_ARG_INT, {.u_int = 64} }, + { MP_QSTR_sample_rate, MP_ARG_INT, {.u_int = 16000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint32_t sample_rate = args[ARG_sample_rate].u_int; + uint32_t points = args[ARG_points].u_int; + + uint32_t step = sample_rate/points; + mp_obj_list_t* ret_list = (mp_obj_list_t*)m_new(mp_obj_list_t,sizeof(mp_obj_list_t));//m_new + mp_obj_list_init(ret_list, 0); + for(int i = 0; i < points; i++) + { + mp_obj_list_append(ret_list, mp_obj_new_int(step * i)); + } + return MP_OBJ_FROM_PTR(ret_list); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(Maix_fft_freq_obj,1, Maix_fft_freq); + + +STATIC mp_obj_t Maix_fft_amplitude(const mp_obj_t list_obj) + { + + if(&mp_type_list != mp_obj_get_type(list_obj)) + { + mp_raise_ValueError("[MAIXPY]FFT:obj is not a list"); + } + mp_obj_list_t* ret_list = (mp_obj_list_t*)m_new(mp_obj_list_t,sizeof(mp_obj_list_t));//m_new + mp_obj_list_init(ret_list, 0); + //---------------------------------- + mp_obj_list_t* list = MP_OBJ_TO_PTR(list_obj); + uint32_t index = 0; + mp_obj_t list_iter; + mp_obj_tuple_t* tuple; + for(index = 0; index < list->len; index++) + { + list_iter = list->items[index]; + tuple = MP_OBJ_FROM_PTR(list_iter); + uint32_t r_val = MP_OBJ_SMALL_INT_VALUE(tuple->items[0]); + uint32_t i_val = MP_OBJ_SMALL_INT_VALUE(tuple->items[1]); + uint32_t amplitude = sqrt(r_val * r_val + i_val * i_val); + //Convert to power + uint32_t hard_power = 2*amplitude/list->len; + mp_obj_list_append(ret_list,mp_obj_new_int(hard_power)); + } + return MP_OBJ_FROM_PTR(ret_list); +} +MP_DEFINE_CONST_FUN_OBJ_1(Maix_fft_amplitude_obj, Maix_fft_amplitude); + +STATIC const mp_rom_map_elem_t Maix_fft_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&Maix_fft_run_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&Maix_fft_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_amplitude), MP_ROM_PTR(&Maix_fft_amplitude_obj) }, + +}; + +STATIC MP_DEFINE_CONST_DICT(Maix_fft_dict, Maix_fft_locals_dict_table); + +const mp_obj_type_t Maix_fft_type = { + { &mp_type_type }, + .name = MP_QSTR_FFT, + .locals_dict = (mp_obj_dict_t*)&Maix_fft_dict, +}; diff --git a/src/声源定位代码/mic-code/Maix/Maix_fpioa.c b/src/声源定位代码/mic-code/Maix/Maix_fpioa.c new file mode 100644 index 0000000..4951f48 --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/Maix_fpioa.c @@ -0,0 +1,395 @@ + +#include +#include +#include + +#include "py/mphal.h" +#include "py/runtime.h" +#include "py/obj.h" +#include "py/objtype.h" +#include "py/objstr.h" +#include "py/objint.h" +#include "py/mperrno.h" +#include "fpioa.h" +#include "fpioa_des.h" + +/*Please don't modify this macro*/ +#define DES_SPACE_NUM(str) (sizeof(" ")-sizeof(" "))-strlen(str) +#define FUN_SPACE_NUM(str) (sizeof(" ")-sizeof(" "))-strlen(str) + +typedef struct _Maix_fpioa_obj_t { + mp_obj_base_t base; +}Maix_fpioa_obj_t; + +const mp_obj_type_t Maix_fpioa_type; + + +STATIC mp_obj_t Maix_set_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_pin, + ARG_func, + ARG_set_sl, + ARG_set_st, + ARG_set_io_driving + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_func, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_set_sl, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_set_st, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_set_io_driving, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint16_t pin_num = args[ARG_pin].u_int; + fpioa_function_t func_num = args[ARG_func].u_int; + int16_t set_sl = args[ARG_set_sl].u_int; + int16_t set_st = args[ARG_set_st].u_int; + int16_t set_io_driving = args[ARG_set_io_driving].u_int; + + if(pin_num > FPIOA_NUM_IO) + mp_raise_ValueError("Don't have this Pin"); + + if(func_num < 0 || func_num > USABLE_FUNC_NUM) + mp_raise_ValueError("This function is invalid"); + + if(0 != fpioa_set_function(pin_num,func_num)) + { + mp_printf(&mp_plat_print, "[Maix]:Opps!Can not set fpioa\n"); + mp_raise_OSError(MP_EIO); + } + + if (-1 != set_sl) { + fpioa_set_sl(pin_num, set_sl); + } + + if (-1 != set_st) { + fpioa_set_st(pin_num, set_st); + } + + if(set_io_driving > FPIOA_DRIVING_MAX) + mp_raise_ValueError("set_io_driving > FPIOA_DRIVING_MAX"); + + if (-1 != set_io_driving) { + fpioa_set_io_driving(pin_num, set_io_driving); + } + + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_set_function_obj, 0,Maix_set_function); + +STATIC mp_obj_t Maix_get_Pin_num(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_func, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_func, MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + fpioa_function_t fun_num = args[ARG_func].u_int; + + if(fun_num < 0 || fun_num > USABLE_FUNC_NUM) + mp_raise_ValueError("This function is invalid"); + + int Pin_num = fpioa_get_io_by_function(fun_num); + + if(-1 == Pin_num) + { + return mp_const_none; + } + return MP_OBJ_NEW_SMALL_INT(Pin_num); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_get_Pin_num_obj, 0,Maix_get_Pin_num); + + +STATIC mp_obj_t Maix_fpioa_help(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_func, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_func, MP_ARG_INT, {.u_int = USABLE_FUNC_NUM} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + char* des_space_str = NULL; + char* fun_space_str = NULL; + if(args[ARG_func].u_int > USABLE_FUNC_NUM) + { + mp_printf(&mp_plat_print, "No this funciton Description\n"); + return mp_const_false; + } + mp_printf(&mp_plat_print, "+-------------------+----------------------------------+\n") ; + mp_printf(&mp_plat_print, "| Function | Description |\n") ; + mp_printf(&mp_plat_print, "+-------------------+----------------------------------+\n") ; + if(args[ARG_func].u_int == USABLE_FUNC_NUM) + { + + for(int i = 0;i < USABLE_FUNC_NUM ; i++) + { + /*malloc memory*/ + des_space_str = (char*)malloc(DES_SPACE_NUM(func_description[i])+1); + fun_space_str = (char*)malloc(FUN_SPACE_NUM( func_name[i])+1); + + memset(des_space_str,' ',DES_SPACE_NUM(func_description[i])); + des_space_str[DES_SPACE_NUM(func_description[i])] = '\0'; + + memset(fun_space_str,' ',FUN_SPACE_NUM( func_name[i])); + fun_space_str[FUN_SPACE_NUM( func_name[i])] = '\0'; + + + mp_printf(&mp_plat_print, "| %s%s| %s%s|\n", func_name[i],fun_space_str,func_description[i],des_space_str) ; + free(des_space_str); + free(fun_space_str); + mp_printf(&mp_plat_print, "+-------------------+----------------------------------+\n") ; + } + } + else + { + des_space_str = (char*)malloc(DES_SPACE_NUM(func_description[args[ARG_func].u_int])+1); + fun_space_str = (char*)malloc(FUN_SPACE_NUM(func_name[args[ARG_func].u_int])+1); + + memset(des_space_str,' ',DES_SPACE_NUM(func_description[args[ARG_func].u_int])); + des_space_str[DES_SPACE_NUM(func_description[args[ARG_func].u_int])] = '\0'; + + memset(fun_space_str,' ',FUN_SPACE_NUM(func_name[args[ARG_func].u_int])); + fun_space_str[FUN_SPACE_NUM(func_name[args[ARG_func].u_int])] = '\0'; + + mp_printf(&mp_plat_print, "| %s%s| %s%s|\n", func_name[args[ARG_func].u_int],fun_space_str,func_description[args[ARG_func].u_int],des_space_str) ; + free(des_space_str); + free(fun_space_str); + mp_printf(&mp_plat_print, "+-------------------+----------------------------------+\n") ; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_fpioa_help_obj, 0,Maix_fpioa_help); + +STATIC mp_obj_t Maix_fpioa_make_new() { + + Maix_fpioa_obj_t *self = m_new_obj(Maix_fpioa_obj_t); + self->base.type = &Maix_fpioa_type; + + return self; +} + +STATIC const mp_rom_map_elem_t Maix_fpioa_locals_dict_table[] = { + // fpioa methods + { MP_ROM_QSTR(MP_QSTR_set_function), MP_ROM_PTR(&Maix_set_function_obj) }, + { MP_ROM_QSTR(MP_QSTR_help), MP_ROM_PTR(&Maix_fpioa_help_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_Pin_num), MP_ROM_PTR(&Maix_get_Pin_num_obj) }, + {MP_ROM_QSTR(MP_QSTR_JTAG_TCLK ), MP_ROM_INT(0 )}, + {MP_ROM_QSTR(MP_QSTR_JTAG_TDI ), MP_ROM_INT(1 )}, + {MP_ROM_QSTR(MP_QSTR_JTAG_TMS ), MP_ROM_INT(2 )}, + {MP_ROM_QSTR(MP_QSTR_JTAG_TDO ), MP_ROM_INT(3 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_D0 ), MP_ROM_INT(4 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_D1 ), MP_ROM_INT(5 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_D2 ), MP_ROM_INT(6 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_D3 ), MP_ROM_INT(7 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_D4 ), MP_ROM_INT(8 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_D5 ), MP_ROM_INT(9 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_D6 ), MP_ROM_INT(10 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_D7 ), MP_ROM_INT(11 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_SS0 ), MP_ROM_INT(12 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_SS1 ), MP_ROM_INT(13 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_SS2 ), MP_ROM_INT(14 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_SS3 ), MP_ROM_INT(15 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_ARB ), MP_ROM_INT(16 )}, + {MP_ROM_QSTR(MP_QSTR_SPI0_SCLK ), MP_ROM_INT(17 )}, + {MP_ROM_QSTR(MP_QSTR_UARTHS_RX ), MP_ROM_INT(18 )}, + {MP_ROM_QSTR(MP_QSTR_UARTHS_TX ), MP_ROM_INT(19 )}, + {MP_ROM_QSTR(MP_QSTR_RESV6 ), MP_ROM_INT(20 )}, + {MP_ROM_QSTR(MP_QSTR_RESV7 ), MP_ROM_INT(21 )}, + {MP_ROM_QSTR(MP_QSTR_CLK_SPI1 ), MP_ROM_INT(22 )}, + {MP_ROM_QSTR(MP_QSTR_CLK_I2C1 ), MP_ROM_INT(23 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS0 ), MP_ROM_INT(24 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS1 ), MP_ROM_INT(25 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS2 ), MP_ROM_INT(26 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS3 ), MP_ROM_INT(27 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS4 ), MP_ROM_INT(28 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS5 ), MP_ROM_INT(29 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS6 ), MP_ROM_INT(30 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS7 ), MP_ROM_INT(31 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS8 ), MP_ROM_INT(32 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS9 ), MP_ROM_INT(33 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS10 ), MP_ROM_INT(34 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS11 ), MP_ROM_INT(35 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS12 ), MP_ROM_INT(36 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS13 ), MP_ROM_INT(37 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS14 ), MP_ROM_INT(38 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS15 ), MP_ROM_INT(39 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS16 ), MP_ROM_INT(40 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS17 ), MP_ROM_INT(41 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS18 ), MP_ROM_INT(42 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS19 ), MP_ROM_INT(43 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS20 ), MP_ROM_INT(44 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS21 ), MP_ROM_INT(45 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS22 ), MP_ROM_INT(46 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS23 ), MP_ROM_INT(47 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS24 ), MP_ROM_INT(48 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS25 ), MP_ROM_INT(49 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS26 ), MP_ROM_INT(50 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS27 ), MP_ROM_INT(51 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS28 ), MP_ROM_INT(52 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS29 ), MP_ROM_INT(53 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS30 ), MP_ROM_INT(54 )}, + {MP_ROM_QSTR(MP_QSTR_GPIOHS31 ), MP_ROM_INT(55 )}, + {MP_ROM_QSTR(MP_QSTR_GPIO0 ), MP_ROM_INT(56 )}, + {MP_ROM_QSTR(MP_QSTR_GPIO1 ), MP_ROM_INT(57 )}, + {MP_ROM_QSTR(MP_QSTR_GPIO2 ), MP_ROM_INT(58 )}, + {MP_ROM_QSTR(MP_QSTR_GPIO3 ), MP_ROM_INT(59 )}, + {MP_ROM_QSTR(MP_QSTR_GPIO4 ), MP_ROM_INT(60 )}, + {MP_ROM_QSTR(MP_QSTR_GPIO5 ), MP_ROM_INT(61 )}, + {MP_ROM_QSTR(MP_QSTR_GPIO6 ), MP_ROM_INT(62 )}, + {MP_ROM_QSTR(MP_QSTR_GPIO7 ), MP_ROM_INT(63 )}, + {MP_ROM_QSTR(MP_QSTR_UART1_RX ), MP_ROM_INT(64 )}, + {MP_ROM_QSTR(MP_QSTR_UART1_TX ), MP_ROM_INT(65 )}, + {MP_ROM_QSTR(MP_QSTR_UART2_RX ), MP_ROM_INT(66 )}, + {MP_ROM_QSTR(MP_QSTR_UART2_TX ), MP_ROM_INT(67 )}, + {MP_ROM_QSTR(MP_QSTR_UART3_RX ), MP_ROM_INT(68 )}, + {MP_ROM_QSTR(MP_QSTR_UART3_TX ), MP_ROM_INT(69 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_D0 ), MP_ROM_INT(70 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_D1 ), MP_ROM_INT(71 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_D2 ), MP_ROM_INT(72 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_D3 ), MP_ROM_INT(73 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_D4 ), MP_ROM_INT(74 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_D5 ), MP_ROM_INT(75 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_D6 ), MP_ROM_INT(76 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_D7 ), MP_ROM_INT(77 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_SS0 ), MP_ROM_INT(78 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_SS1 ), MP_ROM_INT(79 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_SS2 ), MP_ROM_INT(80 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_SS3 ), MP_ROM_INT(81 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_ARB ), MP_ROM_INT(82 )}, + {MP_ROM_QSTR(MP_QSTR_SPI1_SCLK ), MP_ROM_INT(83 )}, + {MP_ROM_QSTR(MP_QSTR_SPI_SLAVE_D0 ), MP_ROM_INT(84 )}, + {MP_ROM_QSTR(MP_QSTR_SPI_SLAVE_SS ), MP_ROM_INT(85 )}, + {MP_ROM_QSTR(MP_QSTR_SPI_SLAVE_SCLK), MP_ROM_INT(86 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_MCLK ), MP_ROM_INT(87 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_SCLK ), MP_ROM_INT(88 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_WS ), MP_ROM_INT(89 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_IN_D0 ), MP_ROM_INT(90 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_IN_D1 ), MP_ROM_INT(91 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_IN_D2 ), MP_ROM_INT(92 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_IN_D3 ), MP_ROM_INT(93 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_OUT_D0 ), MP_ROM_INT(94 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_OUT_D1 ), MP_ROM_INT(95 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_OUT_D2 ), MP_ROM_INT(96 )}, + {MP_ROM_QSTR(MP_QSTR_I2S0_OUT_D3 ), MP_ROM_INT(97 )}, + {MP_ROM_QSTR(MP_QSTR_I2S1_MCLK ), MP_ROM_INT(98 )}, + {MP_ROM_QSTR(MP_QSTR_I2S1_SCLK ), MP_ROM_INT(99 )}, + {MP_ROM_QSTR(MP_QSTR_I2S1_WS ), MP_ROM_INT(100)}, + {MP_ROM_QSTR(MP_QSTR_I2S1_IN_D0 ), MP_ROM_INT(101)}, + {MP_ROM_QSTR(MP_QSTR_I2S1_IN_D1 ), MP_ROM_INT(102)}, + {MP_ROM_QSTR(MP_QSTR_I2S1_IN_D2 ), MP_ROM_INT(103)}, + {MP_ROM_QSTR(MP_QSTR_I2S1_IN_D3 ), MP_ROM_INT(104)}, + {MP_ROM_QSTR(MP_QSTR_I2S1_OUT_D0 ), MP_ROM_INT(105)}, + {MP_ROM_QSTR(MP_QSTR_I2S1_OUT_D1 ), MP_ROM_INT(106)}, + {MP_ROM_QSTR(MP_QSTR_I2S1_OUT_D2 ), MP_ROM_INT(107)}, + {MP_ROM_QSTR(MP_QSTR_I2S1_OUT_D3 ), MP_ROM_INT(108)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_MCLK ), MP_ROM_INT(109)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_SCLK ), MP_ROM_INT(110)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_WS ), MP_ROM_INT(111)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_IN_D0 ), MP_ROM_INT(112)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_IN_D1 ), MP_ROM_INT(113)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_IN_D2 ), MP_ROM_INT(114)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_IN_D3 ), MP_ROM_INT(115)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_OUT_D0 ), MP_ROM_INT(116)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_OUT_D1 ), MP_ROM_INT(117)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_OUT_D2 ), MP_ROM_INT(118)}, + {MP_ROM_QSTR(MP_QSTR_I2S2_OUT_D3 ), MP_ROM_INT(119)}, + {MP_ROM_QSTR(MP_QSTR_RESV0 ), MP_ROM_INT(120)}, + {MP_ROM_QSTR(MP_QSTR_RESV1 ), MP_ROM_INT(121)}, + {MP_ROM_QSTR(MP_QSTR_RESV2 ), MP_ROM_INT(122)}, + {MP_ROM_QSTR(MP_QSTR_RESV3 ), MP_ROM_INT(123)}, + {MP_ROM_QSTR(MP_QSTR_RESV4 ), MP_ROM_INT(124)}, + {MP_ROM_QSTR(MP_QSTR_RESV5 ), MP_ROM_INT(125)}, + {MP_ROM_QSTR(MP_QSTR_I2C0_SCLK ), MP_ROM_INT(126)}, + {MP_ROM_QSTR(MP_QSTR_I2C0_SDA ), MP_ROM_INT(127)}, + {MP_ROM_QSTR(MP_QSTR_I2C1_SCLK ), MP_ROM_INT(128)}, + {MP_ROM_QSTR(MP_QSTR_I2C1_SDA ), MP_ROM_INT(129)}, + {MP_ROM_QSTR(MP_QSTR_I2C2_SCLK ), MP_ROM_INT(130)}, + {MP_ROM_QSTR(MP_QSTR_I2C2_SDA ), MP_ROM_INT(131)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_XCLK ), MP_ROM_INT(132)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_RST ), MP_ROM_INT(133)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_PWDN ), MP_ROM_INT(134)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_VSYNC ), MP_ROM_INT(135)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_HREF ), MP_ROM_INT(136)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_PCLK ), MP_ROM_INT(137)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_D0 ), MP_ROM_INT(138)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_D1 ), MP_ROM_INT(139)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_D2 ), MP_ROM_INT(140)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_D3 ), MP_ROM_INT(141)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_D4 ), MP_ROM_INT(142)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_D5 ), MP_ROM_INT(143)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_D6 ), MP_ROM_INT(144)}, + {MP_ROM_QSTR(MP_QSTR_CMOS_D7 ), MP_ROM_INT(145)}, + {MP_ROM_QSTR(MP_QSTR_SCCB_SCLK ), MP_ROM_INT(146)}, + {MP_ROM_QSTR(MP_QSTR_SCCB_SDA ), MP_ROM_INT(147)}, + {MP_ROM_QSTR(MP_QSTR_UART1_CTS ), MP_ROM_INT(148)}, + {MP_ROM_QSTR(MP_QSTR_UART1_DSR ), MP_ROM_INT(149)}, + {MP_ROM_QSTR(MP_QSTR_UART1_DCD ), MP_ROM_INT(150)}, + {MP_ROM_QSTR(MP_QSTR_UART1_RI ), MP_ROM_INT(151)}, + {MP_ROM_QSTR(MP_QSTR_UART1_SIR_IN ), MP_ROM_INT(152)}, + {MP_ROM_QSTR(MP_QSTR_UART1_DTR ), MP_ROM_INT(153)}, + {MP_ROM_QSTR(MP_QSTR_UART1_RTS ), MP_ROM_INT(154)}, + {MP_ROM_QSTR(MP_QSTR_UART1_OUT2 ), MP_ROM_INT(155)}, + {MP_ROM_QSTR(MP_QSTR_UART1_OUT1 ), MP_ROM_INT(156)}, + {MP_ROM_QSTR(MP_QSTR_UART1_SIR_OUT ), MP_ROM_INT(157)}, + {MP_ROM_QSTR(MP_QSTR_UART1_BAUD ), MP_ROM_INT(158)}, + {MP_ROM_QSTR(MP_QSTR_UART1_RE ), MP_ROM_INT(159)}, + {MP_ROM_QSTR(MP_QSTR_UART1_DE ), MP_ROM_INT(160)}, + {MP_ROM_QSTR(MP_QSTR_UART1_RS485_EN), MP_ROM_INT(161)}, + {MP_ROM_QSTR(MP_QSTR_UART2_CTS ), MP_ROM_INT(162)}, + {MP_ROM_QSTR(MP_QSTR_UART2_DSR ), MP_ROM_INT(163)}, + {MP_ROM_QSTR(MP_QSTR_UART2_DCD ), MP_ROM_INT(164)}, + {MP_ROM_QSTR(MP_QSTR_UART2_RI ), MP_ROM_INT(165)}, + {MP_ROM_QSTR(MP_QSTR_UART2_SIR_IN ), MP_ROM_INT(166)}, + {MP_ROM_QSTR(MP_QSTR_UART2_DTR ), MP_ROM_INT(167)}, + {MP_ROM_QSTR(MP_QSTR_UART2_RTS ), MP_ROM_INT(168)}, + {MP_ROM_QSTR(MP_QSTR_UART2_OUT2 ), MP_ROM_INT(169)}, + {MP_ROM_QSTR(MP_QSTR_UART2_OUT1 ), MP_ROM_INT(170)}, + {MP_ROM_QSTR(MP_QSTR_UART2_SIR_OUT ), MP_ROM_INT(171)}, + {MP_ROM_QSTR(MP_QSTR_UART2_BAUD ), MP_ROM_INT(172)}, + {MP_ROM_QSTR(MP_QSTR_UART2_RE ), MP_ROM_INT(173)}, + {MP_ROM_QSTR(MP_QSTR_UART2_DE ), MP_ROM_INT(174)}, + {MP_ROM_QSTR(MP_QSTR_UART2_RS485_EN), MP_ROM_INT(175)}, + {MP_ROM_QSTR(MP_QSTR_UART3_CTS ), MP_ROM_INT(176)}, + {MP_ROM_QSTR(MP_QSTR_UART3_DSR ), MP_ROM_INT(177)}, + {MP_ROM_QSTR(MP_QSTR_UART3_DCD ), MP_ROM_INT(178)}, + {MP_ROM_QSTR(MP_QSTR_UART3_RI ), MP_ROM_INT(179)}, + {MP_ROM_QSTR(MP_QSTR_UART3_SIR_IN ), MP_ROM_INT(180)}, + {MP_ROM_QSTR(MP_QSTR_UART3_DTR ), MP_ROM_INT(181)}, + {MP_ROM_QSTR(MP_QSTR_UART3_RTS ), MP_ROM_INT(182)}, + {MP_ROM_QSTR(MP_QSTR_UART3_OUT2 ), MP_ROM_INT(183)}, + {MP_ROM_QSTR(MP_QSTR_UART3_OUT1 ), MP_ROM_INT(184)}, + {MP_ROM_QSTR(MP_QSTR_UART3_SIR_OUT ), MP_ROM_INT(185)}, + {MP_ROM_QSTR(MP_QSTR_UART3_BAUD ), MP_ROM_INT(186)}, + {MP_ROM_QSTR(MP_QSTR_UART3_RE ), MP_ROM_INT(187)}, + {MP_ROM_QSTR(MP_QSTR_UART3_DE ), MP_ROM_INT(188)}, + {MP_ROM_QSTR(MP_QSTR_UART3_RS485_EN), MP_ROM_INT(189)}, + {MP_ROM_QSTR(MP_QSTR_TIMER0_TOGGLE1), MP_ROM_INT(190)}, + {MP_ROM_QSTR(MP_QSTR_TIMER0_TOGGLE2), MP_ROM_INT(191)}, + {MP_ROM_QSTR(MP_QSTR_TIMER0_TOGGLE3), MP_ROM_INT(192)}, + {MP_ROM_QSTR(MP_QSTR_TIMER0_TOGGLE4), MP_ROM_INT(193)}, + {MP_ROM_QSTR(MP_QSTR_TIMER1_TOGGLE1), MP_ROM_INT(194)}, + {MP_ROM_QSTR(MP_QSTR_TIMER1_TOGGLE2), MP_ROM_INT(195)}, + {MP_ROM_QSTR(MP_QSTR_TIMER1_TOGGLE3), MP_ROM_INT(196)}, + {MP_ROM_QSTR(MP_QSTR_TIMER1_TOGGLE4), MP_ROM_INT(197)}, + {MP_ROM_QSTR(MP_QSTR_TIMER2_TOGGLE1), MP_ROM_INT(198)}, + {MP_ROM_QSTR(MP_QSTR_TIMER2_TOGGLE2), MP_ROM_INT(199)}, + {MP_ROM_QSTR(MP_QSTR_TIMER2_TOGGLE3), MP_ROM_INT(200)}, + {MP_ROM_QSTR(MP_QSTR_TIMER2_TOGGLE4), MP_ROM_INT(201)}, + {MP_ROM_QSTR(MP_QSTR_CLK_SPI2 ), MP_ROM_INT(202)}, + {MP_ROM_QSTR(MP_QSTR_CLK_I2C2 ), MP_ROM_INT(203)}, +}; +STATIC MP_DEFINE_CONST_DICT(Maix_fpioa_locals_dict, Maix_fpioa_locals_dict_table); +const mp_obj_type_t Maix_fpioa_type = { + { &mp_type_type }, + .name = MP_QSTR_FPIOA, + .make_new = Maix_fpioa_make_new, + .locals_dict = (mp_obj_dict_t*)&Maix_fpioa_locals_dict, +}; + + + diff --git a/src/声源定位代码/mic-code/Maix/Maix_gpio.c b/src/声源定位代码/mic-code/Maix/Maix_gpio.c new file mode 100644 index 0000000..49cb864 --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/Maix_gpio.c @@ -0,0 +1,587 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "gpio.h" +#include "gpiohs.h" +#include "plic.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "mphalport.h" +#include "modmachine.h" +#include "extmod/virtpin.h" + +const mp_obj_type_t Maix_gpio_type; + +typedef int gpio_num_t; +enum { + GPIO_DM_PULL_NONE = -1, +}; + +typedef enum _gpio_type_t{ + GPIOHS = 0, + GPIO = 1, +}gpio_type_t; + +typedef struct _Maix_gpio_obj_t { + mp_obj_base_t base; + gpio_num_t num; + gpio_type_t gpio_type; + gpio_num_t id; + mp_obj_t callback; + gpio_drive_mode_t mode; + +} Maix_gpio_obj_t; + +typedef struct _Maix_gpio_irq_obj_t { + mp_obj_base_t base; + gpio_num_t num; + gpio_num_t id; +} Maix_gpio_irq_obj_t; + +typedef enum __gpio_t{ + GPIO_NUM_0 = 0, + GPIO_NUM_1, + GPIO_NUM_2, + GPIO_NUM_3, + GPIO_NUM_4, + GPIO_NUM_5, + GPIO_NUM_6, + GPIO_NUM_7, +}_gpio_t; + +typedef enum __gpiohs_t{ + GPIOHS_NUM_0 = 0, + GPIOHS_NUM_1, + GPIOHS_NUM_2, + GPIOHS_NUM_3, + GPIOHS_NUM_4, + GPIOHS_NUM_5, + GPIOHS_NUM_6, + GPIOHS_NUM_7, + GPIOHS_NUM_8, + GPIOHS_NUM_9, + GPIOHS_NUM_10, + GPIOHS_NUM_11, + GPIOHS_NUM_12, + GPIOHS_NUM_13, + GPIOHS_NUM_14, + GPIOHS_NUM_15, + GPIOHS_NUM_16, + GPIOHS_NUM_17, + GPIOHS_NUM_18, + GPIOHS_NUM_19, + GPIOHS_NUM_20, + GPIOHS_NUM_21, + GPIOHS_NUM_22, + GPIOHS_NUM_23, + GPIOHS_NUM_24, + GPIOHS_NUM_25, + GPIOHS_NUM_26, + GPIOHS_NUM_27, + GPIOHS_NUM_28, + GPIOHS_NUM_29, + GPIOHS_NUM_30, + GPIOHS_NUM_31, +} _gpiohs_t; + +STATIC const Maix_gpio_obj_t Maix_gpio_obj[] = { + {{&Maix_gpio_type}, 0, GPIOHS, GPIOHS_NUM_0, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 1, GPIOHS, GPIOHS_NUM_1, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 2, GPIOHS, GPIOHS_NUM_2, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 3, GPIOHS, GPIOHS_NUM_3, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 4, GPIOHS, GPIOHS_NUM_4, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 5, GPIOHS, GPIOHS_NUM_5, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 6, GPIOHS, GPIOHS_NUM_6, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 7, GPIOHS, GPIOHS_NUM_7, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 8, GPIOHS, GPIOHS_NUM_8, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 9, GPIOHS, GPIOHS_NUM_9, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 10, GPIOHS, GPIOHS_NUM_10, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 11, GPIOHS, GPIOHS_NUM_11, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 12, GPIOHS, GPIOHS_NUM_12, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 13, GPIOHS, GPIOHS_NUM_13, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 14, GPIOHS, GPIOHS_NUM_14, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 15, GPIOHS, GPIOHS_NUM_15, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 16, GPIOHS, GPIOHS_NUM_16, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 17, GPIOHS, GPIOHS_NUM_17, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 18, GPIOHS, GPIOHS_NUM_18, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 19, GPIOHS, GPIOHS_NUM_19, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 20, GPIOHS, GPIOHS_NUM_20, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 21, GPIOHS, GPIOHS_NUM_21, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 22, GPIOHS, GPIOHS_NUM_22, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 23, GPIOHS, GPIOHS_NUM_23, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 24, GPIOHS, GPIOHS_NUM_24, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 25, GPIOHS, GPIOHS_NUM_25, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 26, GPIOHS, GPIOHS_NUM_26, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 27, GPIOHS, GPIOHS_NUM_27, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 28, GPIOHS, GPIOHS_NUM_28, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 29, GPIOHS, GPIOHS_NUM_29, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 30, GPIOHS, GPIOHS_NUM_30, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 31, GPIOHS, GPIOHS_NUM_31, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 32, GPIO, GPIO_NUM_0, MP_OBJ_NULL, GPIO_DM_INPUT},//32 + {{&Maix_gpio_type}, 33, GPIO, GPIO_NUM_1, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 34, GPIO, GPIO_NUM_2, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 35, GPIO, GPIO_NUM_3, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 36, GPIO, GPIO_NUM_4, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 37, GPIO, GPIO_NUM_5, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 38, GPIO, GPIO_NUM_6, MP_OBJ_NULL, GPIO_DM_INPUT}, + {{&Maix_gpio_type}, 39, GPIO, GPIO_NUM_7, MP_OBJ_NULL, GPIO_DM_INPUT}, + +}; + +// forward declaration +STATIC const Maix_gpio_irq_obj_t Maix_gpio_irq_object[]; + +void Maix_gpios_init(void) { + // memset(&MP_STATE_PORT(Maix_gpio_irq_handler[0]), 0, sizeof(MP_STATE_PORT(Maix_gpio_irq_handler))); +} + +void Maix_gpios_deinit(void) { + + for (int i = 0; i < MP_ARRAY_SIZE(Maix_gpio_obj); ++i) { + if (Maix_gpio_obj[i].gpio_type != GPIO) { + plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + Maix_gpio_obj[i].id); + } + } +} + +STATIC int Maix_gpio_isr_handler(void *arg) { + Maix_gpio_obj_t *self = arg; + //only gpiohs support irq,so only support gpiohs in this func + mp_obj_t handler = self->callback; +// mp_call_function_2(handler, MP_OBJ_FROM_PTR(self), mp_obj_new_int_from_uint(self->id)); + mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self)); + mp_hal_wake_main_task_from_isr(); + return 0; +} + +gpio_num_t Maix_gpio_get_id(mp_obj_t pin_in) { + if (mp_obj_get_type(pin_in) != &Maix_gpio_type) { + mp_raise_ValueError("expecting a pin"); + } + Maix_gpio_obj_t *self = pin_in; + return self->id; +} + +STATIC void Maix_gpio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + Maix_gpio_obj_t *self = self_in; + + mp_printf(print, "Pin(%u)", self->id); +} + +// pin.init(mode, pull=None, *, value) +STATIC mp_obj_t Maix_gpio_obj_init_helper(Maix_gpio_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_pull, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // configure mode + if (args[ARG_mode].u_obj != mp_const_none) { + mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj); + if (0 <= self->num && self->num < MP_ARRAY_SIZE(Maix_gpio_obj)) { + self = (Maix_gpio_obj_t*)&Maix_gpio_obj[self->num]; + if(pin_io_mode == GPIO_DM_OUTPUT && args[ARG_pull].u_obj != mp_const_none && mp_obj_get_int(args[ARG_pull].u_obj) != GPIO_DM_PULL_NONE){ + mp_raise_ValueError("When this pin is in output mode, it is not allowed to pull up and down."); + }else{ + if(args[ARG_pull].u_obj != mp_const_none && mp_obj_get_int(args[ARG_pull].u_obj) != GPIO_DM_PULL_NONE ){ + if(mp_obj_get_int(args[ARG_pull].u_obj) == GPIO_DM_INPUT_PULL_UP || mp_obj_get_int(args[ARG_pull].u_obj) == GPIO_DM_INPUT_PULL_DOWN){ + pin_io_mode = mp_obj_get_int(args[ARG_pull].u_obj); + }else{ + mp_raise_ValueError("this mode not support."); + } + } + if(self->gpio_type == GPIO){ + gpio_set_drive_mode(self->id, pin_io_mode); + }else{ + gpiohs_set_drive_mode(self->id, pin_io_mode); + } + self->mode = pin_io_mode; + } + + //set initial value (dont this before configuring mode/pull) + if (args[ARG_value].u_obj != MP_OBJ_NULL) { + if(self->gpio_type == GPIOHS){ + gpiohs_set_pin((uint8_t)self->id,mp_obj_is_true(args[ARG_value].u_obj)); + }else{ + gpio_set_pin((uint8_t)self->id,mp_obj_is_true(args[ARG_value].u_obj)); + } + } + }else{ + mp_raise_ValueError("pin not found"); + } + } + + return mp_const_none; +} + +// constructor(id, ...) +mp_obj_t mp_maixpy_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted pin object + int wanted_pin = mp_obj_get_int(args[0]); + Maix_gpio_obj_t *self = NULL; + if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(Maix_gpio_obj)) { + self = (Maix_gpio_obj_t*)&Maix_gpio_obj[wanted_pin]; + } + if (self == NULL || self->base.type == NULL) { + mp_raise_ValueError("invalid pin"); + } + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + Maix_gpio_obj_init_helper(self, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(self); +} + +// fast method for getting/setting pin value +STATIC mp_obj_t Maix_gpio_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + Maix_gpio_obj_t *self = self_in; + if (n_args == 0) { + // get pin + if(self->gpio_type == GPIO){ + return MP_OBJ_NEW_SMALL_INT(gpio_get_pin((uint8_t)self->id)); + }else{ + if (self->mode == GPIO_DM_OUTPUT) { + gpiohs_set_drive_mode((uint8_t)self->id, GPIO_DM_INPUT); + } + int value = gpiohs_get_pin((uint8_t)self->id); + if (self->mode == GPIO_DM_OUTPUT) { + gpiohs_set_drive_mode((uint8_t)self->id, GPIO_DM_OUTPUT); + } + return MP_OBJ_NEW_SMALL_INT(value); + } + + } else { + // set pin + if(self->gpio_type == GPIO){ + gpio_set_pin(self->id, mp_obj_is_true(args[0])); + }else{ + gpiohs_set_pin(self->id, mp_obj_is_true(args[0])); + } + return mp_const_none; + } +} + +// pin.init(mode, pull) +STATIC mp_obj_t Maix_gpio_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return Maix_gpio_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(Maix_gpio_init_obj, 1, Maix_gpio_obj_init); + +// pin.value([value]) +STATIC mp_obj_t Maix_gpio_value(size_t n_args, const mp_obj_t *args) { + return Maix_gpio_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Maix_gpio_value_obj, 1, 2, Maix_gpio_value); + +// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING) +STATIC mp_obj_t Maix_gpio_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_handler, ARG_trigger, ARG_wake ,ARG_priority}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PE_BOTH} }, + { MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_priority, MP_ARG_INT, {.u_int = 7} }, + }; + Maix_gpio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (self->gpio_type != GPIO && (n_args > 1 || kw_args->used != 0)) { + // configure irq + mp_obj_t handler = args[ARG_handler].u_obj; + uint32_t trigger = args[ARG_trigger].u_int; + mp_obj_t wake_obj = args[ARG_wake].u_obj; + mp_int_t temp_wake_int; + mp_obj_get_int_maybe(args[ARG_wake].u_obj,&temp_wake_int); + + if(wake_obj != mp_const_none && temp_wake_int != 0){ + mp_raise_ValueError("This platform does not support interrupt wakeup"); + }else{ + if (trigger == GPIO_PE_NONE || trigger == GPIO_PE_RISING || trigger == GPIO_PE_FALLING || trigger == GPIO_PE_BOTH) { + + if (handler == mp_const_none) { + handler = MP_OBJ_NULL; + trigger = 0; + } + self->callback = handler; + gpiohs_set_pin_edge((uint8_t)self->id,trigger); + gpiohs_irq_register((uint8_t)self->id, args[ARG_priority].u_int, Maix_gpio_isr_handler, (void *)self); + }else{ + + } + } + + } + + + //return the irq object + return MP_OBJ_FROM_PTR(&Maix_gpio_irq_object[self->num]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_gpio_irq_obj, 1, Maix_gpio_irq); + +STATIC mp_obj_t Maix_gpio_disirq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + Maix_gpio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + if (self->gpio_type != GPIO) { + plic_irq_disable(IRQN_GPIOHS0_INTERRUPT + (uint8_t)self->id); + } + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_gpio_disirq_obj,1,Maix_gpio_disirq); + + +STATIC mp_obj_t Maix_gpio_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(!mp_obj_is_type(pos_args[0], &Maix_gpio_type)) + mp_raise_ValueError("only for object"); + Maix_gpio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + enum { ARG_mode}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(args[ARG_mode].u_int == -1) + { + return mp_obj_new_int(self->mode); + } + else if(args[ARG_mode].u_int != GPIO_DM_INPUT && + args[ARG_mode].u_int != GPIO_DM_OUTPUT && + args[ARG_mode].u_int != GPIO_DM_PULL_NONE && + args[ARG_mode].u_int != GPIO_DM_INPUT_PULL_UP && + args[ARG_mode].u_int != GPIO_DM_INPUT_PULL_DOWN + ) + { + mp_raise_ValueError("arg error"); + } + if (self->gpio_type == GPIO) { + gpio_set_drive_mode(self->id, (gpio_drive_mode_t)args[ARG_mode].u_int); + }else{ + gpiohs_set_drive_mode(self->id, (gpio_drive_mode_t)args[ARG_mode].u_int); + } + self->mode = (gpio_drive_mode_t)args[ARG_mode].u_int; + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_gpio_mode_obj,1,Maix_gpio_mode); + + +STATIC const mp_rom_map_elem_t Maix_gpio_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&Maix_gpio_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&Maix_gpio_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&Maix_gpio_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_disirq), MP_ROM_PTR(&Maix_gpio_disirq_obj) }, + { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&Maix_gpio_mode_obj) }, + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_DM_INPUT) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_DM_OUTPUT) }, + { MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_DM_PULL_NONE) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_DM_INPUT_PULL_UP) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_DM_INPUT_PULL_DOWN) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_NONE), MP_ROM_INT(GPIO_PE_NONE) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PE_RISING) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PE_FALLING) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_BOTH), MP_ROM_INT(GPIO_PE_BOTH) }, + + // gpio constant + { MP_ROM_QSTR(MP_QSTR_GPIOHS0), MP_ROM_INT(GPIOHS_NUM_0) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS1), MP_ROM_INT(GPIOHS_NUM_1) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS2), MP_ROM_INT(GPIOHS_NUM_2) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS3), MP_ROM_INT(GPIOHS_NUM_3) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS4), MP_ROM_INT(GPIOHS_NUM_4) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS5), MP_ROM_INT(GPIOHS_NUM_5) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS6), MP_ROM_INT(GPIOHS_NUM_6) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS7), MP_ROM_INT(GPIOHS_NUM_7) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS8), MP_ROM_INT(GPIOHS_NUM_8) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS9), MP_ROM_INT(GPIOHS_NUM_9) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS10), MP_ROM_INT(GPIOHS_NUM_10) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS11), MP_ROM_INT(GPIOHS_NUM_11) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS12), MP_ROM_INT(GPIOHS_NUM_12) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS13), MP_ROM_INT(GPIOHS_NUM_13) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS14), MP_ROM_INT(GPIOHS_NUM_14) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS15), MP_ROM_INT(GPIOHS_NUM_15) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS16), MP_ROM_INT(GPIOHS_NUM_16) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS17), MP_ROM_INT(GPIOHS_NUM_17) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS18), MP_ROM_INT(GPIOHS_NUM_18) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS19), MP_ROM_INT(GPIOHS_NUM_19) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS20), MP_ROM_INT(GPIOHS_NUM_20) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS21), MP_ROM_INT(GPIOHS_NUM_21) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS22), MP_ROM_INT(GPIOHS_NUM_22) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS23), MP_ROM_INT(GPIOHS_NUM_23) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS24), MP_ROM_INT(GPIOHS_NUM_24) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS25), MP_ROM_INT(GPIOHS_NUM_25) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS26), MP_ROM_INT(GPIOHS_NUM_26) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS27), MP_ROM_INT(GPIOHS_NUM_27) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS28), MP_ROM_INT(GPIOHS_NUM_28) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS29), MP_ROM_INT(GPIOHS_NUM_29) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS30), MP_ROM_INT(GPIOHS_NUM_30) }, + { MP_ROM_QSTR(MP_QSTR_GPIOHS31), MP_ROM_INT(GPIOHS_NUM_31) }, + { MP_ROM_QSTR(MP_QSTR_GPIO0), MP_ROM_INT(32) }, + { MP_ROM_QSTR(MP_QSTR_GPIO1), MP_ROM_INT(33) }, + { MP_ROM_QSTR(MP_QSTR_GPIO2), MP_ROM_INT(34) }, + { MP_ROM_QSTR(MP_QSTR_GPIO3), MP_ROM_INT(35) }, + { MP_ROM_QSTR(MP_QSTR_GPIO4), MP_ROM_INT(36) }, + { MP_ROM_QSTR(MP_QSTR_GPIO5), MP_ROM_INT(37) }, + { MP_ROM_QSTR(MP_QSTR_GPIO6), MP_ROM_INT(38) }, + { MP_ROM_QSTR(MP_QSTR_GPIO7), MP_ROM_INT(39) }, + + //wakeup not support + { MP_ROM_QSTR(MP_QSTR_WAKEUP_NOT_SUPPORT), MP_ROM_INT(0) }, +}; + +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + Maix_gpio_obj_t *self = self_in; + + switch (request) { + case MP_PIN_READ: { + if(self->gpio_type == GPIO){ + return gpio_get_pin((uint8_t)self->id); + }else{ + return gpio_get_pin((uint8_t)self->id); + } + } + case MP_PIN_WRITE: { + if(self->gpio_type == GPIO){ + gpio_set_pin((uint8_t)self->id, arg); + }else{ + gpiohs_set_pin((uint8_t)self->id, arg); + } + return 0; + } + } + return -1; +} + +STATIC MP_DEFINE_CONST_DICT(Maix_gpio_locals_dict, Maix_gpio_locals_dict_table); + +STATIC const mp_pin_p_t pin_pin_p = { + .ioctl = pin_ioctl, +}; + +const mp_obj_type_t Maix_gpio_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = Maix_gpio_print, + .make_new = mp_maixpy_pin_make_new, + .call = Maix_gpio_call, + .protocol = &pin_pin_p, + .locals_dict = (mp_obj_t)&Maix_gpio_locals_dict, +}; + +/******************************************************************************/ +// Pin IRQ object + +STATIC const mp_obj_type_t Maix_gpio_irq_type; + +STATIC const Maix_gpio_irq_obj_t Maix_gpio_irq_object[] = { + {{&Maix_gpio_irq_type}, 0, GPIOHS_NUM_0}, + {{&Maix_gpio_irq_type}, 1, GPIOHS_NUM_1}, + {{&Maix_gpio_irq_type}, 2, GPIOHS_NUM_2}, + {{&Maix_gpio_irq_type}, 3, GPIOHS_NUM_3}, + {{&Maix_gpio_irq_type}, 4, GPIOHS_NUM_4}, + {{&Maix_gpio_irq_type}, 5, GPIOHS_NUM_5}, + {{&Maix_gpio_irq_type}, 6, GPIOHS_NUM_6}, + {{&Maix_gpio_irq_type}, 7, GPIOHS_NUM_7}, + {{&Maix_gpio_irq_type}, 8, GPIOHS_NUM_8}, + {{&Maix_gpio_irq_type}, 9, GPIOHS_NUM_9}, + {{&Maix_gpio_irq_type}, 10, GPIOHS_NUM_10}, + {{&Maix_gpio_irq_type}, 11, GPIOHS_NUM_11}, + {{&Maix_gpio_irq_type}, 12, GPIOHS_NUM_12}, + {{&Maix_gpio_irq_type}, 13, GPIOHS_NUM_13}, + {{&Maix_gpio_irq_type}, 14, GPIOHS_NUM_14}, + {{&Maix_gpio_irq_type}, 15, GPIOHS_NUM_15}, + {{&Maix_gpio_irq_type}, 16, GPIOHS_NUM_16}, + {{&Maix_gpio_irq_type}, 17, GPIOHS_NUM_17}, + {{&Maix_gpio_irq_type}, 18, GPIOHS_NUM_18}, + {{&Maix_gpio_irq_type}, 19, GPIOHS_NUM_19}, + {{&Maix_gpio_irq_type}, 20, GPIOHS_NUM_20}, + {{&Maix_gpio_irq_type}, 21, GPIOHS_NUM_21}, + {{&Maix_gpio_irq_type}, 22, GPIOHS_NUM_22}, + {{&Maix_gpio_irq_type}, 23, GPIOHS_NUM_23}, + {{&Maix_gpio_irq_type}, 24, GPIOHS_NUM_24}, + {{&Maix_gpio_irq_type}, 25, GPIOHS_NUM_25}, + {{&Maix_gpio_irq_type}, 26, GPIOHS_NUM_26}, + {{&Maix_gpio_irq_type}, 27, GPIOHS_NUM_27}, + {{&Maix_gpio_irq_type}, 28, GPIOHS_NUM_28}, + {{&Maix_gpio_irq_type}, 29, GPIOHS_NUM_29}, + {{&Maix_gpio_irq_type}, 30, GPIOHS_NUM_30}, + {{&Maix_gpio_irq_type}, 31, GPIOHS_NUM_31}, +}; + +STATIC mp_obj_t Maix_gpio_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + Maix_gpio_irq_obj_t *self = self_in; + mp_arg_check_num(n_args, n_kw, 0, 0, false); + Maix_gpio_isr_handler((void*)&Maix_gpio_obj[self->num]); + return mp_const_none; +} + +STATIC mp_obj_t Maix_gpio_irq_trigger(size_t n_args, const mp_obj_t *args) { + Maix_gpio_irq_obj_t *self = args[0]; + if (n_args == 2) { + // set trigger + gpiohs_set_pin_edge(self->id,mp_obj_get_int(args[1])); + }else{ + mp_raise_ValueError("Reading this property is not supported"); + } + // not support to return original trigger value + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Maix_gpio_irq_trigger_obj, 1, 2, Maix_gpio_irq_trigger); + +STATIC const mp_rom_map_elem_t Maix_gpio_irq_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&Maix_gpio_irq_trigger_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(Maix_gpio_irq_locals_dict, Maix_gpio_irq_locals_dict_table); + +STATIC const mp_obj_type_t Maix_gpio_irq_type = { + { &mp_type_type }, + .name = MP_QSTR_IRQ, + .call = Maix_gpio_irq_call, + .locals_dict = (mp_obj_dict_t*)&Maix_gpio_irq_locals_dict, +}; diff --git a/src/声源定位代码/mic-code/Maix/Maix_i2s.c b/src/声源定位代码/mic-code/Maix/Maix_i2s.c new file mode 100644 index 0000000..efdceaa --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/Maix_i2s.c @@ -0,0 +1,371 @@ +/* +* Copyright 2019 Sipeed Co.,Ltd. + +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include + +#include "i2s.h" +#include "dmac.h" +#include "sysctl.h" + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" + +#include "modMaix.h" +#include "py_audio.h" +#include "Maix_i2s.h" +#define MAX_SAMPLE_RATE (4*1024*1024) +#define MAX_SAMPLE_POINTS (64*1024) + +const mp_obj_type_t Maix_i2s_type; + + +STATIC void Maix_i2s_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + Maix_i2s_obj_t* self = MP_OBJ_TO_PTR(self_in); + // i2s_channle_t* channel_iter = &self->channel[0]; + mp_printf(print, "[MAIXPY]i2s%d:(sampling rate=%u, sampling points=%u)\n", + self->i2s_num,self->sample_rate,self->points_num); + for(int channel_iter = 0; channel_iter < 4; channel_iter++) + { + mp_printf(print, "[MAIXPY]channle%d:(resolution=%u, cycles=%u, align_mode=%u, mode=%u)\n", + channel_iter, + self->channel[channel_iter].resolution, + self->channel[channel_iter].cycles, + self->channel[channel_iter].align_mode, + self->channel[channel_iter].mode); + } +} +STATIC mp_obj_t Maix_i2s_init_helper(Maix_i2s_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum + { + ARG_sample_points, + ARG_pll2, + ARG_mclk, + }; + static const mp_arg_t allowed_args[] = + { + { MP_QSTR_sample_points, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1024} }, + { MP_QSTR_pll2, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_mclk, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + + if (args[ARG_pll2].u_int != 0) // 262144000UL + { + sysctl_pll_set_freq(SYSCTL_PLL2, args[ARG_pll2].u_int); + } + + if (args[ARG_mclk].u_int != 0) // 31 an 16384000 / (16000 * 256) = 4 ; + { + sysctl_clock_set_threshold(SYSCTL_THRESHOLD_I2S0_M + self->i2s_num, args[ARG_mclk].u_int); + } + + //set buffer len + if(args[ARG_sample_points].u_int > MAX_SAMPLE_POINTS) + { + mp_raise_ValueError("[MAIXPY]I2S:invalid buffer length"); + } + self->points_num = args[ARG_sample_points].u_int; + self->buf = m_new(uint32_t,self->points_num); + + //set i2s channel mask + self->chn_mask = 0; + + return mp_const_true; +} +STATIC mp_obj_t Maix_i2s_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get i2s num + mp_int_t i2s_num = mp_obj_get_int(args[0]); + if (i2s_num >= I2S_DEVICE_MAX) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "[MAIXPY]I2S%d:does not exist", i2s_num)); + } + + // create instance + Maix_i2s_obj_t *self = m_new_obj(Maix_i2s_obj_t); + self->base.type = &Maix_i2s_type; + self->i2s_num = i2s_num; + self->sample_rate = 0; + memset(&self->channel,0,4 * sizeof(i2s_channle_t)); + + // init instance + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + Maix_i2s_init_helper(self, n_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t Maix_i2s_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return Maix_i2s_init_helper(args[0], n_args -1 , args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_init_obj, 0, Maix_i2s_init); + +STATIC mp_obj_t Maix_i2s_channel_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + //get i2s obj + Maix_i2s_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + //parse parameter + enum{ARG_channel, + ARG_mode, + ARG_resolution, + ARG_cycles, + ARG_align_mode, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_channel, MP_ARG_INT, {.u_int = I2S_CHANNEL_0} }, + { MP_QSTR_mode, MP_ARG_INT, {.u_int = I2S_RECEIVER} }, + { MP_QSTR_resolution, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = RESOLUTION_16_BIT} }, + { MP_QSTR_cycles, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SCLK_CYCLES_32} }, + { MP_QSTR_align_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = STANDARD_MODE} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + //set channel + if(args[ARG_channel].u_int > I2S_CHANNEL_3) + { + mp_raise_ValueError("[MAIXPY]I2S:invalid i2s channle"); + } + i2s_channel_num_t channel_num = args[ARG_channel].u_int; + i2s_channle_t* channle = &self->channel[channel_num]; + + //set resolution + if(args[ARG_resolution].u_int > RESOLUTION_32_BIT ) + { + mp_raise_ValueError("[MAIXPY]I2S:invalid resolution"); + } + channle->resolution = args[ARG_resolution].u_int; + if(args[ARG_cycles].u_int > SCLK_CYCLES_32 ) + { + mp_raise_ValueError("[MAIXPY]I2S:invalid cycles"); + } + channle->cycles = args[ARG_cycles].u_int; + self->cycles = args[ARG_cycles].u_int; + + //set align mode + if(args[ARG_align_mode].u_int != STANDARD_MODE && args[ARG_align_mode].u_int != RIGHT_JUSTIFYING_MODE && args[ARG_align_mode].u_int != LEFT_JUSTIFYING_MODE) + { + mp_raise_ValueError("[MAIXPY]I2S:invalid align mode"); + } + channle->align_mode = args[ARG_align_mode].u_int; + + //set mode + if(args[ARG_mode].u_int > I2S_RECEIVER ) + { + mp_raise_ValueError("[MAIXPY]I2S:invalid cycles"); + } + channle->mode = args[ARG_mode].u_int; + + //running config + if(channle->mode == I2S_RECEIVER) + { + self->chn_mask |= 0x3 << (channel_num * 2); + i2s_init(self->i2s_num, I2S_RECEIVER, self->chn_mask); + i2s_rx_channel_config(self->i2s_num, + channel_num, + channle->resolution, + channle->cycles, + TRIGGER_LEVEL_4, + channle->align_mode); + } + else + { + self->chn_mask |= 0x3 << (channel_num * 2); + i2s_init(self->i2s_num, I2S_TRANSMITTER,self->chn_mask); + i2s_tx_channel_config(self->i2s_num, + channel_num, + channle->resolution, + channle->cycles, + TRIGGER_LEVEL_4, + channle->align_mode); + } + return mp_const_true; +} +MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_channel_config_obj, 2, Maix_i2s_channel_config); + +STATIC mp_obj_t Maix_i2s_set_sample_rate(void* self_, mp_obj_t sample_rate) +{ + Maix_i2s_obj_t* self = (Maix_i2s_obj_t*)self_; + uint32_t smp_rate = mp_obj_get_int(sample_rate); + if(smp_rate > MAX_SAMPLE_RATE) + { + mp_raise_ValueError("[MAIXPY]I2S:invalid sample rate"); + } + int res = i2s_set_sample_rate(self->i2s_num,smp_rate); + + //judege cycles,which channel should we select ? + if(self->cycles == SCLK_CYCLES_16) + { + self->sample_rate = res / 32; + } + else if(self->cycles == SCLK_CYCLES_24) + { + self->sample_rate = res / 48; + } + else if(self->cycles == SCLK_CYCLES_32) + { + self->sample_rate = res / 64; + } + return mp_const_true; +} +MP_DEFINE_CONST_FUN_OBJ_2(Maix_i2s_set_sample_rate_obj,Maix_i2s_set_sample_rate); + + +STATIC mp_obj_t Maix_i2s_record(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)//point_nums,time +{ + //get i2s obj + Maix_i2s_obj_t *self = pos_args[0]; + Maix_audio_obj_t *audio_obj = m_new_obj(Maix_audio_obj_t); + audio_obj->audio.type = I2S_AUDIO; + //parse parameter + enum{ARG_points, + ARG_time, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_points, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_time, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + audio_obj->base.type = &Maix_audio_type; + + //compute buffer length + if(args[ARG_points].u_int > 0) + { + if(audio_obj->audio.points > self->points_num) + { + mp_raise_ValueError("[MAIXPY]I2S:Too many points"); + } + audio_obj->audio.points = args[ARG_points].u_int; + char* audio_buf = m_new(uint32_t, audio_obj->audio.points); + if (audio_buf == NULL) { + mp_raise_ValueError("[MAIXPY]I2S:create audio new buf error"); + } + memcpy(audio_buf, self->buf, sizeof(uint32_t) * audio_obj->audio.points); + audio_obj->audio.buf = audio_buf; + } + else if(args[ARG_time].u_int > 0) + { + if(self->sample_rate <= 0) + mp_raise_ValueError("[MAIXPY]I2S:please set sample rate"); + uint32_t record_sec = args[ARG_time].u_int; + uint32_t smp_points = self->sample_rate * record_sec; + if(smp_points > self->points_num) + mp_raise_ValueError("[MAIXPY]I2S:sampling size is out of bounds"); + audio_obj->audio.points = smp_points; + char* audio_buf = m_new(uint32_t, audio_obj->audio.points); + if (audio_buf == NULL) + { + mp_raise_ValueError("[MAIXPY]I2S:create audio new buf error"); + } + memcpy(audio_buf, self->buf, sizeof(uint32_t) * smp_points); + audio_obj->audio.buf = audio_buf; + }else + { + mp_raise_ValueError("[MAIXPY]I2S:please input recording points or time"); + } + + //record + i2s_receive_data_dma(self->i2s_num, audio_obj->audio.buf, audio_obj->audio.points , DMAC_CHANNEL3); + // dmac_wait_idle(DMAC_CHANNEL3);//wait to finish recv + return MP_OBJ_FROM_PTR(audio_obj); +} +MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_record_obj,1,Maix_i2s_record); + +STATIC mp_obj_t Maix_i2s_wait_record(void*self_) +{ + dmac_wait_idle(DMAC_CHANNEL3);//wait to finish recv + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(Maix_i2s_wait_record_obj, Maix_i2s_wait_record); + +STATIC mp_obj_t Maix_i2s_play(void*self_, mp_obj_t audio_obj) +{ + Maix_i2s_obj_t* self = (Maix_i2s_obj_t*)self_; + Maix_audio_obj_t *audio_p = MP_OBJ_TO_PTR(audio_obj); + i2s_send_data_dma(self->i2s_num, audio_p->audio.buf, audio_p->audio.points, DMAC_CHANNEL4); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(Maix_i2s_play_obj,Maix_i2s_play); + +STATIC mp_obj_t Maix_i2s_deinit(void*self_) +{ + Maix_i2s_obj_t* self = (Maix_i2s_obj_t*)self_; + m_del(uint32_t,self->buf,self->points_num); + m_del_obj(Maix_i2s_obj_t,self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(Maix_i2s_deinit_obj,Maix_i2s_deinit); + +// STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_set_dma_divede_16_obj,1,); +// STATIC MP_DEFINE_CONST_FUN_OBJ_KW(Maix_i2s_set_dma_divede_16_obj,1,); + + +STATIC const mp_rom_map_elem_t Maix_i2s_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___deinit__), MP_ROM_PTR(&Maix_i2s_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&Maix_i2s_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_channel_config), MP_ROM_PTR(&Maix_i2s_channel_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_sample_rate), MP_ROM_PTR(&Maix_i2s_set_sample_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&Maix_i2s_record_obj) }, + { MP_ROM_QSTR(MP_QSTR_wait_record), MP_ROM_PTR(&Maix_i2s_wait_record_obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&Maix_i2s_play_obj) }, + //advance interface , some user don't use it + // { MP_ROM_QSTR(MP_QSTR_set_dma_divede_16), MP_ROM_PTR(&Maix_i2s_set_dma_divede_16_obj) }, + // { MP_ROM_QSTR(MP_QSTR_set_dma_divede_16), MP_ROM_PTR(&Maix_i2s_get_dma_divede_16_obj) }, + { MP_ROM_QSTR(MP_QSTR_DEVICE_0), MP_ROM_INT(I2S_DEVICE_0) }, + { MP_ROM_QSTR(MP_QSTR_DEVICE_1), MP_ROM_INT(I2S_DEVICE_1) }, + { MP_ROM_QSTR(MP_QSTR_DEVICE_2), MP_ROM_INT(I2S_DEVICE_2) }, + + { MP_ROM_QSTR(MP_QSTR_CHANNEL_0), MP_ROM_INT(I2S_CHANNEL_0) }, + { MP_ROM_QSTR(MP_QSTR_CHANNEL_1), MP_ROM_INT(I2S_CHANNEL_1) }, + { MP_ROM_QSTR(MP_QSTR_CHANNEL_2), MP_ROM_INT(I2S_CHANNEL_2) }, + { MP_ROM_QSTR(MP_QSTR_CHANNEL_3), MP_ROM_INT(I2S_CHANNEL_3) }, + + { MP_ROM_QSTR(MP_QSTR_IGNORE_WORD_LENGTH), MP_ROM_INT(IGNORE_WORD_LENGTH) }, + { MP_ROM_QSTR(MP_QSTR_RESOLUTION_12_BIT), MP_ROM_INT(RESOLUTION_12_BIT) }, + { MP_ROM_QSTR(MP_QSTR_RESOLUTION_16_BIT), MP_ROM_INT(RESOLUTION_16_BIT) }, + { MP_ROM_QSTR(MP_QSTR_RESOLUTION_20_BIT), MP_ROM_INT(RESOLUTION_20_BIT) }, + { MP_ROM_QSTR(MP_QSTR_RESOLUTION_24_BIT), MP_ROM_INT(RESOLUTION_24_BIT) }, + { MP_ROM_QSTR(MP_QSTR_RESOLUTION_32_BIT), MP_ROM_INT(RESOLUTION_32_BIT) }, + + { MP_ROM_QSTR(MP_QSTR_SCLK_CYCLES_16), MP_ROM_INT(SCLK_CYCLES_16) }, + { MP_ROM_QSTR(MP_QSTR_SCLK_CYCLES_24), MP_ROM_INT(SCLK_CYCLES_24) }, + { MP_ROM_QSTR(MP_QSTR_SCLK_CYCLES_32), MP_ROM_INT(SCLK_CYCLES_32) }, + + { MP_ROM_QSTR(MP_QSTR_TRANSMITTER), MP_ROM_INT(I2S_TRANSMITTER) }, + { MP_ROM_QSTR(MP_QSTR_RECEIVER), MP_ROM_INT(I2S_RECEIVER) }, + + { MP_ROM_QSTR(MP_QSTR_STANDARD_MODE), MP_ROM_INT(STANDARD_MODE) }, + { MP_ROM_QSTR(MP_QSTR_RIGHT_JUSTIFYING_MODE), MP_ROM_INT(RIGHT_JUSTIFYING_MODE) }, + { MP_ROM_QSTR(MP_QSTR_LEFT_JUSTIFYING_MODE), MP_ROM_INT(LEFT_JUSTIFYING_MODE) }, + +}; + +STATIC MP_DEFINE_CONST_DICT(Maix_i2s_dict, Maix_i2s_locals_dict_table); + +const mp_obj_type_t Maix_i2s_type = { + { &mp_type_type }, + .name = MP_QSTR_I2S, + .print = Maix_i2s_print, + .make_new = Maix_i2s_make_new, + .locals_dict = (mp_obj_dict_t*)&Maix_i2s_dict, +}; diff --git a/src/声源定位代码/mic-code/Maix/Maix_kpu.c b/src/声源定位代码/mic-code/Maix/Maix_kpu.c new file mode 100644 index 0000000..dad3aae --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/Maix_kpu.c @@ -0,0 +1,1840 @@ +/* +* Copyright 2019 Sipeed Co.,Ltd. + +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include +#include + +#include "sipeed_yolo2.h" +#include "sipeed_conf.h" +#include "sipeed_kpu.h" + +#include "w25qxx.h" + +#include +#include "mpconfigboard.h" + +#include "imlib.h" +#include "py_assert.h" +#include "py_helper.h" +#include "extmod/vfs.h" +#include "vfs_wrapper.h" +#include "py_image.h" +#include "syscalls.h" +#include "printf.h" +#include "sleep.h" +#include "sipeed_mem.h" +#include "Maix_kpu.h" + +/////////////////////////////////////////////////////////////////////////////// + + +typedef struct{ + uint16_t index; + uint16_t wi; + uint16_t hi; + uint16_t wo; + uint16_t ho; + uint16_t chi; + uint16_t cho; + uint16_t dw; + uint16_t kernel_type; + uint16_t pool_type; + uint32_t type; + uint32_t para_size; +} __attribute__((aligned(8))) py_kpu_netinfo_list_data_t; + +static int check_img_format(image_t* arg_img, uint16_t w, uint16_t h, uint16_t ch, int kmodel_type) +{ + if (arg_img->pix_ai == NULL) + { + mp_printf(&mp_plat_print, "[MAIXPY]kpu: pix_ai is NULL!\r\n"); + return -1; + } + if(abs(kmodel_type)==3 || abs(kmodel_type)==4){ + if(arg_img->w != w || arg_img->h != h) + { + mp_printf(&mp_plat_print, "[MAIXPY]kpu: img w=%d,h=%d, but model w=%d,h=%d\r\n",\ + arg_img->w, arg_img->h, w, h); + return -1; + } + if(arg_img->bpp == IMAGE_BPP_GRAYSCALE && ch != 1) + { + mp_printf(&mp_plat_print, "[MAIXPY]kpu: grayscale img, but model channel=%d\r\n", ch); + return -1; + } + if(arg_img->bpp == IMAGE_BPP_RGB565 && ch != 3) + { + mp_printf(&mp_plat_print, "[MAIXPY]kpu: RGB img, but model channel=%d\r\n", ch); + return -1; + } + } + if(arg_img->bpp != IMAGE_BPP_GRAYSCALE && arg_img->bpp != IMAGE_BPP_RGB565) + { + mp_printf(&mp_plat_print, "[MAIXPY]kpu: img bpp not support yet!\r\n"); + return -1; + } + //here is right image format + return 0; +} + + +static int py_kpu_class_yolo2_print_to_buf(mp_obj_t self_in, char *buf); + +static void py_kpu_net_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_kpu_net_obj_t *self = self_in; + + const char *path = NULL; + if(MP_OBJ_IS_STR(self->model_path)) + { + path = mp_obj_str_get_str(self->model_path); + } + + uint32_t addr = 0; + if(MP_OBJ_IS_INT(self->model_addr)) + { + addr = mp_obj_get_int(self->model_addr); + } + + char net_args[512]; + + if(py_kpu_class_yolo2_print_to_buf(self->net_args, net_args) != 0) + { + sprintf(net_args,"\"(null)\""); + } + + mp_printf(print, + "{\"model_addr\": %d, \"model_size\": %d, \"model_path\": \"%s\", \"net_args\": %s}", + addr, + mp_obj_get_int(self->model_size), + path, + net_args + ); +} + +STATIC mp_obj_t py_kpu_deinit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +mp_obj_t py_kpu_net_del(mp_obj_t self_in) +{ + mp_printf(&mp_plat_print, "kpu_net __del__\r\n"); + py_kpu_deinit(1, &self_in, NULL); + return mp_const_none; +} +mp_obj_t py_kpu_net_model_addr(mp_obj_t self_in) { return ((py_kpu_net_obj_t *)self_in)->model_addr; } +mp_obj_t py_kpu_net_model_size(mp_obj_t self_in) { return ((py_kpu_net_obj_t *)self_in)->model_size; } +mp_obj_t py_kpu_net_model_path(mp_obj_t self_in) { return ((py_kpu_net_obj_t *)self_in)->model_path; } +mp_obj_t py_kpu_net_arg(mp_obj_t self_in) { return ((py_kpu_net_obj_t *)self_in)->net_args; } + +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_net_del_obj, py_kpu_net_del); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_net_model_addr_obj, py_kpu_net_model_addr); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_net_model_size_obj, py_kpu_net_model_size); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_net_model_path_obj, py_kpu_net_model_path); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_net_arg_obj, py_kpu_net_arg); + +static const mp_rom_map_elem_t py_kpu_net_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&py_kpu_net_del_obj) }, + { MP_ROM_QSTR(MP_QSTR_model_addr), MP_ROM_PTR(&py_kpu_net_model_addr_obj) }, + { MP_ROM_QSTR(MP_QSTR_model_size), MP_ROM_PTR(&py_kpu_net_model_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_model_path), MP_ROM_PTR(&py_kpu_net_model_path_obj) }, + { MP_ROM_QSTR(MP_QSTR_net_arg), MP_ROM_PTR(&py_kpu_net_arg_obj) } +}; + +static MP_DEFINE_CONST_DICT(py_kpu_net_dict, py_kpu_net_dict_table); + +const mp_obj_type_t py_kpu_net_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_kpu_net, + .print = py_kpu_net_obj_print, + .locals_dict = (mp_obj_t) &py_kpu_net_dict +}; + +typedef struct { + uint32_t magic_number; + uint32_t layer_number; + uint32_t layer_cfg_addr_offset; + uint32_t eight_bit_mode; + float scale; + float bias; + } model_config_t; + + +typedef struct { + uint32_t reg_addr_offset; + uint32_t act_addr_offset; + uint32_t bn_addr_offset; + uint32_t bn_len; + uint32_t weights_addr_offset; + uint32_t weights_len; + } layer_config_t; + +static char* get_kpu_err_str(int err) +{ + switch(err) + { + case SIPEED_KPU_ERR_NONE: + return "ERR_NONE"; + case SIPEED_KPU_ERR_PARAM: + return "ERR_PARAM: please check param, load address or kmodel file name"; + case SIPEED_KPU_ERR_KMODEL_VERSION: + #if CONFIG_MICROPYTHON_KMODEL_V4_SUPPORT + return "ERR_KMODEL_VERSION: only support kmodel V3/V4 now"; + #else + return "ERR_KMODEL_VERSION: only support kmodel V3"; + #endif + case SIPEED_KPU_ERR_KMODEL_FORMAT: + return "ERR_KMODEL_FORMAT: layer_header.body_size <=0"; + case SIPEED_KPU_ERR_DECRYPT: + return "ERR_DECRYPT: check smodel match with your board"; + case SIPEED_KPU_ERR_READ_FILE: + return "ERR_READ_FILE: read file failed"; + case SIPEED_KPU_ERR_NO_MEM: + return "ERR_NO_MEM: memory not enough"; + case SIPEED_KPU_ERR_GET_CONV_LAYER: + return "ERR_GET_CONV_LAYER: first layer should be conv layer"; + case SIPEED_KPU_ERR_RUN_MODEL: + return "ERR_RUN_MODEL: maybe model dirty"; + case SIPEED_KPU_ERR_MODELS_FULL: + return "ERR_MODELS_FULL: we only support load 5 models in the same time"; + case SIPEED_KPU_ERR_PERMITION: + return "ERR_PERMITION"; + case SIPEED_KPU_ERR_IDX_OUTRANGE: + return "SIPEED_KPU_ERR_IDX_OUTRANGE"; + case SIPEED_KPU_ERR_SIZE_NOTMATCH: + return "SIPEED_KPU_ERR_SIZE_NOTMATCH"; + case SIPEED_KPU_ERR_OUTPUTS_NODONE: + return "ERR_OUTPUTS_SET: need kpu.set_outputs() to set shape"; + case SIPEED_KPU_ERR_NOT_IMPLEMENT: + return "ERR_NOT_IMPLEMENT"; + case SIPEED_KPU_ERR_UNKNOWN: + default: + return "ERR_UNKNOWN"; + } +} + +int model_init(kpu_task_t *task, const char *path) +{ + uint32_t layer_cfg_addr; + model_config_t model_cfg; + layer_config_t layer_cfg; + kpu_layer_argument_t *layer_arg_ptr; + void *ptr; + mp_obj_t file; + int ferr; + + file = vfs_internal_open(path,"rb", &ferr); + if(file == MP_OBJ_NULL || ferr != 0) + mp_raise_OSError(ferr); + + memset(task, 0, sizeof(kpu_task_t)); + //model_read(addr, (uint8_t *)&model_cfg, sizeof(model_config_t)); + vfs_internal_read(file, (uint8_t *)&model_cfg, sizeof(model_config_t), &ferr); + if( ferr != 0) + mp_raise_OSError(ferr); + + if (model_cfg.magic_number != 0x12345678) + return -1; + layer_arg_ptr = (kpu_layer_argument_t *)malloc(12 * 8 * model_cfg.layer_number); + if (layer_arg_ptr == NULL) + return -2; + + memset(layer_arg_ptr, 0, 12 * 8 * model_cfg.layer_number); + task->layers = layer_arg_ptr; + task->layers_length = model_cfg.layer_number; + task->eight_bit_mode = model_cfg.eight_bit_mode; + task->output_scale = model_cfg.scale; + task->output_bias = model_cfg.bias; + + layer_cfg_addr = model_cfg.layer_cfg_addr_offset; + for (uint32_t i = 0; i < model_cfg.layer_number; i++) + { + // read layer config + //model_read(layer_cfg_addr, (uint8_t *)&layer_cfg, sizeof(layer_config_t)); + vfs_internal_seek(file, layer_cfg_addr, VFS_SEEK_SET, &ferr); + if(ferr != 0) + mp_raise_OSError(ferr); + + vfs_internal_read(file, (uint8_t *)&layer_cfg, sizeof(layer_config_t), &ferr); + if( ferr != 0) + mp_raise_OSError(ferr); + + // read reg arg + //model_read(addr + layer_cfg.reg_addr_offset, (uint8_t *)layer_arg_ptr, sizeof(kpu_layer_argument_t)); + vfs_internal_seek(file, layer_cfg.reg_addr_offset, VFS_SEEK_SET, &ferr); + if(ferr != 0) + mp_raise_OSError(ferr); + + vfs_internal_read(file, (uint8_t *)layer_arg_ptr, sizeof(kpu_layer_argument_t), &ferr); + if( ferr != 0) + mp_raise_OSError(ferr); + + + + // read act arg + ptr = malloc(sizeof(kpu_activate_table_t)); + if (ptr == NULL) + return -2; + //model_read(addr + layer_cfg.act_addr_offset, (uint8_t *)ptr, sizeof(kpu_activate_table_t)); + + vfs_internal_seek(file, layer_cfg.act_addr_offset, VFS_SEEK_SET, &ferr); + if(ferr != 0) + mp_raise_OSError(ferr); + + vfs_internal_read(file, (uint8_t *)ptr, sizeof(kpu_activate_table_t), &ferr); + if( ferr != 0) + mp_raise_OSError(ferr); + + + layer_arg_ptr->kernel_calc_type_cfg.data.active_addr = (uint32_t)ptr; + // read bn arg + ptr = malloc(layer_cfg.bn_len); + if (ptr == NULL) + return -2; + //model_read(addr + layer_cfg.bn_addr_offset, (uint8_t *)ptr, layer_cfg.bn_len); + vfs_internal_seek(file, layer_cfg.bn_addr_offset, VFS_SEEK_SET, &ferr); + if(ferr != 0) + mp_raise_OSError(ferr); + + vfs_internal_read(file, (uint8_t *)ptr, layer_cfg.bn_len, &ferr); + if( ferr != 0) + mp_raise_OSError(ferr); + + layer_arg_ptr->kernel_pool_type_cfg.data.bwsx_base_addr = (uint32_t)ptr; + // read weights arg + ptr = malloc(layer_cfg.weights_len); + if (ptr == NULL) + return -2; + //model_read(addr + layer_cfg.weights_addr_offset, (uint8_t *)ptr, layer_cfg.weights_len); + vfs_internal_seek(file, layer_cfg.weights_addr_offset, VFS_SEEK_SET, &ferr); + if(ferr != 0) + mp_raise_OSError(ferr); + + vfs_internal_read(file, (uint8_t *)ptr, layer_cfg.weights_len, &ferr); + if( ferr != 0) + mp_raise_OSError(ferr); + + layer_arg_ptr->kernel_load_cfg.data.para_start_addr = (uint32_t)ptr; + // next layer + layer_cfg_addr += sizeof(layer_config_t); + layer_arg_ptr++; + } + vfs_internal_close(file, &ferr); + if( ferr != 0) + mp_raise_OSError(ferr); + return 0; +} + +int model_deinit(kpu_task_t *task) +{ + for (uint32_t i = 0; i < task->layers_length; i++) + { + free((void*)task->layers[i].kernel_calc_type_cfg.data.active_addr); + free((void*)task->layers[i].kernel_pool_type_cfg.data.bwsx_base_addr); + free((void*)task->layers[i].kernel_load_cfg.data.para_start_addr); + } + free(task->layers); + return 0; +} + +STATIC mp_obj_t py_kpu_class_load(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + int err = 0; + uint32_t model_size; + py_kpu_net_obj_t *o = m_new_obj_with_finaliser(py_kpu_net_obj_t); + o->base.type = &py_kpu_net_obj_type; + + if(mp_obj_get_type(pos_args[0]) == &mp_type_int) + { //load from flash address + mp_int_t model_addr = mp_obj_get_int(pos_args[0]); + + if(model_addr <= 0)//TODO: address of code end + { + m_del(py_kpu_net_obj_t, o,sizeof(py_kpu_net_obj_t)); + mp_raise_ValueError("[MAIXPY]kpu: model_addr must > 0 "); + return mp_const_false; + } + + o->model_addr = mp_obj_new_int(model_addr); + o->model_path = mp_const_none; + sipeed_kpu_err_t ret = sipeed_kpu_model_load(&o->kmodel_ctx, model_addr, NULL, &model_size); + if(ret != SIPEED_KPU_ERR_NONE) + { + err = ret; //load error + goto error; + } + } + else if(mp_obj_get_type(pos_args[0]) == &mp_type_str) + { + const char *path = mp_obj_str_get_str(pos_args[0]); + + o->model_path = mp_obj_new_str(path,strlen(path)); + o->model_addr = mp_const_none; + + // if(NULL != strstr(path,".bin")) + // { + // err=model_init(kpu_task,path); + // if( err != 0 ) + // { + // model_deinit(kpu_task); + // goto error; + // } + + // } + // else + if( (NULL != strstr(path,".kmodel")) || (NULL != strstr(path,".smodel")) || (NULL != strstr(path,".emodel")) ) + { + int ret = sipeed_kpu_model_load(&o->kmodel_ctx, 0, path, &model_size); + if(ret != SIPEED_KPU_ERR_NONE) + { + err = ret; + goto error; + } + } + else + { + m_del(py_kpu_net_obj_t, o,sizeof(py_kpu_net_obj_t)); + mp_raise_ValueError("[MAIXPY]kpu: model format don't match, only supply .kmodel "); + return mp_const_false; + } + + } + else + { + m_del(py_kpu_net_obj_t, o,sizeof(py_kpu_net_obj_t)); + mp_raise_TypeError("[MAIXPY]kpu: only accept int or string"); + return mp_const_false; + } + o->net_args = mp_const_none; + o->net_deinit = mp_const_none; + o->model_size = mp_obj_new_int(model_size); + o->max_layers = mp_obj_new_int(sipeed_kpu_model_get_layer_num(o->kmodel_ctx)); + + return MP_OBJ_FROM_PTR(o); + +error: +{ + char* err_msg = get_kpu_err_str(err); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "[MAIXPY]kpu: load error:%d, %s", err, err_msg)); +} +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_kpu_class_load_obj, 1, py_kpu_class_load); + + + + +STATIC mp_obj_t py_kpu_class_load_flash(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + int err = 0; + uint32_t model_size; + py_kpu_net_obj_t *o = m_new_obj_with_finaliser(py_kpu_net_obj_t); + o->base.type = &py_kpu_net_obj_type; + + if((mp_obj_get_type(pos_args[0]) == &mp_type_int) && \ + (mp_obj_get_type(pos_args[1]) == &mp_type_int) && \ + (mp_obj_get_type(pos_args[2]) == &mp_type_int) && \ + (mp_obj_get_type(pos_args[3]) == &mp_type_int)) + { + mp_int_t model_addr = mp_obj_get_int(pos_args[0]); + mp_int_t is_dual_buf = mp_obj_get_int(pos_args[1]); + mp_int_t batch_size = mp_obj_get_int(pos_args[2]); + mp_int_t spi_speed = mp_obj_get_int(pos_args[3]); + + if(model_addr <= 0)//TODO: address of code end + { + m_del(py_kpu_net_obj_t, o,sizeof(py_kpu_net_obj_t)); + mp_raise_ValueError("[MAIXPY]kpu: model_addr must > 0 "); + return mp_const_false; + } + + o->model_addr = mp_obj_new_int(model_addr); + o->model_path = mp_const_none; + sipeed_kpu_err_t ret = sipeed_kpu_model_load_flash(&o->kmodel_ctx, model_addr, is_dual_buf, batch_size, spi_speed, &model_size); + if(ret != SIPEED_KPU_ERR_NONE) + { + err = ret; //load error + goto error; + } + o->net_args = mp_const_none; + o->net_deinit = mp_const_none; + o->model_size = mp_obj_new_int(model_size); + o->max_layers = mp_obj_new_int(sipeed_kpu_model_get_layer_num(o->kmodel_ctx)); + return MP_OBJ_FROM_PTR(o); + } else { + mp_raise_ValueError("[MAIXPY]kpu: load_flash arg format error: task=kpu.load_flash(flash_addr, is_dual_buf, batch_size, spi_speed)"); + return mp_const_false; + } +error: +{ + char* err_msg = get_kpu_err_str(err); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "[MAIXPY]kpu: load_flash error:%d, %s", err, err_msg)); +} +return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_kpu_class_load_flash_obj, 4, py_kpu_class_load_flash); + + +//Kmodel V4 need set output shape manually +//set_outputs(int idx, int w, int h, int ch) +STATIC mp_obj_t py_kpu_class_set_outputs(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + if((mp_obj_get_type(pos_args[0]) == &py_kpu_net_obj_type) && \ + (mp_obj_get_type(pos_args[1]) == &mp_type_int) && \ + (mp_obj_get_type(pos_args[2]) == &mp_type_int) && \ + (mp_obj_get_type(pos_args[3]) == &mp_type_int) && \ + (mp_obj_get_type(pos_args[4]) == &mp_type_int)) + { + py_kpu_net_obj_t *kpu_net = MP_OBJ_TO_PTR(pos_args[0]); + uint16_t idx = mp_obj_get_int(pos_args[1]); + uint16_t w = mp_obj_get_int(pos_args[2]); + uint16_t h = mp_obj_get_int(pos_args[3]); + uint16_t ch = mp_obj_get_int(pos_args[4]); + int res = sipeed_kpu_set_outputs_shape(kpu_net->kmodel_ctx, idx, w, h, ch); + mp_obj_t ret=mp_const_false; + + switch(res) + { + case SIPEED_KPU_ERR_IDX_OUTRANGE: + mp_printf(&mp_plat_print, \ + "[MAIXPY]kpu: set_outputs arg value error:kmodel output idx %d out of range\r\n", idx); + break; + case SIPEED_KPU_ERR_SIZE_NOTMATCH: + mp_printf(&mp_plat_print, \ + "[MAIXPY]kpu: set_outputs arg value error: w,c,ch size not match output size\r\n"); + break; + case SIPEED_KPU_ERR_NONE: + ret=mp_const_true; + break; + case SIPEED_KPU_ERR_PARAM: + default: + mp_printf(&mp_plat_print, \ + "[MAIXPY]kpu: set_outputs ctx error, maybe init err:%d\r\n", res); + break; + + } + return ret; + } else { + mp_raise_ValueError("[MAIXPY]kpu: set_outputs arg format error: set_outputs(task, int idx, int w, int h, int ch)"); + return mp_const_false; + } + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_kpu_class_set_outputs_obj, 4, py_kpu_class_set_outputs); + +/////////////////////////////////////////////////////////////////////////////// + +typedef struct py_kpu_class_yolo_args_obj { + mp_obj_base_t base; + + mp_obj_t threshold, nms_value, anchor_number, anchor, rl_args; +} __attribute__((aligned(8))) py_kpu_class_yolo_args_obj_t; + +typedef struct py_kpu_class_region_layer_arg +{ + float threshold; + float nms_value; + int anchor_number; + float *anchor; +}__attribute__((aligned(8))) py_kpu_class_yolo_region_layer_arg_t; + +static void py_kpu_class_yolo2_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_kpu_class_yolo_args_obj_t *yolo_args = self_in; + + py_kpu_class_yolo_region_layer_arg_t *rl_arg = yolo_args->rl_args; + + char msg[300]; + + uint8_t num = rl_arg->anchor_number; + + if(num>0) + { + sprintf(msg,"%f",rl_arg->anchor[0]); + for(uint16_t i = 1; i < num * 2; i++) + snprintf(msg, sizeof(msg), "%s, %f",msg, rl_arg->anchor[i]); + } + + mp_printf(print, + "{\"threshold\":%f, \"nms_value\":%f, \"anchor_number\":%d, \"anchor\":\"(%s)\"}", + rl_arg->threshold, + rl_arg->nms_value, + rl_arg->anchor_number, + msg); +} + +mp_obj_t py_kpu_calss_yolo2_anchor(mp_obj_t self_in); + +mp_obj_t py_kpu_calss_yolo2_threshold(mp_obj_t self_in) { return ((py_kpu_class_yolo_args_obj_t *)self_in)->threshold; } +mp_obj_t py_kpu_calss_yolo2_nms_value(mp_obj_t self_in) { return ((py_kpu_class_yolo_args_obj_t *)self_in)->nms_value; } +mp_obj_t py_kpu_calss_yolo2_anchor_number(mp_obj_t self_in) { return ((py_kpu_class_yolo_args_obj_t *)self_in)->anchor_number; } + +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_calss_yolo2_anchor_obj, py_kpu_calss_yolo2_anchor); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_calss_yolo2_threshold_obj, py_kpu_calss_yolo2_threshold); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_calss_yolo2_nms_value_obj, py_kpu_calss_yolo2_nms_value); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_calss_yolo2_anchor_number_obj, py_kpu_calss_yolo2_anchor_number); + +static const mp_rom_map_elem_t py_kpu_class_yolo2_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_anchor), MP_ROM_PTR(&py_kpu_calss_yolo2_anchor_obj) }, + { MP_ROM_QSTR(MP_QSTR_threshold), MP_ROM_PTR(&py_kpu_calss_yolo2_threshold_obj) }, + { MP_ROM_QSTR(MP_QSTR_nms_value), MP_ROM_PTR(&py_kpu_calss_yolo2_nms_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_anchor_number), MP_ROM_PTR(&py_kpu_calss_yolo2_anchor_number_obj) } +}; + +static MP_DEFINE_CONST_DICT(py_kpu_class_yolo2_dict, py_kpu_class_yolo2_dict_table); + +static const mp_obj_type_t py_kpu_class_yolo_args_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_kpu_yolo2, + .print = py_kpu_class_yolo2_print, + // .subscr = py_kpu_calss_yolo2_subscr, + .locals_dict = (mp_obj_t) &py_kpu_class_yolo2_dict +}; + +static int py_kpu_class_yolo2_print_to_buf(mp_obj_t self_in, char *buf) +{ + if(buf == NULL) + return -1; + + if(mp_obj_get_type(self_in) == &py_kpu_class_yolo_args_obj_type) + { + py_kpu_class_yolo_args_obj_t *yolo_args = self_in; + + py_kpu_class_yolo_region_layer_arg_t *rl_arg = yolo_args->rl_args; + + char msg[300]; + + uint8_t num = rl_arg->anchor_number; + + if(num>0) + { + sprintf(msg,"%f",rl_arg->anchor[0]); + for(uint16_t i = 1; i < num * 2; i++) + snprintf(msg, sizeof(msg), "%s, %f",msg, rl_arg->anchor[i]); + } + + sprintf(buf, + "{\"threshold\":%f, \"nms_value\":%f, \"anchor_number\":%d, \"anchor\":\"(%s)\"}", + rl_arg->threshold, + rl_arg->nms_value, + rl_arg->anchor_number, + msg); + return 0; + } + return -1; +} + +mp_obj_t py_kpu_calss_yolo2_anchor(mp_obj_t self_in) +{ + if(mp_obj_get_type(self_in) == &py_kpu_class_yolo_args_obj_type) + { + py_kpu_class_yolo_args_obj_t *yolo_args = MP_OBJ_TO_PTR(self_in); + + py_kpu_class_yolo_region_layer_arg_t *rl_arg = yolo_args->rl_args; + + mp_obj_t *tuple, *tmp; + + tmp = (mp_obj_t *)malloc(rl_arg->anchor_number * 2 * sizeof(mp_obj_t)); + + for (uint8_t index = 0; index < rl_arg->anchor_number * 2; index++) + tmp[index] = mp_obj_new_float(rl_arg->anchor[index]); + + tuple = mp_obj_new_tuple(rl_arg->anchor_number * 2, tmp); + + free(tmp); + return tuple; + } + else + { + mp_raise_TypeError("[MAIXPY]kpu: object type error"); + return mp_const_false; + } +} + +mp_obj_t py_kpu_calss_yolo2_deinit(mp_obj_t self_in) +{ + if(mp_obj_get_type(self_in) == &py_kpu_class_yolo_args_obj_type) + { + py_kpu_class_yolo_args_obj_t *yolo_args = MP_OBJ_TO_PTR(self_in); + + py_kpu_class_yolo_region_layer_arg_t *rl_arg = yolo_args->rl_args; + + if(rl_arg->anchor) + { + free(rl_arg->anchor); + rl_arg->anchor = NULL; + } + + if(rl_arg) + { + free(rl_arg); + rl_arg->anchor = NULL; + } + return mp_const_true; + } + else + { + mp_raise_TypeError("[MAIXPY]kpu: object type error"); + return mp_const_false; + } +} + +STATIC mp_obj_t py_kpu_class_init_yolo2(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_kpu_net, ARG_threshold, ARG_nms_value, ARG_anchor_number, ARG_anchor, ARG_dma}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_kpu_net, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_threshold, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_nms_value, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_anchor_number, MP_ARG_INT, {.u_int = 0x0} }, + { MP_QSTR_anchor, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_dma, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(mp_obj_get_type(args[ARG_kpu_net].u_obj) == &py_kpu_net_obj_type) + { + float threshold, nms_value, *anchor = NULL; + int anchor_number; + + sipeed_kpu_use_dma(args[ARG_dma].u_int); + threshold = mp_obj_get_float(args[ARG_threshold].u_obj); + if(!(threshold >= 0.0 && threshold <= 1.0)) + { + mp_raise_ValueError("[MAIXPY]kpu: threshold only support 0 to 1"); + return mp_const_false; + } + + nms_value = mp_obj_get_float(args[ARG_nms_value].u_obj); + if(!(nms_value >= 0.0 && nms_value <= 1.0)) + { + mp_raise_ValueError("[MAIXPY]kpu: nms_value only support 0 to 1"); + return mp_const_false; + } + + anchor_number = args[ARG_anchor_number].u_int; + + if(anchor_number > 0) + { + //need free + anchor = (float*)malloc(anchor_number * 2 * sizeof(float)); + + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[ARG_anchor].u_obj, args[ARG_anchor_number].u_int*2, &items); + + for(uint8_t index = 0; index < args[ARG_anchor_number].u_int * 2; index++) + anchor[index] = mp_obj_get_float(items[index]); + } + else + { + mp_raise_ValueError("[MAIXPY]kpu: anchor_number should > 0"); + return mp_const_false; + } + + py_kpu_class_yolo_args_obj_t *yolo_args = m_new_obj(py_kpu_class_yolo_args_obj_t); + + yolo_args->base.type = &py_kpu_class_yolo_args_obj_type; + + yolo_args->threshold = mp_obj_new_float(threshold); + yolo_args->nms_value = mp_obj_new_float(nms_value); + yolo_args->anchor_number = mp_obj_new_int(anchor_number); + + mp_obj_t *tuple, *tmp; + + tmp = (mp_obj_t *)malloc(anchor_number * 2 * sizeof(mp_obj_t)); + + for (uint8_t index = 0; index < anchor_number * 2; index++) + tmp[index] = mp_obj_new_float(anchor[index]); + + tuple = mp_obj_new_tuple(anchor_number * 2, tmp); + + free(tmp); + + yolo_args->anchor = tuple; + + //need free + py_kpu_class_yolo_region_layer_arg_t *rl_arg = malloc(sizeof(py_kpu_class_yolo_region_layer_arg_t)); + + rl_arg->threshold = threshold; + rl_arg->nms_value = nms_value; + rl_arg->anchor_number = anchor_number; + rl_arg->anchor = anchor; + + yolo_args->rl_args = MP_OBJ_FROM_PTR(rl_arg); + + py_kpu_net_obj_t *kpu_net = MP_OBJ_TO_PTR(args[ARG_kpu_net].u_obj); + + kpu_net->net_args = MP_OBJ_FROM_PTR(yolo_args); + + kpu_net->net_deinit = MP_OBJ_FROM_PTR(py_kpu_calss_yolo2_deinit); + + return mp_const_true; + } + else + { + mp_raise_TypeError("[MAIXPY]kpu: kpu_net type error"); + return mp_const_false; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_kpu_class_init_yolo2_obj, 5, py_kpu_class_init_yolo2); + +/////////////////////////////////////////////////////////////////////////////// + +typedef struct py_kpu_class_yolo2_find_obj { + mp_obj_base_t base; + + mp_obj_t x, y, w, h, classid, index, value, objnum; +} __attribute__((aligned(8))) py_kpu_class_yolo2_find_obj_t; + +typedef struct py_kpu_class_list_link_data { + rectangle_t rect; + int classid; + float value; + int index; + int objnum; +} __attribute__((aligned(8))) py_kpu_class_yolo2__list_link_data_t; + +static void py_kpu_class_yolo2_find_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_kpu_class_yolo2_find_obj_t *self = self_in; + mp_printf(print, + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"value\":%f, \"classid\":%d, \"index\":%d, \"objnum\":%d}", + mp_obj_get_int(self->x), + mp_obj_get_int(self->y), + mp_obj_get_int(self->w), + mp_obj_get_int(self->h), + (double)mp_obj_get_float(self->value), + mp_obj_get_int(self->classid), + mp_obj_get_int(self->index), + mp_obj_get_int(self->objnum)); +} + +mp_obj_t py_kpu_class_yolo2_find_rect(mp_obj_t self_in) +{ + return mp_obj_new_tuple(4, (mp_obj_t[]){((py_kpu_class_yolo2_find_obj_t *)self_in)->x, + ((py_kpu_class_yolo2_find_obj_t *)self_in)->y, + ((py_kpu_class_yolo2_find_obj_t *)self_in)->w, + ((py_kpu_class_yolo2_find_obj_t *)self_in)->h}); +} + +mp_obj_t py_kpu_class_yolo2_find_x(mp_obj_t self_in) { return ((py_kpu_class_yolo2_find_obj_t *)self_in)->x; } +mp_obj_t py_kpu_class_yolo2_find_y(mp_obj_t self_in) { return ((py_kpu_class_yolo2_find_obj_t *)self_in)->y; } +mp_obj_t py_kpu_class_yolo2_find_w(mp_obj_t self_in) { return ((py_kpu_class_yolo2_find_obj_t *)self_in)->w; } +mp_obj_t py_kpu_class_yolo2_find_h(mp_obj_t self_in) { return ((py_kpu_class_yolo2_find_obj_t *)self_in)->h; } +mp_obj_t py_kpu_class_yolo2_find_classid(mp_obj_t self_in) { return ((py_kpu_class_yolo2_find_obj_t *)self_in)->classid; } +mp_obj_t py_kpu_class_yolo2_find_index(mp_obj_t self_in) { return ((py_kpu_class_yolo2_find_obj_t *)self_in)->index; } +mp_obj_t py_kpu_class_yolo2_find_value(mp_obj_t self_in) { return ((py_kpu_class_yolo2_find_obj_t *)self_in)->value; } +mp_obj_t py_kpu_class_yolo2_find_objnum(mp_obj_t self_in) { return ((py_kpu_class_yolo2_find_obj_t *)self_in)->objnum; } + +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_yolo2_find_rect_obj, py_kpu_class_yolo2_find_rect); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_yolo2_find_x_obj, py_kpu_class_yolo2_find_x); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_yolo2_find_y_obj, py_kpu_class_yolo2_find_y); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_yolo2_find_w_obj, py_kpu_class_yolo2_find_w); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_yolo2_find_h_obj, py_kpu_class_yolo2_find_h); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_yolo2_find_classid_obj, py_kpu_class_yolo2_find_classid); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_yolo2_find_index_obj, py_kpu_class_yolo2_find_index); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_yolo2_find_value_obj, py_kpu_class_yolo2_find_value); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_yolo2_find_objnum_obj, py_kpu_class_yolo2_find_objnum); + +static const mp_rom_map_elem_t py_kpu_class_yolo2_find_type_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_kpu_class_yolo2_find_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_kpu_class_yolo2_find_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_kpu_class_yolo2_find_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_kpu_class_yolo2_find_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_kpu_class_yolo2_find_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_classid), MP_ROM_PTR(&py_kpu_class_yolo2_find_classid_obj) }, + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&py_kpu_class_yolo2_find_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&py_kpu_class_yolo2_find_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_objnum), MP_ROM_PTR(&py_kpu_class_yolo2_find_objnum_obj) } +}; + +static MP_DEFINE_CONST_DICT(py_kpu_class_yolo2_find_type_locals_dict, py_kpu_class_yolo2_find_type_locals_dict_table); + +static const mp_obj_type_t py_kpu_class_yolo2_find_type = { + { &mp_type_type }, + .name = MP_QSTR_kpu_yolo2_find, + .print = py_kpu_class_yolo2_find_print, + // .subscr = py_kpu_class_subscr, + .locals_dict = (mp_obj_t) &py_kpu_class_yolo2_find_type_locals_dict +}; + +volatile static uint8_t g_ai_done_flag = 0; + +static void ai_done(void *ctx) +{ + g_ai_done_flag = 1; +} + +STATIC mp_obj_t py_kpu_class_run_yolo2(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + if(mp_obj_get_type(pos_args[0]) == &py_kpu_net_obj_type) + { + py_kpu_net_obj_t *kpu_net = MP_OBJ_TO_PTR(pos_args[0]); + image_t *arg_img = py_image_cobj(pos_args[1]); + //PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + uint16_t w0=0;uint16_t h0=0;uint16_t ch0=0; + int kmodel_type=sipeed_kpu_model_get_type(kpu_net->kmodel_ctx); + if(abs(kmodel_type)==3 || abs(kmodel_type)==4){ + if(sipeed_kpu_model_get_input_shape(kpu_net->kmodel_ctx, &w0, &h0, &ch0) != SIPEED_KPU_ERR_NONE) + { + mp_raise_ValueError("[MAIXPY]kpu: first layer not conv layer!\r\n"); + return mp_const_none; + } + } + if(check_img_format(arg_img, w0, h0, ch0, kmodel_type)) + { + mp_raise_ValueError("[MAIXPY]kpu: check img format err!\r\n"); + return mp_const_none; + } + /*****************************region prepare*************************************************/ + py_kpu_class_yolo_args_obj_t *net_args = MP_OBJ_TO_PTR(kpu_net->net_args); + py_kpu_class_yolo_region_layer_arg_t *rl_arg = net_args->rl_args; + region_layer_t kpu_detect_rl; + kpu_detect_rl.anchor_number = rl_arg->anchor_number; + kpu_detect_rl.anchor = rl_arg->anchor; + kpu_detect_rl.threshold = rl_arg->threshold; + kpu_detect_rl.nms_value = rl_arg->nms_value; + if(region_layer_init(&kpu_detect_rl, kpu_net->kmodel_ctx)) + { + mp_raise_ValueError("[MAIXPY]kpu: region_layer_init err!\r\n"); + return mp_const_none; + } + /*************************************************************************************/ + g_ai_done_flag = 0; + sipeed_kpu_err_t ret = sipeed_kpu_model_run(kpu_net->kmodel_ctx, arg_img->pix_ai, K210_DMA_CH_KPU, ai_done, NULL); + if(ret != SIPEED_KPU_ERR_NONE) + { + char* msg = get_kpu_err_str(ret); + mp_raise_msg(&mp_type_OSError, msg); + } + while (!g_ai_done_flag) + ; + g_ai_done_flag = 0; + /****************************start region layer***************************************/ + static obj_info_t mpy_kpu_detect_info; + region_layer_run(&kpu_detect_rl, &mpy_kpu_detect_info); + uint8_t obj_num = 0; + obj_num = mpy_kpu_detect_info.obj_number; + + if (obj_num > 0) + { + list_t out; + list_init(&out, sizeof(py_kpu_class_yolo2__list_link_data_t)); + + for (uint8_t index = 0; index < obj_num; index++) + { + py_kpu_class_yolo2__list_link_data_t lnk_data; + lnk_data.rect.x = mpy_kpu_detect_info.obj[index].x1; + lnk_data.rect.y = mpy_kpu_detect_info.obj[index].y1; + lnk_data.rect.w = mpy_kpu_detect_info.obj[index].x2 - mpy_kpu_detect_info.obj[index].x1; + lnk_data.rect.h = mpy_kpu_detect_info.obj[index].y2 - mpy_kpu_detect_info.obj[index].y1; + lnk_data.classid = mpy_kpu_detect_info.obj[index].classid; + lnk_data.value = mpy_kpu_detect_info.obj[index].prob; + + lnk_data.index = index; + lnk_data.objnum = obj_num; + list_push_back(&out, &lnk_data); + } + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + + for (size_t i = 0; list_size(&out); i++) + { + py_kpu_class_yolo2__list_link_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_kpu_class_yolo2_find_obj_t *o = m_new_obj(py_kpu_class_yolo2_find_obj_t); + + o->base.type = &py_kpu_class_yolo2_find_type; + + o->x = mp_obj_new_int(lnk_data.rect.x); + o->y = mp_obj_new_int(lnk_data.rect.y); + o->w = mp_obj_new_int(lnk_data.rect.w); + o->h = mp_obj_new_int(lnk_data.rect.h); + o->classid = mp_obj_new_int(lnk_data.classid); + o->index = mp_obj_new_int(lnk_data.index); + o->value = mp_obj_new_float(lnk_data.value); + o->objnum = mp_obj_new_int(lnk_data.objnum); + + objects_list->items[i] = o; + } + region_layer_deinit(&kpu_detect_rl); + return objects_list; + } + else + { + region_layer_deinit(&kpu_detect_rl); + + return mp_const_none; + } + } + else + { + mp_raise_TypeError("[MAIXPY]kpu: kpu_net type error"); + return mp_const_false; + } + +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_kpu_class_run_yolo2_obj, 2, py_kpu_class_run_yolo2); + +/////////////////////////////////////////////////////////////////////////////// + +typedef void (*call_net_arg_deinit)(mp_obj_t o); + +void call_deinit(call_net_arg_deinit call_back, mp_obj_t o) +{ + call_back(o); +} + +STATIC mp_obj_t py_kpu_deinit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + if(mp_obj_get_type(pos_args[0]) == &py_kpu_net_obj_type) + { + py_kpu_net_obj_t *kpu_net = MP_OBJ_TO_PTR(pos_args[0]); + + if(kpu_net->kmodel_ctx) + sipeed_kpu_model_destroy(&kpu_net->kmodel_ctx); + if(kpu_net->net_deinit != mp_const_none && MP_OBJ_TO_PTR(kpu_net->net_deinit)) + { + call_deinit(MP_OBJ_TO_PTR(kpu_net->net_deinit),kpu_net->net_args); + kpu_net->net_deinit = mp_const_none; + m_del_obj(py_kpu_class_yolo_args_obj_t, kpu_net->net_args); + kpu_net->net_args = mp_const_none; + } + return mp_const_true; + } + else + { + mp_raise_TypeError("[MAIXPY]kpu: kpu_net type error"); + return mp_const_false; + } + +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_kpu_deinit_obj, 1, py_kpu_deinit); +/////////////////////////////////////////////////////////////////////////////// +/*forward + 单纯的网络前向运�? + 输入参数�? + net结构体的obj(必须) + 是否使用softmax(可选) + stride(可选,默认1�? + 计算到第几层(可选):默认为计算完,可选计算到第n�? + 计算到第n层,即修改第n层的send_data_out�?,使能dma输出,方法为�? + 修改原自动生成的kpu_task_init,设置layers_length为n + + 输出�? + 特征图obj + 即n个通道的m*n的图片,0~255灰度,可以使用color map映射为伪彩色 + m*n即为最后一个layer的输出尺�? + last_layer->image_size.data.o_row_wid, o_col_high + 新建一个类型,直接存储特征图数组, + 对外提供转化某通道特征图到Image对象的方法, + 并且提供deinit方向释放特征图空间�? +*/ + + + +typedef struct fmap +{ + uint8_t* data; + uint32_t size; + uint16_t index; + uint16_t w; + uint16_t h; + uint16_t ch; + uint16_t typecode; +} __attribute__((aligned(8)))fmap_t; + +typedef struct py_kpu_fmap_obj +{ + mp_obj_base_t base; + fmap_t fmap; +} __attribute__((aligned(8))) py_kpu_fmap_obj_t; + +static void py_kpu_fmap_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_kpu_fmap_obj_t *fmap_obj = MP_OBJ_TO_PTR(self_in); + fmap_t* fmap = &(fmap_obj->fmap); + + mp_printf(print, + "{\"fmap\": \"data\"=0x%x, \"size\"=%d, \"index\": %d, \"w\": %d, \"h\": %d, \"ch\": %d, \"typecode\": %c}", + fmap->data, fmap->size, fmap->index, fmap->w, fmap->h, fmap->ch, fmap->typecode); + + return; +} + +static mp_int_t py_fmap_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) +{ + py_kpu_fmap_obj_t *self = self_in; + //if(flags == MP_BUFFER_READ) + bufinfo->buf = self->fmap.data; + bufinfo->len = self->fmap.size; + bufinfo->typecode = (char)(self->fmap.typecode); + return 0; +} + +static mp_obj_t py_fmap_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + py_kpu_fmap_obj_t *self = self_in; + if (value == MP_OBJ_NULL) { // delete + } else if (value == MP_OBJ_SENTINEL) { // load + switch ((char)(self->fmap.typecode)) { + case 'B': { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->fmap.size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + for (mp_uint_t i = 0; i < result->len; i++) { + uint8_t p = self->fmap.data[slice.start + i]; + result->items[i] = mp_obj_new_int(p); + } + return result; + } + mp_uint_t i = mp_get_index(self->base.type, self->fmap.size, index, false); + uint8_t p = self->fmap.data[i]; + return mp_obj_new_int(p); + } + break; + case 'f': { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->fmap.size/sizeof(float), index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + mp_obj_tuple_t *result = mp_obj_new_tuple(slice.stop - slice.start, NULL); + for (mp_uint_t i = 0; i < result->len; i++) { + float p = ((float*)(self->fmap.data))[slice.start + i]; + result->items[i] = mp_obj_new_float(p); + } + return result; + } + mp_uint_t i = mp_get_index(self->base.type, self->fmap.size/sizeof(float), index, false); + float p = ((float*)(self->fmap.data))[i]; + return mp_obj_new_float(p); + } + break; + default: { + mp_printf(&mp_plat_print, "typecode don't support read!\r\n"); + return MP_OBJ_NULL; + } + break; + } + } else { // store + switch ((char)(self->fmap.typecode)) { + case 'B': { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->fmap.size, index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + if (MP_OBJ_IS_TYPE(value, &mp_type_list)) { + mp_uint_t value_l_len; + mp_obj_t *value_l; + mp_obj_get_array(value, &value_l_len, &value_l); + PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image"); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + uint8_t p = mp_obj_get_int(value_l[i]); + self->fmap.data[slice.start + i] = p; + } + } else { + uint8_t p = mp_obj_get_int(value); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + self->fmap.data[slice.start + i] = p; + } + } + return mp_const_none; + } + mp_uint_t i = mp_get_index(self->base.type, self->fmap.size, index, false); + uint8_t p = mp_obj_get_int(value); + self->fmap.data[i] = p; + return mp_const_none; + } + break; + case 'f': { + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(self->fmap.size/sizeof(float), index, &slice)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "only slices with step=1 (aka None) are supported")); + } + if (MP_OBJ_IS_TYPE(value, &mp_type_list)) { + mp_uint_t value_l_len; + mp_obj_t *value_l; + mp_obj_get_array(value, &value_l_len, &value_l); + PY_ASSERT_TRUE_MSG(value_l_len == (slice.stop - slice.start), "cannot grow or shrink image"); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + float p = mp_obj_get_float(value_l[i]); + ((float*)(self->fmap.data))[slice.start + i] = p; + } + } else { + float p = mp_obj_get_float(value); + for (mp_uint_t i = 0; i < (slice.stop - slice.start); i++) { + ((float*)(self->fmap.data))[slice.start + i] = p; + } + } + return mp_const_none; + } + mp_uint_t i = mp_get_index(self->base.type, self->fmap.size/sizeof(float), index, false); + float p = mp_obj_get_float(value); + ((float*)(self->fmap.data))[i] = p; + return mp_const_none; + } + break; + default: { + mp_printf(&mp_plat_print, "typecode don't support write!\r\n"); + return MP_OBJ_NULL; + } + break; + + } + } + return MP_OBJ_NULL; // op not supported +} + +mp_obj_t py_kpu_fmap_size(mp_obj_t self_in) { return mp_obj_new_int(((py_kpu_fmap_obj_t *)self_in)->fmap.size); } +mp_obj_t py_kpu_fmap_index(mp_obj_t self_in) { return mp_obj_new_int(((py_kpu_fmap_obj_t *)self_in)->fmap.index); } +mp_obj_t py_kpu_fmap_w(mp_obj_t self_in) { return mp_obj_new_int(((py_kpu_fmap_obj_t *)self_in)->fmap.w); } +mp_obj_t py_kpu_fmap_h(mp_obj_t self_in) { return mp_obj_new_int(((py_kpu_fmap_obj_t *)self_in)->fmap.h); } +mp_obj_t py_kpu_fmap_ch(mp_obj_t self_in) { return mp_obj_new_int(((py_kpu_fmap_obj_t *)self_in)->fmap.ch); } +mp_obj_t py_kpu_fmap_typecode(mp_obj_t self_in) { return mp_obj_new_str((const char*)((py_kpu_fmap_obj_t *)self_in)->fmap.typecode,1); } + +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_fmap_size_obj, py_kpu_fmap_size); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_fmap_index_obj, py_kpu_fmap_index); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_fmap_w_obj, py_kpu_fmap_w); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_fmap_h_obj, py_kpu_fmap_h); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_fmap_ch_obj, py_kpu_fmap_ch); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_fmap_typecode_obj, py_kpu_fmap_typecode); + + + +static const mp_rom_map_elem_t py_kpu_fmap_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&py_kpu_fmap_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&py_kpu_fmap_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_kpu_fmap_w_obj) }, + { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_kpu_fmap_h_obj) }, + { MP_ROM_QSTR(MP_QSTR_ch), MP_ROM_PTR(&py_kpu_fmap_ch_obj) }, + { MP_ROM_QSTR(MP_QSTR_typecode), MP_ROM_PTR(&py_kpu_fmap_typecode_obj) } +}; + +static MP_DEFINE_CONST_DICT(py_kpu_fmap_dict, py_kpu_fmap_dict_table); + + +static const mp_obj_type_t py_kpu_fmap_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_kpu_fmap, + .print = py_kpu_fmap_print, + .buffer_p = { .get_buffer = py_fmap_get_buffer }, + .subscr = py_fmap_subscr, + .locals_dict = (mp_obj_t) &py_kpu_fmap_dict +}; + + +static int get_typecode_size(char type) +{ + int len; + switch(type) + { + case 'B': + len = 1; + case 'f': + len = 4; + default: + len = 1; + } + return len; +} + +STATIC mp_obj_t py_kpu_set_layers(mp_obj_t kpu_net_obj, mp_obj_t len_obj) +{ + py_kpu_net_obj_t *kpu_net = MP_OBJ_TO_PTR(kpu_net_obj); + int layers_length = mp_obj_get_int(len_obj); //how many layers you want calculate, set <=0 to calculate all layers + int max_length = mp_obj_get_int(kpu_net->max_layers); + // sipeed_kpu_err_t ret; + + if(layers_length > 0) + { //set layer count + if(layers_length <= max_length) + { + //mp_printf(&mp_plat_print, "set layers_length to %d\r\n", layers_length); + /* ret = */sipeed_kpu_model_set_output(kpu_net->kmodel_ctx, 0, layers_length); + } + else + { + mp_printf(&mp_plat_print, "err: set layers_length to %d, but max %d\r\n", layers_length, max_length); + return mp_const_false; + } + } else //calculate all layers + { + //mp_printf(&mp_plat_print, "set layers_length to %d\r\n", max_length); + sipeed_kpu_model_set_output(kpu_net->kmodel_ctx, 0, max_length); + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_kpu_set_layers_obj, py_kpu_set_layers); + +STATIC mp_obj_t py_kpu_forward(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { ARG_kpu_net, ARG_img, ARG_out_index, ARG_dma}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_kpu_net, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_img, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_out_index, MP_ARG_INT, {.u_int = 0x0} }, + { MP_QSTR_dma, MP_ARG_INT, {.u_int = -1} }, + }; //type + char char_temp[30]; + bool need_free_data_in = false; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(mp_obj_get_type(args[ARG_kpu_net].u_obj) == &py_kpu_net_obj_type) + { + sipeed_kpu_err_t ret; + py_kpu_net_obj_t *kpu_net = MP_OBJ_TO_PTR(args[ARG_kpu_net].u_obj); + sipeed_kpu_use_dma(args[ARG_dma].u_int); + + int kmodel_type=sipeed_kpu_model_get_type(kpu_net->kmodel_ctx); + uint8_t* data_in; + if(py_image_obj_is_image(args[ARG_img].u_obj)) + { + uint16_t w0=0, h0=0, ch0=0; + image_t *arg_img = py_image_cobj(args[ARG_img].u_obj); + data_in = arg_img->pix_ai; + // check V3 model input shape + if(abs(kmodel_type)==3 || abs(kmodel_type)==4){ + if(sipeed_kpu_model_get_input_shape(kpu_net->kmodel_ctx, &w0, &h0, &ch0) != SIPEED_KPU_ERR_NONE) + { + mp_raise_ValueError("[MAIXPY]kpu: first layer not conv layer!\r\n"); + return mp_const_none; + } + + } + if(check_img_format(arg_img, w0, h0, ch0, kmodel_type)) + { + mp_raise_ValueError("[MAIXPY]kpu: check img format err!\r\n"); + return mp_const_none; + } + } + else if(MP_OBJ_IS_TYPE(args[ARG_img].u_obj, &mp_type_list)) + { + mp_uint_t arg_list_len; + mp_obj_t *arg_list_obj; + mp_obj_get_array(args[ARG_img].u_obj, &arg_list_len, &arg_list_obj); + if (!arg_list_len) { + mp_raise_ValueError("[MAIXPY]kpu: check input list format err!\r\n"); + return mp_const_none; + } + + data_in = malloc(arg_list_len*sizeof(float)); + if(data_in == NULL) { + mp_raise_ValueError("[MAIXPY]kpu: alloc list mem err!\r\n"); + return mp_const_none; + } + need_free_data_in = true; + float* float_in = (float*)data_in; //理论上malloc申请的地址肯定是4字节对齐的 + for(mp_uint_t i = 0; i < arg_list_len; i++) { + float_in[i] = mp_obj_get_float(arg_list_obj[i]); + } + } + else + { + mp_raise_ValueError("input not support"); + } + int out_index = args[ARG_out_index].u_int; //which output you want, defaultly index 0 + /*************************************************************************************/ + g_ai_done_flag = 0; + ret = sipeed_kpu_model_run(kpu_net->kmodel_ctx, data_in, K210_DMA_CH_KPU, ai_done, NULL); + if(ret != SIPEED_KPU_ERR_NONE) + { + char* msg = get_kpu_err_str(ret); + mp_raise_msg(&mp_type_OSError, msg); + } + + while (!g_ai_done_flag){ + }; + g_ai_done_flag = 0; + if(need_free_data_in) { + free(data_in); + } + + /*************************************************************************************/ + if(abs(kmodel_type)==3) { + uint8_t* features; + size_t count; + kpu_model_layer_type_t layer_type; + ret = sipeed_kpu_model_get_layer_type(kpu_net->kmodel_ctx,sipeed_kpu_model_get_layer_num(kpu_net->kmodel_ctx)-1, &layer_type); + if(ret != SIPEED_KPU_ERR_NONE) + { + mp_raise_msg(&mp_type_OSError, "sipeed_kpu_model_get_layer_num err"); + } + ret = sipeed_kpu_get_output(kpu_net->kmodel_ctx, out_index, &features, &count); + if(ret != SIPEED_KPU_ERR_NONE) + { + mp_raise_msg(&mp_type_OSError, "sipeed_kpu_get_output err"); + } + py_kpu_fmap_obj_t *o = m_new_obj(py_kpu_fmap_obj_t); + o->base.type = &py_kpu_fmap_obj_type; + fmap_t* fmap = &(o->fmap); + fmap->data = features; + fmap->size = (uint32_t)count;// + 1; + fmap->index = sipeed_kpu_model_get_layer_num(kpu_net->kmodel_ctx)-1; + if(layer_type == KL_K210_CONV) + { //conv layer + + kpu_layer_argument_t* layer = sipeed_kpu_model_get_conv_layer(kpu_net->kmodel_ctx, sipeed_kpu_model_get_layer_num(kpu_net->kmodel_ctx)-1); + if(!layer) + { + snprintf(char_temp, sizeof(char_temp), "%d", SIPEED_KPU_ERR_GET_CONV_LAYER); + mp_raise_msg(&mp_type_OSError, char_temp); + } + fmap->w = layer->image_size.data.o_row_wid+1; + fmap->h = layer->image_size.data.o_col_high+1; + fmap->ch = layer->image_channel_num.data.o_ch_num+1; + fmap->typecode = 'B'; + } else + { //other layer, get original output + + fmap->h = 1; + fmap->ch = 1; + fmap->typecode = (uint16_t)sipeed_kpu_model_getdtype_from_type(layer_type); + fmap->w = (uint16_t)(count/get_typecode_size(fmap->typecode)); //TODO: auto cal w,h,c + } + return MP_OBJ_FROM_PTR(o); + //kpu_single_task_deinit + } else if(abs(kmodel_type)==4) { + uint8_t* features; + size_t count; + + ret = sipeed_kpu_get_output(kpu_net->kmodel_ctx, out_index, &features, &count); + if(ret != SIPEED_KPU_ERR_NONE) + { + mp_raise_msg(&mp_type_OSError, "sipeed_kpu_get_output err"); + } + py_kpu_fmap_obj_t *o = m_new_obj(py_kpu_fmap_obj_t); + o->base.type = &py_kpu_fmap_obj_type; + fmap_t* fmap = &(o->fmap); + fmap->data = features; + fmap->size = (uint32_t)count;// + 1; + fmap->index = sipeed_kpu_model_get_layer_num(kpu_net->kmodel_ctx)-1; + + ret = sipeed_kpu_get_outputs_shape(kpu_net->kmodel_ctx, out_index, &(fmap->w), &(fmap->h), &(fmap->ch)); + if(ret != SIPEED_KPU_ERR_NONE) + { + mp_raise_msg(&mp_type_OSError, "sipeed_kpu_get_outputs_shape err"); + } + fmap->typecode = (uint16_t)('f'); //默认float + return MP_OBJ_FROM_PTR(o); + //kpu_single_task_deinit + } + } + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_kpu_forward_obj, 1, py_kpu_forward); + + +STATIC mp_obj_t py_kpu_get_output(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + if((mp_obj_get_type(pos_args[0]) != &py_kpu_net_obj_type) || \ + (mp_obj_get_type(pos_args[1]) != &mp_type_int)) + { + mp_raise_ValueError("[MAIXPY]kpu: get_output arg format error: get_output(task, int idx)"); + return mp_const_false; + } + + py_kpu_net_obj_t *kpu_net = MP_OBJ_TO_PTR(pos_args[0]); + uint16_t out_index = mp_obj_get_int(pos_args[1]); + sipeed_kpu_err_t ret; + char char_temp[30]; + int kmodel_type=sipeed_kpu_model_get_type(kpu_net->kmodel_ctx); + + if(abs(kmodel_type)==3) { + uint8_t* features; + size_t count; + kpu_model_layer_type_t layer_type; + ret = sipeed_kpu_model_get_layer_type(kpu_net->kmodel_ctx,sipeed_kpu_model_get_layer_num(kpu_net->kmodel_ctx)-1, &layer_type); + if(ret != SIPEED_KPU_ERR_NONE) + { + snprintf(char_temp, sizeof(char_temp), "%d", ret); + mp_raise_msg(&mp_type_OSError, char_temp); + } + ret = sipeed_kpu_get_output(kpu_net->kmodel_ctx, out_index, &features, &count); + if(ret != SIPEED_KPU_ERR_NONE) + { + snprintf(char_temp, sizeof(char_temp), "%d", ret); + mp_raise_msg(&mp_type_OSError, char_temp); + } + py_kpu_fmap_obj_t *o = m_new_obj(py_kpu_fmap_obj_t); + o->base.type = &py_kpu_fmap_obj_type; + fmap_t* fmap = &(o->fmap); + fmap->data = features; + fmap->size = (uint32_t)count;// + 1; + fmap->index = sipeed_kpu_model_get_layer_num(kpu_net->kmodel_ctx)-1; + if(layer_type == KL_K210_CONV) + { //conv layer + kpu_layer_argument_t* layer = sipeed_kpu_model_get_conv_layer(kpu_net->kmodel_ctx, sipeed_kpu_model_get_layer_num(kpu_net->kmodel_ctx)-1); + if(!layer) + { + snprintf(char_temp, sizeof(char_temp), "%d", SIPEED_KPU_ERR_GET_CONV_LAYER); + mp_raise_msg(&mp_type_OSError, char_temp); + } + fmap->w = layer->image_size.data.o_row_wid+1; + fmap->h = layer->image_size.data.o_col_high+1; + fmap->ch = layer->image_channel_num.data.o_ch_num+1; + fmap->typecode = 'B'; + } else + { //other layer, get original output + fmap->h = 1; + fmap->ch = 1; + fmap->typecode = (uint16_t)sipeed_kpu_model_getdtype_from_type(layer_type); + fmap->w = (uint16_t)(count/get_typecode_size(fmap->typecode)); //TODO: auto cal w,h,c + } + return MP_OBJ_FROM_PTR(o); + //kpu_single_task_deinit + } else if(abs(kmodel_type)==4) { + uint8_t* features; + size_t count; + + ret = sipeed_kpu_get_output(kpu_net->kmodel_ctx, out_index, &features, &count); + if(ret != SIPEED_KPU_ERR_NONE) + { + mp_raise_msg(&mp_type_OSError, "get_output err"); + } + py_kpu_fmap_obj_t *o = m_new_obj(py_kpu_fmap_obj_t); + o->base.type = &py_kpu_fmap_obj_type; + fmap_t* fmap = &(o->fmap); + fmap->data = features; + fmap->size = (uint32_t)count;// + 1; + fmap->index = sipeed_kpu_model_get_layer_num(kpu_net->kmodel_ctx)-1; + + ret = sipeed_kpu_get_outputs_shape(kpu_net->kmodel_ctx, out_index, &(fmap->w), &(fmap->h), &(fmap->ch)); + if(ret != SIPEED_KPU_ERR_NONE) + { + mp_raise_msg(&mp_type_OSError, "get_outputs_shape err"); + } + fmap->typecode = (uint16_t)('f'); //默认float + return MP_OBJ_FROM_PTR(o); + //kpu_single_task_deinit + } + + return mp_const_none; +} + + + + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_kpu_get_output_obj, 2, py_kpu_get_output); + +//gen ch channel fmap, in Image_t format +/*typedef struct image { + int w; + int h; + int bpp; + union { + uint8_t *pixels; + uint8_t *data; + }; + uint8_t *pix_ai; //for MAIX AI speed up +} __attribute__((aligned(8)))image_t; +*/ + +STATIC mp_obj_t py_kpu_fmap(mp_obj_t fmap_obj, mp_obj_t ch_obj) +{ + int ch = mp_obj_get_int(ch_obj); + fmap_t* fmap = &(((py_kpu_fmap_obj_t*)fmap_obj)->fmap); + if(ch<0 || ch>= (fmap->ch)) + { + char str_ret[40]; + sprintf(str_ret,"[MAIXPY]kpu: ch err,input 0~%d\r\n", fmap->ch); + mp_raise_ValueError(str_ret); + return mp_const_none; + } + if(fmap->typecode != 'B') + { + char str_ret[50]; + snprintf(str_ret, sizeof(str_ret), "[MAIXPY]kpu: can't convet float fmap yet\r\n"); + mp_raise_ValueError(str_ret); + return mp_const_none; + } + mp_obj_t image = py_image(fmap->w, fmap->h, IMAGE_BPP_GRAYSCALE, fmap->data + ((fmap->w)*(fmap->h))*ch); + return image; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_kpu_fmap_obj, py_kpu_fmap); + +STATIC mp_obj_t py_kpu_fmap_free(mp_obj_t fmap_obj) +{ + //fmap_t* fmap = &(((py_kpu_fmap_obj_t*)fmap_obj)->fmap); + //free(fmap->data); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_fmap_free_obj, py_kpu_fmap_free); + + + + +typedef struct py_kpu_class_netinfo_find_obj { + mp_obj_base_t base; + + mp_obj_t index,type,wi,hi,wo,ho,chi,cho,dw,kernel_type,pool_type,para_size; +} __attribute__((aligned(8))) py_kpu_class_netinfo_find_obj_t; + +static void py_kpu_class_netinfo_find_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) +{ + py_kpu_class_netinfo_find_obj_t *self = self_in; + mp_printf(print, + "{\"index\":%d, \"type\":%s, \"wi\":%d, \"hi\":%d, \"wo\":%d, \"ho\":%d, \"chi\":%d, \"cho\":%d, \"dw\":%d, \"kernel_type\":%d, \"pool_type\":%d, \"para_size\":%d}", + mp_obj_get_int(self->index), + sipeed_kpu_model_getname_from_type(mp_obj_get_int(self->type)), + mp_obj_get_int(self->wi), + mp_obj_get_int(self->hi), + mp_obj_get_int(self->wo), + mp_obj_get_int(self->ho), + mp_obj_get_int(self->chi), + mp_obj_get_int(self->cho), + mp_obj_get_int(self->dw), + mp_obj_get_int(self->kernel_type), + mp_obj_get_int(self->pool_type), + mp_obj_get_int(self->para_size)); +} + +mp_obj_t py_kpu_class_netinfo_find_index (mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->index; } +mp_obj_t py_kpu_class_netinfo_find__type (mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->type; } +mp_obj_t py_kpu_class_netinfo_find_wi(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->wi; } +mp_obj_t py_kpu_class_netinfo_find_hi(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->hi; } +mp_obj_t py_kpu_class_netinfo_find_wo(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->wo; } +mp_obj_t py_kpu_class_netinfo_find_ho(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->ho; } +mp_obj_t py_kpu_class_netinfo_find_chi(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->chi; } +mp_obj_t py_kpu_class_netinfo_find_cho(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->cho; } +mp_obj_t py_kpu_class_netinfo_find_dw(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->dw; } +mp_obj_t py_kpu_class_netinfo_find_kernel_type(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->kernel_type; } +mp_obj_t py_kpu_class_netinfo_find_pool_type(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->pool_type; } +mp_obj_t py_kpu_class_netinfo_find_para_size(mp_obj_t self_in) { return ((py_kpu_class_netinfo_find_obj_t *)self_in)->para_size; } + +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_index_obj, py_kpu_class_netinfo_find_index); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find__type_obj, py_kpu_class_netinfo_find__type); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_wi_obj, py_kpu_class_netinfo_find_wi); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_hi_obj, py_kpu_class_netinfo_find_hi); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_wo_obj, py_kpu_class_netinfo_find_wo); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_ho_obj, py_kpu_class_netinfo_find_ho); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_chi_obj, py_kpu_class_netinfo_find_chi); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_cho_obj, py_kpu_class_netinfo_find_cho); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_dw_obj, py_kpu_class_netinfo_find_dw); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_kernel_type_obj, py_kpu_class_netinfo_find_kernel_type); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_pool_type_obj, py_kpu_class_netinfo_find_pool_type); +static MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_class_netinfo_find_para_size_obj, py_kpu_class_netinfo_find_para_size); + +static const mp_rom_map_elem_t py_kpu_class_netinfo_find_type_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&py_kpu_class_netinfo_find_index_obj) }, + { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&py_kpu_class_netinfo_find__type_obj) }, + { MP_ROM_QSTR(MP_QSTR_wi), MP_ROM_PTR(&py_kpu_class_netinfo_find_wi_obj) }, + { MP_ROM_QSTR(MP_QSTR_hi), MP_ROM_PTR(&py_kpu_class_netinfo_find_hi_obj) }, + { MP_ROM_QSTR(MP_QSTR_wo), MP_ROM_PTR(&py_kpu_class_netinfo_find_wo_obj) }, + { MP_ROM_QSTR(MP_QSTR_ho), MP_ROM_PTR(&py_kpu_class_netinfo_find_ho_obj) }, + { MP_ROM_QSTR(MP_QSTR_chi), MP_ROM_PTR(&py_kpu_class_netinfo_find_chi_obj) }, + { MP_ROM_QSTR(MP_QSTR_cho), MP_ROM_PTR(&py_kpu_class_netinfo_find_cho_obj) }, + { MP_ROM_QSTR(MP_QSTR_dw), MP_ROM_PTR(&py_kpu_class_netinfo_find_dw_obj) }, + { MP_ROM_QSTR(MP_QSTR_kernel_type), MP_ROM_PTR(&py_kpu_class_netinfo_find_kernel_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_pool_type), MP_ROM_PTR(&py_kpu_class_netinfo_find_pool_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_para_size), MP_ROM_PTR(&py_kpu_class_netinfo_find_para_size_obj) }, +}; + +static MP_DEFINE_CONST_DICT(py_kpu_class_netinfo_find_type_locals_dict, py_kpu_class_netinfo_find_type_locals_dict_table); + +static const mp_obj_type_t py_kpu_class_netinfo_find_type = { + { &mp_type_type }, + .name = MP_QSTR_kpu_netinfo_find, + .print = py_kpu_class_netinfo_find_print, + // .subscr = py_kpu_class_subscr, + .locals_dict = (mp_obj_t) &py_kpu_class_netinfo_find_type_locals_dict +}; + + +STATIC mp_obj_t py_kpu_netinfo(mp_obj_t py_kpu_net_obj) +{ + py_kpu_net_obj_t *kpu_net = MP_OBJ_TO_PTR(py_kpu_net_obj); + + int len = sipeed_kpu_model_get_layer_num(kpu_net->kmodel_ctx); + if(len <= 0) + { + mp_raise_ValueError("get layer num error!"); + } + kpu_layer_argument_t *layer; + list_t out; + list_init(&out, sizeof(py_kpu_netinfo_list_data_t)); + + sipeed_kpu_model_print_layer_info(kpu_net->kmodel_ctx); + for (uint8_t index = 0; index < len; index++) + { + py_kpu_netinfo_list_data_t data; + sipeed_kpu_err_t ret; + data.index = index; + ret = sipeed_kpu_model_get_layer_type(kpu_net->kmodel_ctx, index, (kpu_model_layer_type_t*)&data.type); + if(ret != SIPEED_KPU_ERR_NONE) + mp_raise_OSError(ret); + layer = sipeed_kpu_model_get_conv_layer(kpu_net->kmodel_ctx, index); + if(layer != NULL) //conv layer + { + data.wi = layer->image_size.data.i_row_wid+1; + data.hi = layer->image_size.data.i_col_high+1; + data.wo = layer->image_size.data.o_row_wid+1; + data.ho = layer->image_size.data.o_col_high+1; + data.chi = layer->image_channel_num.data.i_ch_num+1; + data.cho = layer->image_channel_num.data.o_ch_num+1; + data.dw = layer->interrupt_enabe.data.depth_wise_layer; + data.kernel_type = layer->kernel_pool_type_cfg.data.kernel_type; + data.pool_type = layer->kernel_pool_type_cfg.data.pool_type; + data.para_size = layer->kernel_load_cfg.data.para_size; + } else{ + data.wi = 0; + data.hi = 0; + data.wo = 0; + data.ho = 0; + data.chi = 0; + data.cho = 0; + data.dw = 0; + data.kernel_type = 0; + data.pool_type = 0; + data.para_size = sipeed_kpu_model_get_layer_size(kpu_net->kmodel_ctx, index); + } + list_push_back(&out, &data); + } + + mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); + + for (size_t i = 0; list_size(&out); i++) + { + py_kpu_netinfo_list_data_t lnk_data; + list_pop_front(&out, &lnk_data); + + py_kpu_class_netinfo_find_obj_t *o = m_new_obj(py_kpu_class_netinfo_find_obj_t); + + o->base.type = &py_kpu_class_netinfo_find_type; + + o->index = mp_obj_new_int(lnk_data.index); + o->type = mp_obj_new_int(lnk_data.type); + o->wi = mp_obj_new_int(lnk_data.wi); + o->hi = mp_obj_new_int(lnk_data.hi); + o->wo = mp_obj_new_int(lnk_data.wo); + o->ho = mp_obj_new_int(lnk_data.ho); + o->chi = mp_obj_new_int(lnk_data.chi); + o->cho= mp_obj_new_int(lnk_data.cho); + o->dw = mp_obj_new_int(lnk_data.dw); + o->kernel_type = mp_obj_new_int(lnk_data.kernel_type); + o->pool_type = mp_obj_new_int(lnk_data.pool_type); + o->para_size = mp_obj_new_int(lnk_data.para_size); + + objects_list->items[i] = o; + } + + return objects_list; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_kpu_netinfo_obj, py_kpu_netinfo); + + +STATIC mp_obj_t py_kpu_memtest(void) +{ + int mem0,mem1,mem; + char* ptr; + mem0=0; + mem1=0x800000; + while(mem1-mem0>0x400){ + for(mem=(mem0+mem1)/2; memFACE_FEATURE_DIM_MAX) + { + mp_raise_ValueError("feature dim <=200\r\n"); + } + for(int i=0; imodel = m_new(kpu_model_info_t, 1); + self->kpu_model = model; + self->model->kmodel_ctx = model->kmodel_ctx; + self->model->max_layers = model->max_layers; + self->model->model_addr = model->model_addr; + if(model->model_path == mp_const_none) + self->model->model_path = NULL; + else + self->model->model_path = mp_obj_str_get_str(model->model_path); + self->model->model_size = model->model_size; + int ret = maix_kpu_classifier_init(&self->obj, self->model, (int)class_num, (int)sample_num, false, 0, feature_length); + if(ret < 0) + mp_raise_OSError(-ret); +} + +STATIC int add_class_img(maix_kpu_classifier_t* self, image_t* img, int idx){ + int ret = maix_kpu_classifier_add_class_img(self->obj, img, idx); + if(ret < 0) + mp_raise_OSError(-ret); + return ret; +} + +STATIC int rm_class_img(maix_kpu_classifier_t* self){ + int ret = maix_kpu_classifier_rm_class_img(self->obj); + if(ret < 0) + mp_raise_OSError(-ret); + return ret; +} + +STATIC int add_sample_img(maix_kpu_classifier_t* self, image_t* img){ + int ret = maix_kpu_classifier_add_sample_img(self->obj, img); + if(ret < 0) + mp_raise_OSError(-ret); + return ret; +} + +STATIC int rm_sample_img(maix_kpu_classifier_t* self){ + int ret = maix_kpu_classifier_rm_sample_img(self->obj); + if(ret < 0) + mp_raise_OSError(-ret); + return ret; +} + +STATIC void clear_obj(maix_kpu_classifier_t* self){ + int ret = maix_kpu_classifier_del(&self->obj); + if(ret < 0) + mp_raise_OSError(-ret); +} + +STATIC void train(maix_kpu_classifier_t* self){ + int ret = maix_kpu_classifier_train(self->obj); + if(ret < 0) + mp_raise_OSError(-ret); +} + +STATIC int predict(maix_kpu_classifier_t* self, image_t* img, float* min_distance){ + int ret = maix_kpu_classifier_predict(self->obj, img, min_distance, NULL, NULL, NULL, NULL); + if(ret < 0) + mp_raise_OSError(-ret); + return ret; +} + + +STATIC void save_trained_model(maix_kpu_classifier_t* self, const char* path){ + int ret = maix_kpu_classifier_save(self->obj, path); + if(ret < 0) + mp_raise_OSError(-ret); +} + +STATIC void load_trained_model(maix_kpu_classifier_t* self, const char* path, py_kpu_net_obj_t* model, int* class_num, int* sample_num, int feature_length){ + self->model = m_new(kpu_model_info_t, 1); + self->kpu_model = model; + self->model->kmodel_ctx = model->kmodel_ctx; + self->model->max_layers = model->max_layers; + self->model->model_addr = model->model_addr; + if(model->model_path == mp_const_none) + self->model->model_path = NULL; + else + self->model->model_path = mp_obj_str_get_str(model->model_path); + self->model->model_size = model->model_size; + int ret = maix_kpu_classifier_load(&self->obj, path, self->model, class_num, sample_num, feature_length); + if(ret < 0) + mp_raise_OSError(-ret); +} + +mp_obj_t maix_kpu_classifier_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + maix_kpu_classifier_t* self = m_new_obj_with_finaliser(maix_kpu_classifier_t); + self->base.type = &Maix_kpu_classifier_type; + self->obj = NULL; + if(n_args<3) + { + mp_raise_ValueError("model, class num, sample num"); + } + if(mp_obj_get_type(args[0]) != &py_kpu_net_obj_type){ + mp_raise_ValueError("model"); + } + int feature_length = 0; + if(n_kw > 0) + { + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + feature_length = py_helper_keyword_int(n_args, args, 3, &kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fea_len), 0); + } + sipeed_kpu_use_dma(1); + init_obj(self, (py_kpu_net_obj_t*)args[0], mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), feature_length); + return (mp_obj_t)self; +} + +mp_obj_t classifier_add_class_img(size_t n_args, const mp_obj_t *args){ + if(mp_obj_get_type(args[0]) != &Maix_kpu_classifier_type){ + mp_raise_ValueError("must be obj"); + } + maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)args[0]; + image_t* img = py_image_cobj(args[1]); + int idx = -1; + if(n_args > 2) + idx = mp_obj_get_int(args[2]); + int ret_index = add_class_img(self, img, idx); + return mp_obj_new_int(ret_index); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(classifier_add_class_img_obj, 2, 3, classifier_add_class_img); + + +mp_obj_t classifier_rm_class_img(mp_obj_t self_in){ + if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){ + mp_raise_ValueError("must be obj"); + } + maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in; + int ret_index = rm_class_img(self); + return mp_obj_new_int(ret_index); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(classifier_rm_class_img_obj, classifier_rm_class_img); + + +mp_obj_t classifier_add_sample_img(mp_obj_t self_in, mp_obj_t img_in){ + if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){ + mp_raise_ValueError("must be obj"); + } + maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in; + image_t* img = py_image_cobj(img_in); + int ret = add_sample_img(self, img); + return mp_obj_new_int(ret); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(classifier_add_sample_img_obj, classifier_add_sample_img); + +mp_obj_t classifier_rm_sample_img(mp_obj_t self_in){ + if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){ + mp_raise_ValueError("must be obj"); + } + maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in; + int ret_index = rm_sample_img(self); + return mp_obj_new_int(ret_index); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(classifier_rm_sample_img_obj, classifier_rm_sample_img); + +mp_obj_t classifier_del(mp_obj_t self_in){ + if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){ + mp_raise_ValueError("must be obj"); + } + mp_printf(&mp_plat_print, "classifier __del__\r\n"); + maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in; + clear_obj(self); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(classifier_del_obj, classifier_del); + +mp_obj_t classifier_train(mp_obj_t self_in){ + if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){ + mp_raise_ValueError("must be obj"); + } + maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in; + train(self); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(classifier_train_obj, classifier_train); + +mp_obj_t classifier_predict(mp_obj_t self_in, mp_obj_t img_in){ + if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){ + mp_raise_ValueError("must be obj"); + } + maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in; + image_t* img = py_image_cobj(img_in); + float min_distance; + int ret_index = predict(self, img, &min_distance); + mp_obj_t t[2]; + t[0] = mp_obj_new_int(ret_index); + t[1] = mp_obj_new_float(min_distance); + return mp_obj_new_tuple(2,t); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(classifier_predict_obj, classifier_predict); + + +mp_obj_t classifier_save(mp_obj_t self_in, mp_obj_t path_in){ + if(mp_obj_get_type(self_in) != &Maix_kpu_classifier_type){ + mp_raise_ValueError("must be obj"); + } + maix_kpu_classifier_t* self = (maix_kpu_classifier_t*)self_in; + const char* path = mp_obj_str_get_str(path_in); + save_trained_model(self, path); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(classifier_save_obj, classifier_save); + +/** + * @param model_in kpu model object + * @param path_in saved classifier model path + * @param class_num init object classnum, if not set, the same as saved model's + * @param sample_num ... + */ +mp_obj_t classifier_load(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args){ + mp_obj_t model_in = args[0]; + mp_obj_t path_in = args[1]; + if(mp_obj_get_type(model_in) == &Maix_kpu_classifier_type){ + mp_raise_ValueError("must be class"); + } + if(mp_obj_get_type(model_in) != &py_kpu_net_obj_type){ + mp_raise_ValueError("must be model"); + } + if(mp_obj_get_type(path_in) != &mp_type_str){ + mp_raise_ValueError("path err"); + } + maix_kpu_classifier_t* self = m_new_obj_with_finaliser(maix_kpu_classifier_t); + self->base.type = &Maix_kpu_classifier_type; + self->obj = NULL; + int class_num = 0, sample_num = 0; + if(n_args > 2) + { + class_num = mp_obj_get_int(args[2]); + } + if(n_args > 3) + { + sample_num = mp_obj_get_int(args[3]); + } + int feature_length = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fea_len), 0); + load_trained_model(self, mp_obj_str_get_str(path_in), (py_kpu_net_obj_t*)model_in, &class_num, &sample_num, feature_length); + mp_obj_t* items[3] = {(mp_obj_t)self, mp_obj_new_int(class_num), mp_obj_new_int(sample_num)}; + return mp_obj_new_tuple(3, items); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(classifier_load_obj, 2, classifier_load); + + +STATIC const mp_map_elem_t locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_classifier) }, + { MP_ROM_QSTR(MP_QSTR_add_class_img), (mp_obj_t)(&classifier_add_class_img_obj) }, + { MP_ROM_QSTR(MP_QSTR_add_sample_img), (mp_obj_t)(&classifier_add_sample_img_obj) }, + { MP_ROM_QSTR(MP_QSTR_train), (mp_obj_t)(&classifier_train_obj) }, + { MP_ROM_QSTR(MP_QSTR_predict), (mp_obj_t)(&classifier_predict_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), (mp_obj_t)(&classifier_del_obj) }, + { MP_ROM_QSTR(MP_QSTR_rm_class_img), (mp_obj_t)(&classifier_rm_class_img_obj) }, + { MP_ROM_QSTR(MP_QSTR_rm_sample_img), (mp_obj_t)(&classifier_rm_sample_img_obj) }, + { MP_ROM_QSTR(MP_QSTR_save), (mp_obj_t)(&classifier_save_obj) }, + { MP_ROM_QSTR(MP_QSTR_load), (mp_obj_t)(&classifier_load_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); + +const mp_obj_type_t Maix_kpu_classifier_type = { + .base = { &mp_type_type }, + .name = MP_QSTR_classifier, + .make_new = maix_kpu_classifier_make_new, + .locals_dict = (mp_obj_dict_t*)&locals_dict +}; + diff --git a/src/声源定位代码/mic-code/Maix/Maix_mic_array.c b/src/声源定位代码/mic-code/Maix/Maix_mic_array.c new file mode 100644 index 0000000..12ac21b --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/Maix_mic_array.c @@ -0,0 +1,286 @@ +#include +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/objarray.h" +#include "py/binary.h" +#include "py_assert.h" +#include "mperrno.h" +#include "mphalport.h" +#include "modMaix.h" +#include "imlib.h" + +#include "sleep.h" +#include "lcd.h" +#include "sysctl.h" +#include "fpioa.h" +#include "lib_mic.h" +#include "sipeed_sk9822.h" +#include "py_image.h" + +#define PLL2_OUTPUT_FREQ 45158400UL + +STATIC uint16_t colormap_parula[64] = { + 0x3935, 0x4156, 0x4178, 0x4199, 0x41ba, 0x41db, 0x421c, 0x423d, + 0x4a7e, 0x429e, 0x42df, 0x42ff, 0x431f, 0x435f, 0x3b7f, 0x3bbf, + 0x33ff, 0x2c1f, 0x2c3e, 0x2c7e, 0x2c9d, 0x24bd, 0x24dd, 0x251c, + 0x1d3c, 0x1d5c, 0x1d7b, 0x159a, 0x05ba, 0x05d9, 0x05d8, 0x0df7, + 0x1e16, 0x2615, 0x2e34, 0x3634, 0x3652, 0x3e51, 0x4e70, 0x566f, + 0x666d, 0x766c, 0x866b, 0x8e49, 0x9e48, 0xae27, 0xbe26, 0xc605, + 0xd5e4, 0xdde5, 0xe5c5, 0xf5c6, 0xfdc7, 0xfde7, 0xfe27, 0xfe46, + 0xfe86, 0xfea5, 0xf6e5, 0xf704, 0xf744, 0xf764, 0xffa3, 0xffc2}; + +STATIC uint16_t colormap_parula_rect[64][14 * 14] __attribute__((aligned(128))); + +STATIC int init_colormap_parula_rect() +{ + for (uint32_t i = 0; i < 64; i++) + { + for (uint32_t j = 0; j < 14 * 14; j++) + { + colormap_parula_rect[i][j] = colormap_parula[i]; + } + } + return 0; +} +STATIC uint8_t lib_init_flag = 0; + +STATIC volatile uint8_t mic_done = 0; +STATIC uint8_t thermal_map_data[256]; + +STATIC void lib_mic_cb(void) +{ + mic_done = 1; +} + +STATIC mp_obj_t Maix_mic_array_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + enum { + ARG_i2s_d0, + ARG_i2s_d1, + ARG_i2s_d2, + ARG_i2s_d3, + ARG_i2s_ws, + ARG_i2s_sclk, + + ARG_sk9822_dat, + ARG_sk9822_clk, + }; + + // sysctl_pll_set_freq(SYSCTL_PLL2, PLL2_OUTPUT_FREQ); //如果使用i2s,必须设置PLL2 + static const mp_arg_t allowed_args[]={ + {MP_QSTR_i2s_d0, MP_ARG_INT, {.u_int = 23}}, + {MP_QSTR_i2s_d1, MP_ARG_INT, {.u_int = 22}}, + {MP_QSTR_i2s_d2, MP_ARG_INT, {.u_int = 21}}, + {MP_QSTR_i2s_d3, MP_ARG_INT, {.u_int = 20}}, + {MP_QSTR_i2s_ws, MP_ARG_INT, {.u_int = 19}}, + {MP_QSTR_i2s_sclk, MP_ARG_INT, {.u_int = 18}}, + + {MP_QSTR_sk9822_dat, MP_ARG_INT, {.u_int = 24}}, + {MP_QSTR_sk9822_clk, MP_ARG_INT, {.u_int = 25}}, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + //evil code + fpioa_set_function(args[ARG_i2s_d0].u_int, FUNC_I2S0_IN_D0); + fpioa_set_function(args[ARG_i2s_d1].u_int, FUNC_I2S0_IN_D1); + fpioa_set_function(args[ARG_i2s_d2].u_int, FUNC_I2S0_IN_D2); + fpioa_set_function(args[ARG_i2s_d3].u_int, FUNC_I2S0_IN_D3); + fpioa_set_function(args[ARG_i2s_ws].u_int, FUNC_I2S0_WS); + fpioa_set_function(args[ARG_i2s_sclk].u_int, FUNC_I2S0_SCLK); + //TODO: optimize Soft SPI + fpioa_set_function(args[ARG_sk9822_dat].u_int, FUNC_GPIOHS0 + SK9822_DAT_GPIONUM); + fpioa_set_function(args[ARG_sk9822_clk].u_int, FUNC_GPIOHS0 + SK9822_CLK_GPIONUM); + + // init_colormap_parula_rect(); + sipeed_init_mic_array_led(); + + int ret = lib_mic_init(DMAC_CHANNEL4, lib_mic_cb, thermal_map_data); + if(ret != 0) + { + char tmp[64]; + sprintf(tmp,"lib_mic init error with %d",ret); + mp_raise_ValueError((const char*)tmp); + return mp_const_false; + } + lib_init_flag = 1; + // sysctl_enable_irq(); + return mp_const_true; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(Maix_mic_array_init_obj, 0, Maix_mic_array_init); + +STATIC mp_obj_t Maix_mic_array_deinit(void) +{ + if(lib_init_flag) + { + lib_mic_deinit(); + lib_init_flag = 0; + } + return mp_const_true; +} + +MP_DEFINE_CONST_FUN_OBJ_0(Maix_mic_array_deinit_obj, Maix_mic_array_deinit); + +STATIC mp_obj_t Maix_mic_array_get_map(void) +{ + image_t out; + + out.w = 16; + out.h = 16; + out.bpp = IMAGE_BPP_GRAYSCALE; + out.data = xalloc(256); + mic_done = 0; + + volatile uint8_t retry = 100; + + while(mic_done == 0) + { + retry--; + msleep(1); + } + + if(mic_done == 0 && retry == 0) + { + xfree(out.data); + mp_raise_OSError(MP_ETIMEDOUT); + return mp_const_false; + } + + memcpy(out.data, thermal_map_data, 256); + + return py_image_from_struct(&out); +} + +MP_DEFINE_CONST_FUN_OBJ_0(Maix_mic_array_get_map_obj, Maix_mic_array_get_map); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +STATIC uint8_t voice_strength_len[12] = {14, 20, 14, 14, 20, 14, 14, 20, 14, 14, 20, 14}; + +//voice strength, to calc direction +STATIC uint8_t voice_strength[12][32] = { + {197, 198, 199, 213, 214, 215, 228, 229, 230, 231, 244, 245, 246, 247}, //14 + {178, 179, 192, 193, 194, 195, 196, 208, 209, 210, 211, 212, 224, 225, 226, 227, 240, 241, 242, 243}, //20 + {128, 129, 130, 131, 144, 145, 146, 147, 160, 161, 162, 163, 176, 177}, + {64, 65, 80, 81, 82, 83, 96, 97, 98, 99, 112, 113, 114, 115}, + {0, 1, 2, 3, 16, 17, 18, 19, 32, 33, 34, 35, 36, 48, 49, 50, 51, 52, 66, 67}, + {4, 5, 6, 7, 20, 21, 22, 23, 37, 38, 39, 53, 54, 55}, + {8, 9, 10, 11, 24, 25, 26, 27, 40, 41, 42, 56, 57, 58}, + {12, 13, 14, 15, 28, 29, 30, 31, 43, 44, 45, 46, 47, 59, 60, 61, 62, 63, 76, 77}, + {78, 79, 92, 93, 94, 95, 108, 109, 110, 111, 124, 125, 126, 127}, + {140, 141, 142, 143, 156, 157, 158, 159, 173, 172, 174, 175, 190, 191}, + {188, 189, 203, 204, 205, 206, 207, 219, 220, 221, 222, 223, 236, 237, 238, 239, 252, 253, 254, 255}, + {200, 201, 202, 216, 217, 218, 232, 233, 234, 235, 248, 249, 250, 251}, +}; + +STATIC void calc_voice_strength(uint8_t *voice_data, uint8_t *led_brightness) +{ + uint32_t tmp_sum[12] = {0}; + uint8_t i, index, tmp; + + for (index = 0; index < 12; index++) + { + tmp_sum[index] = 0; + for (i = 0; i < voice_strength_len[index]; i++) + { + tmp_sum[index] += voice_data[voice_strength[index][i]]; + } + tmp = (uint8_t)tmp_sum[index] / voice_strength_len[index]; + led_brightness[index] = tmp > 15 ? 15 : tmp; + } +} + +STATIC mp_obj_t Maix_mic_array_get_dir(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + uint8_t led_brightness[12]={0}; + + image_t *arg_img = py_image_cobj(pos_args[0]); + PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + + if(arg_img->w!=16 || arg_img->h!=16 || arg_img->bpp!=IMAGE_BPP_GRAYSCALE) + { + mp_raise_ValueError("image type error, only support 16*16 grayscale image"); + return mp_const_false; + } + + calc_voice_strength(arg_img->data, led_brightness); + + mp_obj_t *tuple, *tmp; + + tmp = (mp_obj_t *)malloc(12 * sizeof(mp_obj_t)); + + for (uint8_t index = 0; index < 12; index++) + tmp[index] = mp_obj_new_int(led_brightness[index]); + + tuple = mp_obj_new_tuple(12, tmp); + + free(tmp); + + return tuple; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(Maix_mic_array_get_dir_obj, 1, Maix_mic_array_get_dir); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +STATIC mp_obj_t Maix_mic_array_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + int index, brightness[12] = {0}, led_color[12] = {0}, color[3] = {0}; + + mp_obj_t *items; + mp_obj_get_array_fixed_n(pos_args[0], 12, &items); + + for(index= 0; index < 12; index++) + brightness[index] = mp_obj_get_int(items[index]); + + mp_obj_get_array_fixed_n(pos_args[1], 3, &items); + for(index = 0; index < 3; index++) + color[index] = mp_obj_get_int(items[index]); + + //rgb + uint32_t set_color = (color[2] << 16) | (color[1] << 8) | (color[0]); + + for (index = 0; index < 12; index++) + { + led_color[index] = (brightness[index] / 2) > 1 ? (((0xe0 | (brightness[index] * 2)) << 24) | set_color) : 0xe0000000; + } + +//FIXME close irq? +sysctl_disable_irq(); + sk9822_start_frame(); + for (index = 0; index < 12; index++) + { + sk9822_send_data(led_color[index]); + } + sk9822_stop_frame(); + +sysctl_enable_irq(); + + return mp_const_true; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(Maix_mic_array_set_led_obj, 2, Maix_mic_array_set_led); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +STATIC const mp_rom_map_elem_t Maix_mic_array_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&Maix_mic_array_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&Maix_mic_array_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_dir), MP_ROM_PTR(&Maix_mic_array_get_dir_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&Maix_mic_array_set_led_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_map), MP_ROM_PTR(&Maix_mic_array_get_map_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(Maix_mic_array_dict, Maix_mic_array_locals_dict_table); + +const mp_obj_type_t Maix_mic_array_type = { + { &mp_type_type }, + .name = MP_QSTR_MIC_ARRAY, + .locals_dict = (mp_obj_dict_t*)&Maix_mic_array_dict, +}; diff --git a/src/声源定位代码/mic-code/Maix/Maix_utils.c b/src/声源定位代码/mic-code/Maix/Maix_utils.c new file mode 100644 index 0000000..bc0cf2e --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/Maix_utils.c @@ -0,0 +1,86 @@ +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "mpconfigboard.h" +#include "stdint.h" +#include "stdbool.h" +#include "stdlib.h" +#include "sipeed_mem.h" +#include "w25qxx.h" + +STATIC mp_obj_t py_gc_heap_size(size_t n_args, const mp_obj_t *args) { + config_data_t config; + load_config_from_spiffs(&config); + if(n_args == 0) + return mp_obj_new_int(config.gc_heap_size); + else if(n_args != 1) + mp_raise_OSError(MP_EINVAL); + config.gc_heap_size = mp_obj_get_int(args[0]); + if( !save_config_to_spiffs(&config) ) + mp_raise_OSError(MP_EIO); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_gc_heap_size_obj, 0, 1, py_gc_heap_size); + +// sys_free(): return the number of bytes of available sys heap RAM +STATIC mp_obj_t py_heap_free(void) { + return MP_OBJ_NEW_SMALL_INT(get_free_heap_size2()); +} +MP_DEFINE_CONST_FUN_OBJ_0(py_heap_free_obj, py_heap_free); + +// STATIC mp_obj_t py_malloc(mp_obj_t arg) { +// void malloc_stats(void); +// malloc_stats(); +// void* p = malloc(mp_obj_get_int(arg)); +// return mp_obj_new_int((mp_int_t)p); +// } + +// STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_malloc_obj, py_malloc); + +// STATIC mp_obj_t py_free(mp_obj_t arg) { +// free(mp_obj_get_int(arg)); +// return mp_const_none; +// } + +// STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_free_obj, py_free); + + +// STATIC mp_obj_t py_flash_write(mp_obj_t addr, mp_obj_t data_in) { +// mp_buffer_info_t bufinfo; +// mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); +// w25qxx_status_t status = w25qxx_write_data_dma(mp_obj_get_int(addr), bufinfo.buf, (uint32_t)bufinfo.len); +// return mp_obj_new_int(status); // (status != W25QXX_OK) +// } + +// STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_flash_write_obj, py_flash_write); + +STATIC mp_obj_t py_flash_read(mp_obj_t addr, mp_obj_t len_in) { + size_t length = mp_obj_get_int(len_in); + byte* data = m_new(byte, length); + w25qxx_status_t status = w25qxx_read_data_dma(mp_obj_get_int(addr), data, (uint32_t)length, W25QXX_QUAD_FAST); + if(status != W25QXX_OK) + { + mp_raise_OSError(MP_EIO); + } + return mp_obj_new_bytes(data, length); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_flash_read_obj, py_flash_read); + +static const mp_map_elem_t locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utils) }, + { MP_ROM_QSTR(MP_QSTR_gc_heap_size), (mp_obj_t)(&py_gc_heap_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_heap_free), (mp_obj_t)(&py_heap_free_obj) }, + // { MP_ROM_QSTR(MP_QSTR_malloc), (mp_obj_t)(&py_malloc_obj) }, + // { MP_ROM_QSTR(MP_QSTR_free), (mp_obj_t)(&py_free_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_read), (mp_obj_t)(&py_flash_read_obj) }, + // { MP_ROM_QSTR(MP_QSTR_flash_write), (mp_obj_t)(&py_flash_write_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); + +const mp_obj_type_t Maix_utils_type = { + .base = { &mp_type_type }, + .name = MP_QSTR_utils, + .locals_dict = (mp_obj_dict_t*)&locals_dict +}; \ No newline at end of file diff --git a/src/声源定位代码/mic-code/Maix/include/Maix_config.h b/src/声源定位代码/mic-code/Maix/include/Maix_config.h new file mode 100644 index 0000000..65cfa1a --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/include/Maix_config.h @@ -0,0 +1,5 @@ +#include "obj.h" + +mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur); +mp_obj_t maix_config_init(); +mp_obj_t maix_config_get_value(mp_obj_t key, mp_obj_t def_value); diff --git a/src/声源定位代码/mic-code/Maix/include/Maix_i2s.h b/src/声源定位代码/mic-code/Maix/include/Maix_i2s.h new file mode 100644 index 0000000..26db124 --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/include/Maix_i2s.h @@ -0,0 +1,23 @@ +#ifndef MICROPY_MAIX_I2S_H +#define MICROPY_MAIX_I2S_H + +#include "py/obj.h" +#include "i2s.h" +typedef struct _i2s_channle_t{ + i2s_word_length_t resolution; + i2s_word_select_cycles_t cycles; + i2s_work_mode_t align_mode; + i2s_transmit_t mode; +}i2s_channle_t; + +typedef struct _Maix_i2s_obj_t { + mp_obj_base_t base; + i2s_device_number_t i2s_num; + i2s_channle_t channel[4]; + uint32_t sample_rate; + uint32_t points_num; + uint32_t* buf; + i2s_word_select_cycles_t cycles; + uint32_t chn_mask; +} Maix_i2s_obj_t; +#endif \ No newline at end of file diff --git a/src/声源定位代码/mic-code/Maix/include/Maix_kpu.h b/src/声源定位代码/mic-code/Maix/include/Maix_kpu.h new file mode 100644 index 0000000..5805414 --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/include/Maix_kpu.h @@ -0,0 +1,25 @@ +#ifndef __MAIX_KPU_H +#define __MAIX_KPU_H + +#include "py/obj.h" + +typedef struct py_kpu_net_obj +{ + mp_obj_base_t base; + + void* kmodel_ctx; //sipeed_model_ctx_t + mp_obj_t model_size; + mp_obj_t model_addr; + mp_obj_t model_path; + mp_obj_t max_layers; + mp_obj_t net_args; // for yolo2 + mp_obj_t net_deinit; // for yolo2 +} __attribute__((aligned(8))) py_kpu_net_obj_t; + +extern const mp_obj_type_t py_kpu_net_obj_type; + +extern const mp_obj_type_t Maix_kpu_classifier_type; + + +#endif + diff --git a/src/声源定位代码/mic-code/Maix/include/modMaix.h b/src/声源定位代码/mic-code/Maix/include/modMaix.h new file mode 100644 index 0000000..be282db --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/include/modMaix.h @@ -0,0 +1,31 @@ +/* +* Copyright 2019 Sipeed Co.,Ltd. + +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MICROPY_INCLUDED_MAIX_MAIX_H +#define MICROPY_INCLUDED_MAIX_MAIX_H + +#include "py/obj.h" +#include "i2s.h" + +extern const mp_obj_type_t Maix_fpioa_type; +extern const mp_obj_type_t Maix_gpio_type; +extern const mp_obj_type_t Maix_i2s_type; +extern const mp_obj_type_t Maix_audio_type; +extern const mp_obj_type_t Maix_fft_type; +extern const mp_obj_type_t Maix_mic_array_type; +extern const mp_obj_type_t cpufreq_type; +extern const mp_obj_type_t Maix_utils_type; +extern const mp_obj_type_t Maix_config_type; +#endif // MICROPY_INCLUDED_MAIX_MAIX_H \ No newline at end of file diff --git a/src/声源定位代码/mic-code/Maix/include/py_cpufreq.h b/src/声源定位代码/mic-code/Maix/include/py_cpufreq.h new file mode 100644 index 0000000..12291a0 --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/include/py_cpufreq.h @@ -0,0 +1,11 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * CPU Frequency module. + * + */ +#ifndef __PY_CPUFREQ_H__ +#define __PY_CPUFREQ_H__ +#endif // __PY_CPUFREQ_H__ diff --git a/src/声源定位代码/mic-code/Maix/modMaix.c b/src/声源定位代码/mic-code/Maix/modMaix.c new file mode 100644 index 0000000..c70666e --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/modMaix.c @@ -0,0 +1,46 @@ +/* +* Copyright 2019 Sipeed Co.,Ltd. + +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include "py/runtime.h" + +#include "modMaix.h" + +STATIC const mp_rom_map_elem_t maix_module_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_machine) }, + { MP_ROM_QSTR(MP_QSTR_FPIOA), MP_ROM_PTR(&Maix_fpioa_type) }, + { MP_ROM_QSTR(MP_QSTR_GPIO), MP_ROM_PTR(&Maix_gpio_type) }, + { MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&Maix_i2s_type) }, + { MP_ROM_QSTR(MP_QSTR_Audio), MP_ROM_PTR(&Maix_audio_type) }, + { MP_ROM_QSTR(MP_QSTR_FFT), MP_ROM_PTR(&Maix_fft_type) }, +#if CONFIG_MAIXPY_MIC_ARRAY_ENABLE + { MP_ROM_QSTR(MP_QSTR_MIC_ARRAY), MP_ROM_PTR(&Maix_mic_array_type) }, +#endif + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&cpufreq_type) }, + { MP_ROM_QSTR(MP_QSTR_utils), MP_ROM_PTR(&Maix_utils_type) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&Maix_config_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT ( + maix_module_globals, + maix_module_globals_table +); + +const mp_obj_module_t maix_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&maix_module_globals, +}; + diff --git a/src/声源定位代码/mic-code/Maix/py_cpufreq.c b/src/声源定位代码/mic-code/Maix/py_cpufreq.c new file mode 100644 index 0000000..a2d1b7e --- /dev/null +++ b/src/声源定位代码/mic-code/Maix/py_cpufreq.c @@ -0,0 +1,136 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * CPU frequency scaling module. + * + */ + +#include +#include +#include +#include +#include "sysctl.h" +#include "py_cpufreq.h" +#include "py_helper.h" +#include "mpconfigboard.h" +#include "vfs_spiffs.h" +#include "sipeed_sys.h" + + +#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0])) +// static const uint32_t kpufreq_freqs[] = {100, 200, 400}; +//static const uint32_t cpufreq_pllq[] = {5, 6, 7, 8, 9}; + +// static const uint32_t cpufreq_latency[] = { // Flash latency (see table 11) +// FLASH_LATENCY_3, FLASH_LATENCY_4, FLASH_LATENCY_5, FLASH_LATENCY_7, FLASH_LATENCY_7 +// }; + +uint32_t cpufreq_get_cpuclk() +{ + uint32_t cpuclk = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU); + + return cpuclk; +} + +mp_obj_t py_cpufreq_get_current_frequencies() +{ + mp_obj_t tuple[2] = { + mp_obj_new_int(cpufreq_get_cpuclk() / (1000000)), + mp_obj_new_int(sysctl_clock_get_freq(SYSCTL_CLOCK_AI) / (1000000)), + }; + return mp_obj_new_tuple(2, tuple); +} + +// mp_obj_t py_kpufreq_get_supported_frequencies() +// { + +// mp_obj_t freq_list = mp_obj_new_list(0, NULL); +// for (int i=0; i FREQ_KPU_MAX || + freq_kpu < FREQ_KPU_MIN) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported KPU frequency!")); + } + + // Frequency is Not supported. + if ( config.freq_cpu > FREQ_CPU_MAX || + config.freq_cpu < FREQ_CPU_MIN ) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported CPU frequency!")); + } + + // Return if frequency hasn't changed. + if (( 20 > abs(config.freq_cpu - cpufreq_get_cpuclk())) && ( 20 > abs(freq_kpu - sysctl_clock_get_freq(SYSCTL_CLOCK_AI) ))) { + mp_printf(&mp_plat_print, "No change\r\n"); + return mp_const_none; + } + if(!save_config_to_spiffs(&config)) + mp_printf(&mp_plat_print, "save config fail"); + mp_printf(&mp_plat_print, "\r\nreboot now\r\n"); + mp_hal_delay_ms(50); + sipeed_sys_reset(); + + return mp_const_true; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_cpufreq_set_freq_obj,0, py_cpufreq_set_frequency); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_cpufreq_get_current_freq_obj, py_cpufreq_get_current_frequencies); +// STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_kpufreq_get_supported_frequencies_obj, py_kpufreq_get_supported_frequencies); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_kpufreq_get_kpu_obj, py_kpufreq_get_kpu); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_kpufreq_get_cpu_obj, py_kpufreq_get_cpu); + +static const mp_map_elem_t locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_freq) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_set), (mp_obj_t)&py_cpufreq_set_freq_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get), (mp_obj_t)&py_cpufreq_get_current_freq_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_kpu), (mp_obj_t)&py_kpufreq_get_kpu_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_get_cpu), (mp_obj_t)&py_kpufreq_get_cpu_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); + +const mp_obj_type_t cpufreq_type = { + .base = { &mp_type_type }, + .name = MP_QSTR_freq, + .locals_dict = (mp_obj_t)&locals_dict, +}; diff --git a/src/声源定位代码/mic-code/init-code/main.py b/src/声源定位代码/mic-code/init-code/main.py new file mode 100644 index 0000000..6ad6595 --- /dev/null +++ b/src/声源定位代码/mic-code/init-code/main.py @@ -0,0 +1,259 @@ +# 声源定位+WiFi传输集成程序 +from fpioa_manager import fm +from Maix import GPIO, MIC_ARRAY as mic +from board import board_info +import network, socket, time +from machine import UART +import math + +#----------------------------- +# 1. WiFi和服务器配置 +#----------------------------- +wifi_ap_ssid = "junzekeji" # 你的WiFi SSID +wifi_ap_passwd = "234567890l" # 你的WiFi密码 +PC_IP = "192.168.32.6" # 运行sound_map.py的电脑IP +UDP_PORT = 12345 # 与sound_map.py里配置的端口一致 +TCP_PORT = 12345 # 替换你想要的端口 + +# 全局变量 +uart = None +wifi_en = None +nic = None +udp_sock = None +tcp_sock = None + +#----------------------------- +# 2. 引脚映射和WiFi使能 +#----------------------------- +def init_wifi_hardware(): + global wifi_en + # GPIOHS0 用于WiFi使能控制 + fm.register(8, fm.fpioa.GPIOHS0, force=True) + wifi_en = GPIO(GPIO.GPIOHS0, GPIO.OUT) + # 配置UART用于与ESP8285通信 + fm.register(board_info.WIFI_RX, fm.fpioa.UART2_TX, force=True) + fm.register(board_info.WIFI_TX, fm.fpioa.UART2_RX, force=True) + print("WiFi硬件引脚初始化完成。") + +def wifi_enable(en): + # 控制WiFi模块电源 + global wifi_en + if wifi_en: + wifi_en.value(en) + +#----------------------------- +# 3. 复位WiFi并连接到路由器 +#----------------------------- +def wifi_reset_and_connect(): + global uart, nic + # 复位WiFi模块 + wifi_enable(0) # 先关闭 + time.sleep_ms(200) + wifi_enable(1) # 再打开 + time.sleep(2) # 等待稳定 + + # 初始化UART,低波特率 + uart = UART(UART.UART2, 115200, timeout=1000, read_buf_len=4096) + _ = uart.read() # 清空缓存 + + # 提升波特率到921600 + uart.write("AT+UART_CUR=921600,8,1,0,0\r\n") + time.sleep_ms(100) + print("AT+UART_CUR响应:", uart.read()) + uart = UART(UART.UART2, 921600, timeout=1000, read_buf_len=4096) + + # 测试AT指令是否正常 + uart.write("AT\r\n") + time.sleep_ms(100) + at_response = uart.read() + print("AT响应:", at_response) + if not at_response or not at_response.endswith(b"OK\r\n"): + print("AT命令失败,WiFi重置失败。") + return False + + # 初始化网络对象 + try: + nic = network.ESP8285(uart) + except Exception as e: + print("ESP8285初始化失败:", e) + return False + + # 连接到WiFi网络 + print("尝试连接到WiFi: {}...".format(wifi_ap_ssid)) + try: + nic.connect(wifi_ap_ssid, wifi_ap_passwd) + attempts = 0 + while not nic.isconnected() and attempts < 20: # 最多等待20秒 + print("等待连接... {}/20".format(attempts + 1)) + time.sleep(1) + attempts += 1 + + if nic.isconnected(): + print("WiFi连接成功!") + print("IP信息:", nic.ifconfig()) + return True + else: + print("WiFi连接超时或失败。") + return False + except Exception as e: + print("连接WiFi时发生异常:", e) + return False + +#----------------------------- +# 4. 声源定位函数 +#----------------------------- +def get_mic_dir(): + AngleX = 0 + AngleY = 0 + AngleR = 0 + Angle = 0 + AngleAddPi = 0 + mic_list = [] + imga = mic.get_map() # 获取声音源分布图像 + b = mic.get_dir(imga) # 计算声源方向 + for i in range(len(b)): + if b[i] >= 2: + AngleX += b[i] * math.sin(i * math.pi / 6) + AngleY += b[i] * math.cos(i * math.pi / 6) + AngleX = round(AngleX, 6) + AngleY = round(AngleY, 6) + if AngleY < 0: + AngleAddPi = 180 + if AngleX < 0 and AngleY > 0: + AngleAddPi = 360 + if AngleX != 0 or AngleY != 0: + if AngleY == 0: + Angle = 90 if AngleX > 0 else 270 + else: + Angle = AngleAddPi + round(math.degrees(math.atan(AngleX / AngleY)), 4) + AngleR = round(math.sqrt(AngleY * AngleY + AngleX * AngleX), 4) + mic_list.append(AngleX) + mic_list.append(AngleY) + mic_list.append(AngleR) + mic_list.append(Angle) + mic.set_led(b, (0, 0, 255)) + + return mic_list + +#----------------------------- +# 5. 初始化TCP Socket +#----------------------------- +def setup_tcp_socket(): + global tcp_sock + try: + tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + tcp_sock.connect((PC_IP, TCP_PORT)) + print("TCP连接成功。") + return True + except Exception as e: + print("TCP连接失败:", e) + return False + +#----------------------------- +# 6. 主循环:连接WiFi、发送数据 +#----------------------------- +def main_loop(): + global nic, tcp_sock + + # 初始化麦克风阵列 + mic.init(i2s_d0=23, i2s_d1=22, i2s_d2=21, i2s_d3=20, + i2s_ws=19, i2s_sclk=18, + sk9822_dat=24, sk9822_clk=25) + print("麦克风阵列初始化完成。") + + # 初始化WiFi硬件 + init_wifi_hardware() + + # 不断尝试连接WiFi和设置TCP + while True: + if nic and nic.isconnected(): + if not tcp_sock: + if not setup_tcp_socket(): + print("TCP设置失败,2秒后重试...") + time.sleep(2) + nic.disconnect() + nic = None + continue + # 如果WiFi和TCP都已准备好,跳出循环 + break + else: + print("尝试连接WiFi...") + if wifi_reset_and_connect(): + if not setup_tcp_socket(): + print("TCP设置失败,断开WiFi并重试...") + nic.disconnect() + nic = None + time.sleep(2) + else: + print("WiFi连接失败,2秒后重试...") + time.sleep(2) + + print("WiFi和TCP准备就绪,开始发送声源数据到 {}:{}".format(PC_IP, TCP_PORT)) + + # 发送消息计数 + msg_count = 0 + + # 主循环:获取声源数据并发送 + while True: + # 检查WiFi连接状态 + if not nic or not nic.isconnected(): + print("WiFi连接断开,尝试重新连接...") + if tcp_sock: + tcp_sock.close() + tcp_sock = None + nic = None + # 重新启动连接流程 + main_loop() + return + + # 获取声源数据 + source_data = get_mic_dir() + if source_data: + # 解析数据: X, Y, 强度, 角度 + x, y, strength, angle = source_data + + # 打印数据用于调试 + print("麦克风定位: X={:.2f}, Y={:.2f}, 强度={:.2f}, 角度={:.2f}".format( + x, y, strength, angle)) + + # 格式化为CSV字符串发送 + data_string = "{:.4f},{:.4f},{:.4f},{:.4f}".format(x, y, strength, angle) + + try: + # 发送到PC + tcp_sock.send(data_string.encode('utf-8')) + msg_count += 1 + # 每50条显示一次发送状态 + if msg_count % 50 == 0: + print("已发送第 {} 条数据".format(msg_count)) + except Exception as e: + print("TCP发送失败:", e) + # 关闭并重新连接 + tcp_sock.close() + tcp_sock = None + nic.disconnect() + nic = None + print("将尝试重新建立连接...") + time.sleep(1) + main_loop() + return + + # 控制采样间隔 + time.sleep_ms(100) + +# 主程序入口 +if __name__ == "__main__": + try: + main_loop() + except KeyboardInterrupt: + print("用户中断程序。") + finally: + # 清理资源 + if tcp_sock: + tcp_sock.close() + print("TCP socket已关闭。") + if nic and nic.isconnected(): + nic.disconnect() + print("WiFi已断开。") + wifi_enable(0) # 关闭WiFi模块 + print("程序结束。") diff --git a/src/声源定位代码/mic-code/init-code/main_raw.py b/src/声源定位代码/mic-code/init-code/main_raw.py new file mode 100644 index 0000000..d09d9e6 --- /dev/null +++ b/src/声源定位代码/mic-code/init-code/main_raw.py @@ -0,0 +1,38 @@ +from Maix import MIC_ARRAY as mic +import lcd,time +import math +mic.init(i2s_d0=23, i2s_d1=22, i2s_d2=21, i2s_d3=20, i2s_ws=19, i2s_sclk=18, sk9822_dat=24, sk9822_clk=25) +def get_mic_dir(): + AngleX=0 + AngleY=0 + AngleR=0 + Angle=0 + AngleAddPi=0 + mic_list=[] + imga = mic.get_map() # 获取声音源分布图像 + b = mic.get_dir(imga) # 计算、获取声源方向 + for i in range(len(b)): + if b[i]>=2: + AngleX+= b[i]*math.sin(i*math.pi/6) + AngleY+= b[i]*math.cos(i*math.pi/6) + AngleX=round(AngleX,6) #计算坐标转换值 + AngleY=round(AngleY,6) + if AngleY<0:AngleAddPi=180 + if AngleX<0 and AngleY > 0:AngleAddPi=360 + if AngleX!=0 or AngleY!=0: #参数修正 + if AngleY==0: + Angle=90 if AngleX>0 else 270 #填补X轴角度 + else: + Angle=AngleAddPi+round(math.degrees(math.atan(AngleX/AngleY)),4) #计算角度 + AngleR=round(math.sqrt(AngleY*AngleY+AngleX*AngleX),4) #计算强度 + mic_list.append(AngleX) + mic_list.append(AngleY) + mic_list.append(AngleR) + mic_list.append(Angle) + a = mic.set_led(b,(0,0,255))# 配置 RGB LED 颜色值 + return mic_list #返回列表,X坐标,Y坐标,强度,角度 +while True: + A=get_mic_dir() + if A: + print(A) + time.sleep_ms(100) diff --git a/src/声源定位代码/mic-code/init-code/tcp_listen.py b/src/声源定位代码/mic-code/init-code/tcp_listen.py new file mode 100644 index 0000000..2ea8d41 --- /dev/null +++ b/src/声源定位代码/mic-code/init-code/tcp_listen.py @@ -0,0 +1,27 @@ +import socket +import time + +LOCAL_IP = "0.0.0.0" +LOCAL_PORT = 12345 + +def start_tcp_server(): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind((LOCAL_IP, LOCAL_PORT)) + sock.listen(5) + print(f"Listening on TCP {LOCAL_IP}:{LOCAL_PORT} ... (Ctrl+C 退出)\n") + client_socket, address = sock.accept() + client_socket.setblocking(True) + try: + while True: + recvmsg = client_socket.recv(1024) + strData = recvmsg.decode("utf-8") + now = time.strftime('%H:%M:%S') + print(f"[{now}] 来自 {client_socket.getpeername()} 的数据: {strData}") + except KeyboardInterrupt: + print("\n服务器已退出.") + finally: + client_socket.close() + sock.close() + +if __name__ == "__main__": + start_tcp_server() \ No newline at end of file diff --git a/src/声源定位代码/mic-code/init-code/test_send.py b/src/声源定位代码/mic-code/init-code/test_send.py new file mode 100644 index 0000000..55137ad --- /dev/null +++ b/src/声源定位代码/mic-code/init-code/test_send.py @@ -0,0 +1,89 @@ +from fpioa_manager import fm +from Maix import GPIO +from board import board_info +import time, network, socket +from machine import UART + + + +WIFI_SSID = "junzekeji" # 替换为你的WiFi +WIFI_PASSWD = "234567890l" # 替换为你的WiFi密码 +PC_IP = "192.168.32.6" # 替换为你的电脑IP +PC_PORT = 12345 # 替换为你的监听端口 + +def wifi_enable(en): + if wifi_en: + wifi_en.value(en) + + + +# 定义UDP发送函数 +def udp_send(ip, port, message): + """向指定IP和端口发送UDP消息""" + try: + ADDR = (ip, port) + sock = socket.socket() + sock.connect(ADDR) + #sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + #sock.settimeout(1) + print(message, ip, port) + sock.send(message) + sock.close() + return True + except Exception as e: + print("UDP发送错误:", e) + return False + +# 测试单次发送 +def udp_client(server_ip, server_port): + message = "Hello from K210!" + if udp_send(server_ip, server_port, message): + print("已向 {}:{} 发送消息: {}".format(server_ip, server_port, message)) + else: + print("向 {}:{} 发送消息失败".format(server_ip, server_port)) + +if __name__ == "__main__": + # (1) GPIO 注册,用于 WiFi 使能 + fm.register(8, fm.fpioa.GPIOHS0, force=True) + wifi_en = GPIO(GPIO.GPIOHS0, GPIO.OUT) + wifi_enable(0) + time.sleep_ms(200) + wifi_enable(1) + time.sleep(2) + + # (2) 初始化 UART (115200) + fm.register(board_info.WIFI_RX, fm.fpioa.UART2_TX, force=True) + fm.register(board_info.WIFI_TX, fm.fpioa.UART2_RX, force=True) + uart = UART(UART.UART2, 115200, timeout=1000, read_buf_len=4096) + _ = uart.read() # 清空缓存 + + # (3) 初始化 ESP8285 + try: + nic = network.ESP8285(uart) + except Exception as e: + print("ESP8285初始化失败:", e) + time.sleep(1) + + # (4) 连接 WiFi + print("尝试连接 WiFi:", WIFI_SSID) + try: + nic.connect(WIFI_SSID, WIFI_PASSWD) + attempts = 0 + while not nic.isconnected() and attempts < 20: + attempts += 1 + print("等待连接... 第 {}/20 次".format(attempts)) + time.sleep(1) + + if nic.isconnected(): + print("WiFi连接成功!") + print("IP信息:", nic.ifconfig()) + #time.sleep(1) + else: + print("WiFi连接失败,请检查SSID或密码。") + time.sleep(1) + except Exception as e: + print("连接WiFi异常:", e) + + # 测试单次发送 + udp_client(PC_IP, PC_PORT) + diff --git a/src/声源定位代码/mic-code/init-code/wifi_connection.py b/src/声源定位代码/mic-code/init-code/wifi_connection.py new file mode 100644 index 0000000..22eab49 --- /dev/null +++ b/src/声源定位代码/mic-code/init-code/wifi_connection.py @@ -0,0 +1,110 @@ +from fpioa_manager import fm +from Maix import GPIO +from board import board_info +import network, socket, time +from machine import UART + +# 1. 引脚映射(适配 Maix Dock + ESP8285) +fm.register(8, fm.fpioa.GPIOHS0, force=True) +wifi_en = GPIO(GPIO.GPIOHS0, GPIO.OUT) + +fm.register(board_info.WIFI_RX, fm.fpioa.UART2_TX, force=True) +fm.register(board_info.WIFI_TX, fm.fpioa.UART2_RX, force=True) + +# 2. 配置您的无线网络及服务器信息 +wifi_ap_ssid = "junzekeji" +wifi_ap_passwd = "234567890l" +server_ip = "192.168.0.101" +server_port = 8080 + +# 3. WiFi使能控制 +def wifi_enable(en): + global wifi_en + wifi_en.value(en) + +# 4. WiFi复位并返回网络对象 +def wifi_reset(): + global uart + wifi_enable(0) # 关闭WiFi + time.sleep_ms(200) + wifi_enable(1) # 启用WiFi + time.sleep(2) + # 初始化UART + uart = UART(UART.UART2, 115200, timeout=1000, read_buf_len=4096) + tmp = uart.read() # 清空缓存 + # 提升波特率 + uart.write("AT+UART_CUR=921600,8,1,0,0\r\n") + print(uart.read()) + uart = UART(UART.UART2, 921600, timeout=1000, read_buf_len=4096) + # 测试 AT 指令 + uart.write("AT\r\n") + tmp = uart.read() + print(tmp) + + if not tmp or (not tmp.endswith(b"OK\r\n")): + print("reset fail") + return None + + # 尝试通过ESP8285对象进行初始化 + try: + nic = network.ESP8285(uart) + except Exception as e: + print("ESP8285 init fail:", e) + return None + return nic + +def main(): + nic = None + while True: + # 若无网络或已断开, 则重置并连接 + if (not nic) or (not nic.isconnected()): + nic = wifi_reset() + if not nic: + print("WiFi init fail, retry...") + continue + + # 连接WiFi + try: + nic.connect(wifi_ap_ssid, wifi_ap_passwd) + print("WiFi info:", nic.ifconfig()) + except Exception as e: + print("连接错误:", e) + continue + + # 判断连接状态 + if not nic.isconnected(): + print("WiFi连接失败,重试...") + continue + + print("WiFi连接成功!") + sock = socket.socket() + addr = (server_ip, server_port) + try: + sock.connect(addr) + print("已连接到服务器:", addr) + except Exception as e: + print("连接服务器失败:", e) + sock.close() + continue + + # 发送数据 + err = 0 + count = 0 + while True: + if err >= 10: + print("socket broken!") + break + try: + send_len = sock.send("Hello from K210!\n") + count += 1 + print("已发送:", count, "次") + except Exception as e: + print("发送失败:", e) + err += 1 + time.sleep(2) + continue + time.sleep(1) + sock.close() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/声源定位代码/mic-code/sound_map.py b/src/声源定位代码/mic-code/sound_map.py new file mode 100644 index 0000000..402e863 --- /dev/null +++ b/src/声源定位代码/mic-code/sound_map.py @@ -0,0 +1,113 @@ +# serial_receiver_with_map.py +import serial +import time +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.animation import FuncAnimation + +# ========== 配置区 ========== +SERIAL_PORT = 'COM9' # 串口号 +BAUDRATE = 115200 # 波特率 +PLOT_INTERVAL_MS = 100 # 刷新间隔(ms) +PLOT_RANGE = 15.0 # 坐标轴固定范围(-PLOT_RANGE 到 +PLOT_RANGE) +POINT_SIZE = 200 # 声源点大小(加大更醒目) +# =========================== + +# 初始化串口 +ser = serial.Serial(port=SERIAL_PORT , baudrate=BAUDRATE , timeout=0.1) +ser.dtr = False +ser.rts = False + +# 存储数据(仅保留最新点) +current_point = np.array([[0 , 0]]) # 初始化为原点 +current_strength = np.array([0.0]) + +# 设置中文字体 +plt.rcParams['font.sans-serif'] = ['SimHei'] +plt.rcParams['axes.unicode_minus'] = False + +# 初始化绘图 +fig , ax = plt.subplots(figsize=(8 , 8)) +ax.set_title("实时声源定位地图(单点模式)") +ax.set_xlabel("X 坐标") +ax.set_ylabel("Y 坐标") +ax.set_xlim(-PLOT_RANGE , PLOT_RANGE) +ax.set_ylim(-PLOT_RANGE , PLOT_RANGE) +ax.grid(True) + +# 设置坐标轴样式 +ax.axhline(0 , color='gray' , linestyle='--' , alpha=0.5) +ax.axvline(0 , color='gray' , linestyle='--' , alpha=0.5) +ax.scatter([0] , [0] , c='red' , s=80 , label='当前位置') +ax.legend(loc='upper right') + +# 初始化散点图(始终只显示一个点) +scat = ax.scatter([] , [] , c=[] , cmap='viridis' , + s=POINT_SIZE , alpha=0.9 , + vmin=0 , vmax=10 , # 根据实际强度范围调整vmax + edgecolors='black') + + +def update_plot(frame): + """更新地图""" + scat.set_offsets(current_point) + scat.set_array(current_strength) + return scat , + + +# 启动动画 +ani = FuncAnimation(fig , update_plot , interval=PLOT_INTERVAL_MS , + cache_frame_data=False , blit=True) + + +def safe_read(): + """安全读取串口数据""" + try: + return ser.read(ser.in_waiting).decode('ascii' , errors='ignore') if ser.in_waiting > 0 else '' + except Exception as e: + print(f"串口错误: {e}") + return '' + + +def clamp(value , min_val , max_val): + """保底显示:超出范围时显示在边缘""" + return max(min(value , max_val) , min_val) + + +try: + buffer = '' + print("开始监听... (Ctrl+C 停止)") + + while True: + buffer += safe_read() + while '\n' in buffer: + line , buffer = buffer.split('\n' , 1) + line = line.strip() + + if line.startswith('[') and line.endswith(']'): + try: + # 解析数据 + data_str = line[1:-1].replace(' ' , '') + data = list(map(float , data_str.split(','))) + if len(data) == 4: + raw_x , raw_y , strength , _ = data + + # 保底坐标计算 + x = clamp(raw_x , -PLOT_RANGE , PLOT_RANGE) + y = clamp(raw_y , -PLOT_RANGE , PLOT_RANGE) + + print(f"接收到: X={x:.2f}, Y={y:.2f}, 强度={strength:.2f}") + + # 更新数据(覆盖旧点) + current_point[0] = [x , y] # 直接修改数组内容 + current_strength[0] = strength + except Exception as e: + print(f"解析失败: {line}, 错误: {e}") + + plt.pause(0.001) + +except KeyboardInterrupt: + print("\n用户终止") +finally: + ser.close() + plt.close() \ No newline at end of file diff --git a/src/声源定位代码/mic-code/sound_map_wifi.py b/src/声源定位代码/mic-code/sound_map_wifi.py new file mode 100644 index 0000000..e4b57f9 --- /dev/null +++ b/src/声源定位代码/mic-code/sound_map_wifi.py @@ -0,0 +1,114 @@ +import socket +import time +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.animation import FuncAnimation + +# ========== 配置区 ========== +TCP_IP = "0.0.0.0" # PC端监听所有可用IP地址 +TCP_PORT = 12345 # 必须与K210端配置的 TCP_PORT 一致 +PLOT_INTERVAL_MS = 100 # 刷新间隔(ms) +PLOT_RANGE = 15.0 # 坐标轴固定范围(-PLOT_RANGE 到 +PLOT_RANGE) +POINT_SIZE = 200 # 声源点大小(加大更醒目) +# =========================== + +# 初始化 TCP 服务器 +server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +try: + server_sock.bind((TCP_IP, TCP_PORT)) + server_sock.listen(1) + print("TCP服务器正在监听 {}:{} ...".format(TCP_IP, TCP_PORT)) + client_sock, addr = server_sock.accept() + client_sock.settimeout(0.1) + print("已接受连接:", addr) +except Exception as e: + print("绑定或监听TCP端口 {} 失败: {}".format(TCP_PORT, e)) + exit() + +# 仅保留最新点 +current_point = np.array([[0, 0]]) +current_strength = np.array([0.0]) + +# 设置中文字体 +plt.rcParams['font.sans-serif'] = ['SimHei'] +plt.rcParams['axes.unicode_minus'] = False + +# 初始化绘图 +fig, ax = plt.subplots(figsize=(8, 8)) +ax.set_title("实时声源定位地图 (TCP接收)") +ax.set_xlabel("X 坐标") +ax.set_ylabel("Y 坐标") +ax.set_xlim(-PLOT_RANGE, PLOT_RANGE) +ax.set_ylim(-PLOT_RANGE, PLOT_RANGE) +ax.grid(True) + +# 坐标轴辅助线 +ax.axhline(0, color='gray', linestyle='--', alpha=0.5) +ax.axvline(0, color='gray', linestyle='--', alpha=0.5) +ax.scatter([0], [0], c='red', s=80, label='声源探测器位置') +ax.legend(loc='upper right') + +# 初始化散点图(始终只显示一个点) +scat = ax.scatter([], [], c=[], cmap='viridis', + s=POINT_SIZE, alpha=0.9, + vmin=0, vmax=10, + edgecolors='black') + +def update_plot(frame): + scat.set_offsets(current_point) + scat.set_array(current_strength) + return scat, + +ani = FuncAnimation(fig, update_plot, interval=PLOT_INTERVAL_MS, + cache_frame_data=False, blit=True) + +def clamp(value, min_val, max_val): + return max(min(value, max_val), min_val) + +try: + print("开始通过TCP监听声源数据... (Ctrl+C 停止)") + while True: + try: + data_bytes = client_sock.recv(1024) + if not data_bytes: + # 对端断开或网络中断时直接退出 + print("连接已断开。") + break + line = data_bytes.decode('utf-8').strip() + + # K210发送的数据格式: "X,Y,强度,Angle" + if line: + try: + data_parts = list(map(float, line.split(','))) + if len(data_parts) == 4: + raw_x, raw_y, strength, angle = data_parts + x = clamp(raw_x, -PLOT_RANGE, PLOT_RANGE) + y = clamp(raw_y, -PLOT_RANGE, PLOT_RANGE) + print("接收到声源: X={:.2f}, Y={:.2f}, 强度={:.2f}, 角度={:.2f}".format(x, y, strength, angle)) + current_point[0] = [x, y] + current_strength[0] = strength + else: + print("数据格式错误:", line) + except ValueError: + print("数据解析失败 (非数字):", line) + except Exception as e: + print("处理数据时发生错误: {}, 错误: {}".format(line, e)) + except socket.timeout: + pass + except Exception as e: + print("TCP接收错误:", e) + time.sleep(0.1) + + plt.pause(0.001) + +except KeyboardInterrupt: + print("\n用户终止") +finally: + if client_sock: + client_sock.close() + print("TCP客户端socket已关闭。") + if server_sock: + server_sock.close() + print("TCP服务器已关闭。") + plt.close() + print("程序结束。") \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/.vscode/settings.json b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/.vscode/settings.json new file mode 100644 index 0000000..dd22383 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.sourceDirectory": "/home/zwt/software/gold_eyes/src/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system" +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/.gitignore b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/demo.iml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/demo.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/demo.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/inspectionProfiles/Project_Default.xml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/misc.xml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/misc.xml new file mode 100644 index 0000000..0e05be0 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/modules.xml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/modules.xml new file mode 100644 index 0000000..c95e899 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/vcs.xml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/vcs.xml new file mode 100644 index 0000000..bc59970 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/details.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/details.md new file mode 100644 index 0000000..f1a1fd9 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/details.md @@ -0,0 +1,69 @@ +# Details + +Date : 2025-06-10 08:55:17 + +Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master + +Total : 54 files, 6851 codes, 838 comments, 1201 blanks, all 8890 lines + +[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md) + +## Files +| filename | language | code | comment | blank | total | +| :--- | :--- | ---: | ---: | ---: | ---: | +| [README.md](/README.md) | Markdown | 302 | 0 | 72 | 374 | +| [README\_en.md](/README_en.md) | Markdown | 231 | 0 | 45 | 276 | +| [audio-classification-platform/README.md](/audio-classification-platform/README.md) | Markdown | 96 | 0 | 41 | 137 | +| [audio-classification-platform/backend/app.py](/audio-classification-platform/backend/app.py) | Python | 255 | 35 | 61 | 351 | +| [audio-classification-platform/backend/config.py](/audio-classification-platform/backend/config.py) | Python | 22 | 8 | 10 | 40 | +| [audio-classification-platform/backend/requirements.txt](/audio-classification-platform/backend/requirements.txt) | pip requirements | 7 | 0 | 1 | 8 | +| [audio-classification-platform/frontend/index.html](/audio-classification-platform/frontend/index.html) | HTML | 25 | 0 | 2 | 27 | +| [audio-classification-platform/frontend/package.json](/audio-classification-platform/frontend/package.json) | JSON | 24 | 0 | 1 | 25 | +| [audio-classification-platform/frontend/src/App.vue](/audio-classification-platform/frontend/src/App.vue) | Vue | 88 | 5 | 14 | 107 | +| [audio-classification-platform/frontend/src/components/AudioRecorder.vue](/audio-classification-platform/frontend/src/components/AudioRecorder.vue) | Vue | 551 | 38 | 102 | 691 | +| [audio-classification-platform/frontend/src/components/AudioRecorder\_new.vue](/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue) | Vue | 811 | 48 | 162 | 1,021 | +| [audio-classification-platform/frontend/src/components/AudioUpload.vue](/audio-classification-platform/frontend/src/components/AudioUpload.vue) | Vue | 580 | 28 | 107 | 715 | +| [audio-classification-platform/frontend/src/components/HistoryList.vue](/audio-classification-platform/frontend/src/components/HistoryList.vue) | Vue | 513 | 25 | 79 | 617 | +| [audio-classification-platform/frontend/src/components/PredictionResult.vue](/audio-classification-platform/frontend/src/components/PredictionResult.vue) | Vue | 803 | 22 | 117 | 942 | +| [audio-classification-platform/frontend/src/main.js](/audio-classification-platform/frontend/src/main.js) | JavaScript | 13 | 1 | 5 | 19 | +| [audio-classification-platform/frontend/src/router/index.js](/audio-classification-platform/frontend/src/router/index.js) | JavaScript | 14 | 0 | 4 | 18 | +| [audio-classification-platform/frontend/src/utils/api.js](/audio-classification-platform/frontend/src/utils/api.js) | JavaScript | 156 | 25 | 33 | 214 | +| [audio-classification-platform/frontend/src/views/HomePage.vue](/audio-classification-platform/frontend/src/views/HomePage.vue) | Vue | 692 | 40 | 110 | 842 | +| [audio-classification-platform/frontend/vite.config.js](/audio-classification-platform/frontend/vite.config.js) | JavaScript | 32 | 0 | 2 | 34 | +| [audio-classification-platform/start.bat](/audio-classification-platform/start.bat) | Batch | 20 | 0 | 5 | 25 | +| [audio-classification-platform/start.sh](/audio-classification-platform/start.sh) | Shell Script | 26 | 3 | 8 | 37 | +| [configs/augmentation.yml](/configs/augmentation.yml) | YAML | 21 | 21 | 5 | 47 | +| [configs/cam++.yml](/configs/cam++.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/ecapa\_tdnn.yml](/configs/ecapa_tdnn.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/eres2net.yml](/configs/eres2net.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/panns.yml](/configs/panns.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/res2net.yml](/configs/res2net.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/resnet\_se.yml](/configs/resnet_se.yml) | YAML | 43 | 33 | 5 | 81 | +| [configs/tdnn.yml](/configs/tdnn.yml) | YAML | 43 | 33 | 5 | 81 | +| [create\_data.py](/create_data.py) | Python | 75 | 9 | 16 | 100 | +| [eval.py](/eval.py) | Python | 20 | 2 | 5 | 27 | +| [extract\_features.py](/extract_features.py) | Python | 13 | 2 | 5 | 20 | +| [infer.py](/infer.py) | Python | 17 | 1 | 6 | 24 | +| [infer\_record.py](/infer_record.py) | Python | 40 | 7 | 12 | 59 | +| [macls/\_\_init\_\_.py](/macls/__init__.py) | Python | 1 | 0 | 1 | 2 | +| [macls/data\_utils/\_\_init\_\_.py](/macls/data_utils/__init__.py) | Python | 0 | 0 | 1 | 1 | +| [macls/data\_utils/collate\_fn.py](/macls/data_utils/collate_fn.py) | Python | 17 | 4 | 3 | 24 | +| [macls/data\_utils/featurizer.py](/macls/data_utils/featurizer.py) | Python | 88 | 36 | 9 | 133 | +| [macls/data\_utils/reader.py](/macls/data_utils/reader.py) | Python | 114 | 33 | 11 | 158 | +| [macls/metric/\_\_init\_\_.py](/macls/metric/__init__.py) | Python | 0 | 0 | 1 | 1 | +| [macls/metric/metrics.py](/macls/metric/metrics.py) | Python | 9 | 1 | 3 | 13 | +| [macls/optimizer/\_\_init\_\_.py](/macls/optimizer/__init__.py) | Python | 26 | 0 | 7 | 33 | +| [macls/optimizer/scheduler.py](/macls/optimizer/scheduler.py) | Python | 42 | 0 | 7 | 49 | +| [macls/predict.py](/macls/predict.py) | Python | 124 | 47 | 7 | 178 | +| [macls/trainer.py](/macls/trainer.py) | Python | 338 | 99 | 20 | 457 | +| [macls/utils/\_\_init\_\_.py](/macls/utils/__init__.py) | Python | 0 | 0 | 1 | 1 | +| [macls/utils/checkpoint.py](/macls/utils/checkpoint.py) | Python | 113 | 40 | 10 | 163 | +| [macls/utils/record.py](/macls/utils/record.py) | Python | 18 | 8 | 6 | 32 | +| [macls/utils/utils.py](/macls/utils/utils.py) | Python | 99 | 16 | 17 | 132 | +| [record\_audio.py](/record_audio.py) | Python | 10 | 0 | 5 | 15 | +| [requirements.txt](/requirements.txt) | pip requirements | 17 | 0 | 1 | 18 | +| [setup.py](/setup.py) | Python | 43 | 1 | 11 | 55 | +| [tools/download\_language\_data.sh](/tools/download_language_data.sh) | Shell Script | 19 | 1 | 10 | 30 | +| [train.py](/train.py) | Python | 25 | 1 | 5 | 31 | + +[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md) \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff-details.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff-details.md new file mode 100644 index 0000000..55f2906 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff-details.md @@ -0,0 +1,15 @@ +# Diff Details + +Date : 2025-06-10 08:55:17 + +Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master + +Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines + +[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details + +## Files +| filename | language | code | comment | blank | total | +| :--- | :--- | ---: | ---: | ---: | ---: | + +[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.csv b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.csv new file mode 100644 index 0000000..b7d8d75 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.csv @@ -0,0 +1,2 @@ +"filename", "language", "", "comment", "blank", "total" +"Total", "-", , 0, 0, 0 \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.md new file mode 100644 index 0000000..0cab177 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.md @@ -0,0 +1,19 @@ +# Diff Summary + +Date : 2025-06-10 08:55:17 + +Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master + +Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines + +[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md) + +## Languages +| language | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | + +## Directories +| path | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | + +[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md) \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.txt b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.txt new file mode 100644 index 0000000..b332216 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/diff.txt @@ -0,0 +1,22 @@ +Date : 2025-06-10 08:55:17 +Directory : e:\pycharm_projects\AudioClassification-Pytorch-master +Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines + +Languages ++----------+------------+------------+------------+------------+------------+ +| language | files | code | comment | blank | total | ++----------+------------+------------+------------+------------+------------+ ++----------+------------+------------+------------+------------+------------+ + +Directories ++------+------------+------------+------------+------------+------------+ +| path | files | code | comment | blank | total | ++------+------------+------------+------------+------------+------------+ ++------+------------+------------+------------+------------+------------+ + +Files ++----------+----------+------------+------------+------------+------------+ +| filename | language | code | comment | blank | total | ++----------+----------+------------+------------+------------+------------+ +| Total | | 0 | 0 | 0 | 0 | ++----------+----------+------------+------------+------------+------------+ \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.csv b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.csv new file mode 100644 index 0000000..6cde0c8 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.csv @@ -0,0 +1,56 @@ +"filename", "language", "Python", "pip requirements", "Markdown", "Shell Script", "YAML", "Batch", "JavaScript", "Vue", "JSON", "HTML", "comment", "blank", "total" +"e:\pycharm_projects\AudioClassification-Pytorch-master\README.md", "Markdown", 0, 0, 302, 0, 0, 0, 0, 0, 0, 0, 0, 72, 374 +"e:\pycharm_projects\AudioClassification-Pytorch-master\README_en.md", "Markdown", 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 0, 45, 276 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\README.md", "Markdown", 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 41, 137 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\app.py", "Python", 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 61, 351 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\config.py", "Python", 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 40 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\requirements.txt", "pip requirements", 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 8 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\index.html", "HTML", 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 2, 27 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\package.json", "JSON", 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 1, 25 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\App.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 5, 14, 107 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 551, 0, 0, 38, 102, 691 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder_new.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 811, 0, 0, 48, 162, 1021 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioUpload.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 580, 0, 0, 28, 107, 715 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\HistoryList.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 513, 0, 0, 25, 79, 617 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\PredictionResult.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 803, 0, 0, 22, 117, 942 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\main.js", "JavaScript", 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 1, 5, 19 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\router\index.js", "JavaScript", 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 4, 18 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\utils\api.js", "JavaScript", 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 25, 33, 214 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\views\HomePage.vue", "Vue", 0, 0, 0, 0, 0, 0, 0, 692, 0, 0, 40, 110, 842 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\vite.config.js", "JavaScript", 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 2, 34 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.bat", "Batch", 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 5, 25 +"e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.sh", "Shell Script", 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 3, 8, 37 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\augmentation.yml", "YAML", 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 21, 5, 47 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\cam++.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\ecapa_tdnn.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\eres2net.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\panns.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\res2net.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\resnet_se.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\configs\tdnn.yml", "YAML", 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 33, 5, 81 +"e:\pycharm_projects\AudioClassification-Pytorch-master\create_data.py", "Python", 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 16, 100 +"e:\pycharm_projects\AudioClassification-Pytorch-master\eval.py", "Python", 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 27 +"e:\pycharm_projects\AudioClassification-Pytorch-master\extract_features.py", "Python", 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 20 +"e:\pycharm_projects\AudioClassification-Pytorch-master\infer.py", "Python", 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 24 +"e:\pycharm_projects\AudioClassification-Pytorch-master\infer_record.py", "Python", 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 12, 59 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\__init__.py", "Python", 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\__init__.py", "Python", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\collate_fn.py", "Python", 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 3, 24 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\featurizer.py", "Python", 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 9, 133 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\reader.py", "Python", 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 11, 158 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\__init__.py", "Python", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\metrics.py", "Python", 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 13 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\__init__.py", "Python", 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 33 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\scheduler.py", "Python", 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 49 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\predict.py", "Python", 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 7, 178 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\trainer.py", "Python", 338, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 20, 457 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\__init__.py", "Python", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\checkpoint.py", "Python", 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 10, 163 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\record.py", "Python", 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 6, 32 +"e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\utils.py", "Python", 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 132 +"e:\pycharm_projects\AudioClassification-Pytorch-master\record_audio.py", "Python", 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 15 +"e:\pycharm_projects\AudioClassification-Pytorch-master\requirements.txt", "pip requirements", 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 18 +"e:\pycharm_projects\AudioClassification-Pytorch-master\setup.py", "Python", 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11, 55 +"e:\pycharm_projects\AudioClassification-Pytorch-master\tools\download_language_data.sh", "Shell Script", 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 1, 10, 30 +"e:\pycharm_projects\AudioClassification-Pytorch-master\train.py", "Python", 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 31 +"Total", "-", 1509, 24, 629, 45, 322, 20, 215, 4038, 24, 25, 838, 1201, 8890 \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.json b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.json new file mode 100644 index 0000000..922a690 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.json @@ -0,0 +1 @@ +{"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/record_audio.py":{"language":"Python","code":10,"comment":0,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/train.py":{"language":"Python","code":25,"comment":1,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/setup.py":{"language":"Python","code":43,"comment":1,"blank":11},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/requirements.txt":{"language":"pip requirements","code":17,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/README_en.md":{"language":"Markdown","code":231,"comment":0,"blank":45},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/tools/download_language_data.sh":{"language":"Shell Script","code":19,"comment":1,"blank":10},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/infer.py":{"language":"Python","code":17,"comment":1,"blank":6},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/infer_record.py":{"language":"Python","code":40,"comment":7,"blank":12},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/__init__.py":{"language":"Python","code":1,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/extract_features.py":{"language":"Python","code":13,"comment":2,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/README.md":{"language":"Markdown","code":302,"comment":0,"blank":72},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/create_data.py":{"language":"Python","code":75,"comment":9,"blank":16},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/trainer.py":{"language":"Python","code":338,"comment":99,"blank":20},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/optimizer/__init__.py":{"language":"Python","code":26,"comment":0,"blank":7},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/optimizer/scheduler.py":{"language":"Python","code":42,"comment":0,"blank":7},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/predict.py":{"language":"Python","code":124,"comment":47,"blank":7},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/eval.py":{"language":"Python","code":20,"comment":2,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/tdnn.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/resnet_se.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/panns.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/res2net.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/ecapa_tdnn.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/cam%2B%2B.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/eres2net.yml":{"language":"YAML","code":43,"comment":33,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/utils/utils.py":{"language":"Python","code":99,"comment":16,"blank":17},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/metric/metrics.py":{"language":"Python","code":9,"comment":1,"blank":3},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/configs/augmentation.yml":{"language":"YAML","code":21,"comment":21,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/utils/__init__.py":{"language":"Python","code":0,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/utils/record.py":{"language":"Python","code":18,"comment":8,"blank":6},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/metric/__init__.py":{"language":"Python","code":0,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/utils/checkpoint.py":{"language":"Python","code":113,"comment":40,"blank":10},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/start.sh":{"language":"Shell Script","code":26,"comment":3,"blank":8},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/start.bat":{"language":"Batch","code":20,"comment":0,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/README.md":{"language":"Markdown","code":96,"comment":0,"blank":41},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/data_utils/reader.py":{"language":"Python","code":114,"comment":33,"blank":11},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/data_utils/featurizer.py":{"language":"Python","code":88,"comment":36,"blank":9},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/vite.config.js":{"language":"JavaScript","code":32,"comment":0,"blank":2},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/data_utils/collate_fn.py":{"language":"Python","code":17,"comment":4,"blank":3},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/macls/data_utils/__init__.py":{"language":"Python","code":0,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/main.js":{"language":"JavaScript","code":13,"comment":1,"blank":5},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/views/HomePage.vue":{"language":"Vue","code":692,"comment":40,"blank":110},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/backend/config.py":{"language":"Python","code":22,"comment":8,"blank":10},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/App.vue":{"language":"Vue","code":88,"comment":5,"blank":14},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/package.json":{"language":"JSON","code":24,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/index.html":{"language":"HTML","code":25,"comment":0,"blank":2},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/backend/requirements.txt":{"language":"pip requirements","code":7,"comment":0,"blank":1},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/HistoryList.vue":{"language":"Vue","code":513,"comment":25,"blank":79},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/AudioUpload.vue":{"language":"Vue","code":580,"comment":28,"blank":107},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/backend/app.py":{"language":"Python","code":255,"comment":35,"blank":61},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/PredictionResult.vue":{"language":"Vue","code":803,"comment":22,"blank":117},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue":{"language":"Vue","code":811,"comment":48,"blank":162},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/utils/api.js":{"language":"JavaScript","code":156,"comment":25,"blank":33},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/router/index.js":{"language":"JavaScript","code":14,"comment":0,"blank":4},"file:///e%3A/pycharm_projects/AudioClassification-Pytorch-master/audio-classification-platform/frontend/src/components/AudioRecorder.vue":{"language":"Vue","code":551,"comment":38,"blank":102}} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.md new file mode 100644 index 0000000..ac3e4e6 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.md @@ -0,0 +1,50 @@ +# Summary + +Date : 2025-06-10 08:55:17 + +Directory e:\\pycharm_projects\\AudioClassification-Pytorch-master + +Total : 54 files, 6851 codes, 838 comments, 1201 blanks, all 8890 lines + +Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md) + +## Languages +| language | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | +| Vue | 7 | 4,038 | 206 | 691 | 4,935 | +| Python | 25 | 1,509 | 350 | 240 | 2,099 | +| Markdown | 3 | 629 | 0 | 158 | 787 | +| YAML | 8 | 322 | 252 | 40 | 614 | +| JavaScript | 4 | 215 | 26 | 44 | 285 | +| Shell Script | 2 | 45 | 4 | 18 | 67 | +| HTML | 1 | 25 | 0 | 2 | 27 | +| pip requirements | 2 | 24 | 0 | 2 | 26 | +| JSON | 1 | 24 | 0 | 1 | 25 | +| Batch | 1 | 20 | 0 | 5 | 25 | + +## Directories +| path | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | +| . | 54 | 6,851 | 838 | 1,201 | 8,890 | +| . (Files) | 11 | 793 | 23 | 183 | 999 | +| audio-classification-platform | 19 | 4,728 | 278 | 864 | 5,870 | +| audio-classification-platform (Files) | 3 | 142 | 3 | 54 | 199 | +| audio-classification-platform\\backend | 3 | 284 | 43 | 72 | 399 | +| audio-classification-platform\\frontend | 13 | 4,302 | 232 | 738 | 5,272 | +| audio-classification-platform\\frontend (Files) | 3 | 81 | 0 | 5 | 86 | +| audio-classification-platform\\frontend\\src | 10 | 4,221 | 232 | 733 | 5,186 | +| audio-classification-platform\\frontend\\src (Files) | 2 | 101 | 6 | 19 | 126 | +| audio-classification-platform\\frontend\\src\\components | 5 | 3,258 | 161 | 567 | 3,986 | +| audio-classification-platform\\frontend\\src\\router | 1 | 14 | 0 | 4 | 18 | +| audio-classification-platform\\frontend\\src\\utils | 1 | 156 | 25 | 33 | 214 | +| audio-classification-platform\\frontend\\src\\views | 1 | 692 | 40 | 110 | 842 | +| configs | 8 | 322 | 252 | 40 | 614 | +| macls | 15 | 989 | 284 | 104 | 1,377 | +| macls (Files) | 3 | 463 | 146 | 28 | 637 | +| macls\\data_utils | 4 | 219 | 73 | 24 | 316 | +| macls\\metric | 2 | 9 | 1 | 4 | 14 | +| macls\\optimizer | 2 | 68 | 0 | 14 | 82 | +| macls\\utils | 4 | 230 | 64 | 34 | 328 | +| tools | 1 | 19 | 1 | 10 | 30 | + +Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md) \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.txt b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.txt new file mode 100644 index 0000000..8367acc --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.VSCodeCounter/2025-06-10_08-55-17/results.txt @@ -0,0 +1,107 @@ +Date : 2025-06-10 08:55:17 +Directory : e:\pycharm_projects\AudioClassification-Pytorch-master +Total : 54 files, 6851 codes, 838 comments, 1201 blanks, all 8890 lines + +Languages ++------------------+------------+------------+------------+------------+------------+ +| language | files | code | comment | blank | total | ++------------------+------------+------------+------------+------------+------------+ +| Vue | 7 | 4,038 | 206 | 691 | 4,935 | +| Python | 25 | 1,509 | 350 | 240 | 2,099 | +| Markdown | 3 | 629 | 0 | 158 | 787 | +| YAML | 8 | 322 | 252 | 40 | 614 | +| JavaScript | 4 | 215 | 26 | 44 | 285 | +| Shell Script | 2 | 45 | 4 | 18 | 67 | +| HTML | 1 | 25 | 0 | 2 | 27 | +| pip requirements | 2 | 24 | 0 | 2 | 26 | +| JSON | 1 | 24 | 0 | 1 | 25 | +| Batch | 1 | 20 | 0 | 5 | 25 | ++------------------+------------+------------+------------+------------+------------+ + +Directories ++------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+ +| path | files | code | comment | blank | total | ++------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+ +| . | 54 | 6,851 | 838 | 1,201 | 8,890 | +| . (Files) | 11 | 793 | 23 | 183 | 999 | +| audio-classification-platform | 19 | 4,728 | 278 | 864 | 5,870 | +| audio-classification-platform (Files) | 3 | 142 | 3 | 54 | 199 | +| audio-classification-platform\backend | 3 | 284 | 43 | 72 | 399 | +| audio-classification-platform\frontend | 13 | 4,302 | 232 | 738 | 5,272 | +| audio-classification-platform\frontend (Files) | 3 | 81 | 0 | 5 | 86 | +| audio-classification-platform\frontend\src | 10 | 4,221 | 232 | 733 | 5,186 | +| audio-classification-platform\frontend\src (Files) | 2 | 101 | 6 | 19 | 126 | +| audio-classification-platform\frontend\src\components | 5 | 3,258 | 161 | 567 | 3,986 | +| audio-classification-platform\frontend\src\router | 1 | 14 | 0 | 4 | 18 | +| audio-classification-platform\frontend\src\utils | 1 | 156 | 25 | 33 | 214 | +| audio-classification-platform\frontend\src\views | 1 | 692 | 40 | 110 | 842 | +| configs | 8 | 322 | 252 | 40 | 614 | +| macls | 15 | 989 | 284 | 104 | 1,377 | +| macls (Files) | 3 | 463 | 146 | 28 | 637 | +| macls\data_utils | 4 | 219 | 73 | 24 | 316 | +| macls\metric | 2 | 9 | 1 | 4 | 14 | +| macls\optimizer | 2 | 68 | 0 | 14 | 82 | +| macls\utils | 4 | 230 | 64 | 34 | 328 | +| tools | 1 | 19 | 1 | 10 | 30 | ++------------------------------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+ + +Files ++------------------------------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+ +| filename | language | code | comment | blank | total | ++------------------------------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+ +| e:\pycharm_projects\AudioClassification-Pytorch-master\README.md | Markdown | 302 | 0 | 72 | 374 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\README_en.md | Markdown | 231 | 0 | 45 | 276 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\README.md | Markdown | 96 | 0 | 41 | 137 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\app.py | Python | 255 | 35 | 61 | 351 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\config.py | Python | 22 | 8 | 10 | 40 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\backend\requirements.txt | pip requirements | 7 | 0 | 1 | 8 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\index.html | HTML | 25 | 0 | 2 | 27 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\package.json | JSON | 24 | 0 | 1 | 25 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\App.vue | Vue | 88 | 5 | 14 | 107 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder.vue | Vue | 551 | 38 | 102 | 691 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioRecorder_new.vue | Vue | 811 | 48 | 162 | 1,021 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\AudioUpload.vue | Vue | 580 | 28 | 107 | 715 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\HistoryList.vue | Vue | 513 | 25 | 79 | 617 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\components\PredictionResult.vue | Vue | 803 | 22 | 117 | 942 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\main.js | JavaScript | 13 | 1 | 5 | 19 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\router\index.js | JavaScript | 14 | 0 | 4 | 18 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\utils\api.js | JavaScript | 156 | 25 | 33 | 214 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\src\views\HomePage.vue | Vue | 692 | 40 | 110 | 842 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\frontend\vite.config.js | JavaScript | 32 | 0 | 2 | 34 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.bat | Batch | 20 | 0 | 5 | 25 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\audio-classification-platform\start.sh | Shell Script | 26 | 3 | 8 | 37 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\augmentation.yml | YAML | 21 | 21 | 5 | 47 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\cam++.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\ecapa_tdnn.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\eres2net.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\panns.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\res2net.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\resnet_se.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\configs\tdnn.yml | YAML | 43 | 33 | 5 | 81 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\create_data.py | Python | 75 | 9 | 16 | 100 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\eval.py | Python | 20 | 2 | 5 | 27 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\extract_features.py | Python | 13 | 2 | 5 | 20 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\infer.py | Python | 17 | 1 | 6 | 24 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\infer_record.py | Python | 40 | 7 | 12 | 59 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\__init__.py | Python | 1 | 0 | 1 | 2 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\__init__.py | Python | 0 | 0 | 1 | 1 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\collate_fn.py | Python | 17 | 4 | 3 | 24 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\featurizer.py | Python | 88 | 36 | 9 | 133 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\data_utils\reader.py | Python | 114 | 33 | 11 | 158 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\__init__.py | Python | 0 | 0 | 1 | 1 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\metric\metrics.py | Python | 9 | 1 | 3 | 13 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\__init__.py | Python | 26 | 0 | 7 | 33 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\optimizer\scheduler.py | Python | 42 | 0 | 7 | 49 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\predict.py | Python | 124 | 47 | 7 | 178 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\trainer.py | Python | 338 | 99 | 20 | 457 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\__init__.py | Python | 0 | 0 | 1 | 1 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\checkpoint.py | Python | 113 | 40 | 10 | 163 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\record.py | Python | 18 | 8 | 6 | 32 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\macls\utils\utils.py | Python | 99 | 16 | 17 | 132 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\record_audio.py | Python | 10 | 0 | 5 | 15 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\requirements.txt | pip requirements | 17 | 0 | 1 | 18 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\setup.py | Python | 43 | 1 | 11 | 55 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\tools\download_language_data.sh | Shell Script | 19 | 1 | 10 | 30 | +| e:\pycharm_projects\AudioClassification-Pytorch-master\train.py | Python | 25 | 1 | 5 | 31 | +| Total | | 6,851 | 838 | 1,201 | 8,890 | ++------------------------------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+ \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.gitignore b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.gitignore new file mode 100644 index 0000000..92da7e3 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/.gitignore @@ -0,0 +1,296 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST +macls.egg-info/ + +# PyInstaller +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django/Flask stuff +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal +instance/ +.webassets-cache + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +Pipfile.lock + +# PEP 582 +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# Node.js dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +package-lock.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage +.grunt + +# Bower dependency directory +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons +build/Release + +# Dependency directories +jspm_packages/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env.local +.env.production + +# parcel-bundler cache +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt + +# Gatsby files +# Comment in the public line in if your project uses Gatsby +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# Audio Classification specific ignores +# Model files (usually large) +*.pth +*.pt +*.h5 +*.ckpt +*.pb +*.onnx +*.pkl +*.joblib + +# Dataset directories (usually large audio files) +dataset/ +dataset/*/audio/ +dataset/*/wav/ +dataset/*/mp3/ +dataset/*/flac/ +# Uncomment if you want to ignore all audio files +# *.wav +# *.mp3 +# *.flac +# *.ogg +# *.m4a +# *.aac + +# Training artifacts and logs +log/ +logs/ +output/ +outputs/ +uploads/ +results/ +checkpoints/ +models/ +pretrained_models/ +feature_models/ +runs/ +wandb/ +mlruns/ +.mlflow/ + +# Temporary files +temp/ +tmp/ +*.tmp +test*.py + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# IDE files +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Audio processing temporary files +*.spec +*.mfcc +*.mel + +# Frontend build files +audio-classification-platform/frontend/dist/ +audio-classification-platform/frontend/build/ +audio-classification-platform/frontend/.vite/ + +# Uploaded files directory +audio-classification-platform/backend/uploads/ + +# Local development configuration +audio-classification-platform/backend/.env +audio-classification-platform/frontend/.env.local \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/LICENSE b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/README.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/README.md new file mode 100644 index 0000000..0341824 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/README.md @@ -0,0 +1,373 @@ +简体中文 | [English](./README_en.md) + +# 基于Pytorch实现的声音分类系统 + +![python version](https://img.shields.io/badge/python-3.8+-orange.svg) +![GitHub forks](https://img.shields.io/github/forks/yeyupiaoling/AudioClassification-Pytorch) +![GitHub Repo stars](https://img.shields.io/github/stars/yeyupiaoling/AudioClassification-Pytorch) +![GitHub](https://img.shields.io/github/license/yeyupiaoling/AudioClassification-Pytorch) +![支持系统](https://img.shields.io/badge/支持系统-Win/Linux/MAC-9cf) + +# 前言 + +本项目是基于Pytorch的声音分类项目,旨在实现对各种环境声音、动物叫声和语种的识别。项目提供了多种声音分类模型,如EcapaTdnn、PANNS、ResNetSE、CAMPPlus和ERes2Net,以支持不同的应用场景。此外,项目还提供了常用的Urbansound8K数据集测试报告和一些方言数据集的下载和使用例子。用户可以根据自己的需求选择适合的模型和数据集,以实现更准确的声音分类。项目的应用场景广泛,可以用于室外的环境监测、野生动物保护、语音识别等领域。同时,项目也鼓励用户探索更多的使用场景,以推动声音分类技术的发展和应用。 + +**欢迎大家扫码入知识星球或者QQ群讨论,知识星球里面提供项目的模型文件和博主其他相关项目的模型文件,也包括其他一些资源。** + +
+ 知识星球 + QQ群 +
+ + +# 目录 + +- [前言](#前言) +- [项目特性](#项目特性) +- [模型测试表](#模型测试表) +- [安装环境](#安装环境) +- [创建数据](#创建数据) +- [修改预处理方法(可选)](#修改预处理方法可选) +- [提取特征(可选)](#提取特征可选) +- [训练模型](#训练模型) +- [评估模型](#评估模型) +- [预测](#预测) +- [其他功能](#其他功能) + + +# 使用准备 + + - Anaconda 3 + - Python 3.11 + - Pytorch 2.0.1 + - Windows 11 or Ubuntu 22.04 + +# 项目特性 + +1. 支持模型:EcapaTdnn、PANNS、TDNN、Res2Net、ResNetSE、CAMPPlus、ERes2Net +2. 支持池化层:AttentiveStatsPool(ASP)、SelfAttentivePooling(SAP)、TemporalStatisticsPooling(TSP)、TemporalAveragePooling(TAP) +4. 支持预处理方法:MelSpectrogram、Spectrogram、MFCC、Fbank、Wav2vec2.0、WavLM + +**模型论文:** + +- EcapaTdnn:[ECAPA-TDNN: Emphasized Channel Attention, Propagation and Aggregation in TDNN Based Speaker Verification](https://arxiv.org/abs/2005.07143v3) +- PANNS:[PANNs: Large-Scale Pretrained Audio Neural Networks for Audio Pattern Recognition](https://arxiv.org/abs/1912.10211v5) +- TDNN:[Prediction of speech intelligibility with DNN-based performance measures](https://arxiv.org/abs/2203.09148) +- Res2Net:[Res2Net: A New Multi-scale Backbone Architecture](https://arxiv.org/abs/1904.01169) +- ResNetSE:[Squeeze-and-Excitation Networks](https://arxiv.org/abs/1709.01507) +- CAMPPlus:[CAM++: A Fast and Efficient Network for Speaker Verification Using Context-Aware Masking](https://arxiv.org/abs/2303.00332v3) +- ERes2Net:[An Enhanced Res2Net with Local and Global Feature Fusion for Speaker Verification](https://arxiv.org/abs/2305.12838v1) + +# 模型测试表 + +| 模型 | Params(M) | 预处理方法 | 数据集 | 类别数量 | 准确率 | 获取模型 | +|:------------:|:---------:|:-----:|:------------:|:----:|:-------:|:--------:| +| ResNetSE | 7.8 | Flank | UrbanSound8K | 10 | 0.96233 | 加入知识星球获取 | +| ERes2NetV2 | 5.4 | Flank | UrbanSound8K | 10 | 0.95662 | 加入知识星球获取 | +| CAMPPlus | 7.1 | Flank | UrbanSound8K | 10 | 0.95454 | 加入知识星球获取 | +| EcapaTdnn | 6.4 | Flank | UrbanSound8K | 10 | 0.95227 | 加入知识星球获取 | +| ERes2Net | 6.6 | Flank | UrbanSound8K | 10 | 0.94292 | 加入知识星球获取 | +| TDNN | 2.6 | Flank | UrbanSound8K | 10 | 0.93977 | 加入知识星球获取 | +| PANNS(CNN10) | 5.2 | Flank | UrbanSound8K | 10 | 0.92954 | 加入知识星球获取 | +| Res2Net | 5.0 | Flank | UrbanSound8K | 10 | 0.92580 | 加入知识星球获取 | + +**说明:** + +1. 使用的测试集为从数据集中每10条音频取一条,共874条。 + +## 安装环境 + + - 首先安装的是Pytorch的GPU版本,如果已经安装过了,请跳过。 +```shell +conda install pytorch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 pytorch-cuda=11.8 -c pytorch -c nvidia +``` + + - 安装macls库。 + +使用pip安装,命令如下: +```shell +python -m pip install macls -U -i https://pypi.tuna.tsinghua.edu.cn/simple +``` + +**建议源码安装**,源码安装能保证使用最新代码。 +```shell +git clone https://github.com/yeyupiaoling/AudioClassification-Pytorch.git +cd AudioClassification-Pytorch/ +pip install . +``` + +## 创建数据 + +生成数据列表,用于下一步的读取需要,`audio_path`为音频文件路径,用户需要提前把音频数据集存放在`dataset/audio`目录下,每个文件夹存放一个类别的音频数据,每条音频数据长度在3秒以上,如 `dataset/audio/鸟叫声/······`。`audio`是数据列表存放的位置,生成的数据类别的格式为 `音频路径\t音频对应的类别标签`,音频路径和标签用制表符 `\t`分开。读者也可以根据自己存放数据的方式修改以下函数。 + +以Urbansound8K为例,Urbansound8K是目前应用较为广泛的用于自动城市环境声分类研究的公共数据集,包含10个分类:空调声、汽车鸣笛声、儿童玩耍声、狗叫声、钻孔声、引擎空转声、枪声、手提钻、警笛声和街道音乐声。数据集下载地址:[UrbanSound8K.tar.gz](https://aistudio.baidu.com/aistudio/datasetdetail/36625)。以下是针对Urbansound8K生成数据列表的函数。如果读者想使用该数据集,请下载并解压到 `dataset`目录下,把生成数据列表代码改为以下代码。 + +执行`create_data.py`即可生成数据列表,里面提供了生成多种数据集列表方式,具体看代码。 +```shell +python create_data.py +``` + +生成的列表是长这样的,前面是音频的路径,后面是该音频对应的标签,从0开始,路径和标签之间用`\t`隔开。 +```shell +dataset/UrbanSound8K/audio/fold2/104817-4-0-2.wav 4 +dataset/UrbanSound8K/audio/fold9/105029-7-2-5.wav 7 +dataset/UrbanSound8K/audio/fold3/107228-5-0-0.wav 5 +dataset/UrbanSound8K/audio/fold4/109711-3-2-4.wav 3 +``` + +# 修改预处理方法(可选) + +配置文件中默认使用的是Fbank预处理方法,如果要使用其他预处理方法,可以修改配置文件中的安装下面方式修改,具体的值可以根据自己情况修改。如果不清楚如何设置参数,可以直接删除该部分,直接使用默认值。 + +```yaml +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 +``` + +# 提取特征(可选) + +在训练过程中,首先是要读取音频数据,然后提取特征,最后再进行训练。其中读取音频数据、提取特征也是比较消耗时间的,所以我们可以选择提前提取好取特征,训练模型的是就可以直接加载提取好的特征,这样训练速度会更快。这个提取特征是可选择,如果没有提取好的特征,训练模型的时候就会从读取音频数据,然后提取特征开始。提取特征步骤如下: + +1. 执行`extract_features.py`,提取特征,特征会保存在`dataset/features`目录下,并生成新的数据列表`train_list_features.txt`和`test_list_features.txt`。 + +```shell +python extract_features.py --configs=configs/cam++.yml --save_dir=dataset/features +``` + +2. 修改配置文件,将`dataset_conf.train_list`和`dataset_conf.test_list`修改为`train_list_features.txt`和`test_list_features.txt`。 + + +## 训练模型 + +接着就可以开始训练模型了,创建 `train.py`。配置文件里面的参数一般不需要修改,但是这几个是需要根据自己实际的数据集进行调整的,首先最重要的就是分类大小`dataset_conf.num_class`,这个每个数据集的分类大小可能不一样,根据自己的实际情况设定。然后是`dataset_conf.batch_size`,如果是显存不够的话,可以减小这个参数。 + +```shell +# 单卡训练 +CUDA_VISIBLE_DEVICES=0 python train.py +# 多卡训练 +CUDA_VISIBLE_DEVICES=0,1 torchrun --standalone --nnodes=1 --nproc_per_node=2 train.py +``` + +训练输出日志: +``` +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:14 - ----------- 额外配置参数 ----------- +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - configs: configs/ecapa_tdnn.yml +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - local_rank: 0 +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - pretrained_model: None +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - resume_model: None +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - save_model_path: models/ +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - use_gpu: True +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:17 - ------------------------------------------------ +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:19 - ----------- 配置文件参数 ----------- +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:22 - dataset_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - aug_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - noise_aug_prob: 0.2 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - noise_dir: dataset/noise +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - speed_perturb: True +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - volume_aug_prob: 0.2 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - volume_perturb: False +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - dataLoader: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - batch_size: 64 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - num_workers: 4 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - do_vad: False +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - eval_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - batch_size: 1 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - max_duration: 20 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - label_list_path: dataset/label_list.txt +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - max_duration: 3 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - min_duration: 0.5 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - sample_rate: 16000 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - spec_aug_args: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - freq_mask_width: [0, 8] +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - time_mask_width: [0, 10] +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - target_dB: -20 +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - test_list: dataset/test_list.txt +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - train_list: dataset/train_list.txt +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - use_dB_normalization: True +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - use_spec_aug: True +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:22 - model_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - num_class: 10 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - pooling_type: ASP +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:22 - optimizer_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - learning_rate: 0.001 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - optimizer: Adam +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - scheduler: WarmupCosineSchedulerLR +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:25 - scheduler_args: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - max_lr: 0.001 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - min_lr: 1e-05 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - warmup_epoch: 5 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - weight_decay: 1e-06 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:22 - preprocess_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - feature_method: Fbank +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:25 - method_args: +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:27 - num_mel_bins: 80 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:27 - sample_frequency: 16000 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:22 - train_conf: +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:29 - log_interval: 10 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:29 - max_epoch: 30 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:31 - use_model: EcapaTdnn +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:32 - ------------------------------------------------ +[2023-08-07 22:54:22.213166 WARNING] trainer:__init__:67 - Windows系统不支持多线程读取数据,已自动关闭! +========================================================================================== +Layer (type:depth-idx) Output Shape Param # +========================================================================================== +EcapaTdnn [1, 10] -- +├─Conv1dReluBn: 1-1 [1, 512, 98] -- +│ └─Conv1d: 2-1 [1, 512, 98] 204,800 +│ └─BatchNorm1d: 2-2 [1, 512, 98] 1,024 +├─Sequential: 1-2 [1, 512, 98] -- +│ └─Conv1dReluBn: 2-3 [1, 512, 98] -- +│ │ └─Conv1d: 3-1 [1, 512, 98] 262,144 +│ │ └─BatchNorm1d: 3-2 [1, 512, 98] 1,024 +│ └─Res2Conv1dReluBn: 2-4 [1, 512, 98] -- +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +··································· +│ │ └─ModuleList: 3-56 -- (recursive) +│ │ └─ModuleList: 3-55 -- (recursive) +│ │ └─ModuleList: 3-56 -- (recursive) +│ │ └─ModuleList: 3-55 -- (recursive) +│ │ └─ModuleList: 3-56 -- (recursive) +│ └─Conv1dReluBn: 2-13 [1, 512, 98] -- +│ │ └─Conv1d: 3-57 [1, 512, 98] 262,144 +│ │ └─BatchNorm1d: 3-58 [1, 512, 98] 1,024 +│ └─SE_Connect: 2-14 [1, 512, 98] -- +│ │ └─Linear: 3-59 [1, 256] 131,328 +│ │ └─Linear: 3-60 [1, 512] 131,584 +├─Conv1d: 1-5 [1, 1536, 98] 2,360,832 +├─AttentiveStatsPool: 1-6 [1, 3072] -- +│ └─Conv1d: 2-15 [1, 128, 98] 196,736 +│ └─Conv1d: 2-16 [1, 1536, 98] 198,144 +├─BatchNorm1d: 1-7 [1, 3072] 6,144 +├─Linear: 1-8 [1, 192] 590,016 +├─BatchNorm1d: 1-9 [1, 192] 384 +├─Linear: 1-10 [1, 10] 1,930 +========================================================================================== +Total params: 6,188,490 +Trainable params: 6,188,490 +Non-trainable params: 0 +Total mult-adds (M): 470.96 +========================================================================================== +Input size (MB): 0.03 +Forward/backward pass size (MB): 10.28 +Params size (MB): 24.75 +Estimated Total Size (MB): 35.07 +========================================================================================== +[2023-08-07 22:54:26.726095 INFO ] trainer:train:344 - 训练数据:8644 +[2023-08-07 22:54:30.092504 INFO ] trainer:__train_epoch:296 - Train epoch: [1/30], batch: [0/4], loss: 2.57033, accuracy: 0.06250, learning rate: 0.00001000, speed: 19.02 data/sec, eta: 0:06:43 +``` + +**训练可视化:** + +项目的根目录执行下面命令,并网页访问`http://localhost:8040/`,如果是服务器,需要修改`localhost`为服务器的IP地址。 +```shell +visualdl --logdir=log --host=0.0.0.0 +``` + +打开的网页如下: + +
+
+混淆矩阵 +
+ + + +# 评估模型 + +执行下面命令执行评估。 + +```shell +python eval.py --configs=configs/bi_lstm.yml +``` + +评估输出如下: +```shell +[2024-02-03 15:13:25.469242 INFO ] trainer:evaluate:461 - 成功加载模型:models/CAMPPlus_Fbank/best_model/model.pth +100%|██████████████████████████████| 150/150 [00:00<00:00, 1281.96it/s] +评估消耗时间:1s,loss:0.61840,accuracy:0.87333 +``` + +评估会出来输出准确率,还保存了混淆矩阵图片,保存路径`output/images/`,如下。 + +
+
+混淆矩阵 +
+ + +注意:如果类别标签是中文的,需要设置安装字体才能正常显示,一般情况下Windows无需安装,Ubuntu需要安装。如果Windows确实是缺少字体,只需要[字体文件](https://github.com/tracyone/program_font)这里下载`.ttf`格式的文件,复制到`C:\Windows\Fonts`即可。Ubuntu系统操作如下。 + +1. 安装字体 +```shell +git clone https://github.com/tracyone/program_font && cd program_font && ./install.sh +``` + +2. 执行下面Python代码 +```python +import matplotlib +import shutil +import os + +path = matplotlib.matplotlib_fname() +path = path.replace('matplotlibrc', 'fonts/ttf/') +print(path) +shutil.copy('/usr/share/fonts/MyFonts/simhei.ttf', path) +user_dir = os.path.expanduser('~') +shutil.rmtree(f'{user_dir}/.cache/matplotlib', ignore_errors=True) +``` + +# 预测 + +在训练结束之后,我们得到了一个模型参数文件,我们使用这个模型预测音频。 + +```shell +python infer.py --audio_path=dataset/UrbanSound8K/audio/fold5/156634-5-2-5.wav +``` + +# 其他功能 + + - 为了方便读取录制数据和制作数据集,这里提供了录音程序`record_audio.py`,这个用于录制音频,录制的音频采样率为16000,单通道,16bit。 + +```shell +python record_audio.py +``` + + - `infer_record.py`这个程序是用来不断进行录音识别,我们可以大致理解为这个程序在实时录音识别。通过这个应该我们可以做一些比较有趣的事情,比如把麦克风放在小鸟经常来的地方,通过实时录音识别,一旦识别到有鸟叫的声音,如果你的数据集足够强大,有每种鸟叫的声音数据集,这样你还能准确识别是那种鸟叫。如果识别到目标鸟类,就启动程序,例如拍照等等。 + +```shell +python infer_record.py --record_seconds=3 +``` + +## 打赏作者 +
+
+

打赏一块钱支持一下作者

+打赏作者 +
+ +# 参考资料 + +1. https://github.com/PaddlePaddle/PaddleSpeech +2. https://github.com/yeyupiaoling/PaddlePaddle-MobileFaceNets +3. https://github.com/yeyupiaoling/PPASR +4. https://github.com/alibaba-damo-academy/3D-Speaker diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/README_en.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/README_en.md new file mode 100644 index 0000000..43e1e2a --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/README_en.md @@ -0,0 +1,275 @@ +[简体中文](./README.md) | English + +# Sound classification system implemented in Pytorch + +![python version](https://img.shields.io/badge/python-3.8+-orange.svg) +![GitHub forks](https://img.shields.io/github/forks/yeyupiaoling/AudioClassification-Pytorch) +![GitHub Repo stars](https://img.shields.io/github/stars/yeyupiaoling/AudioClassification-Pytorch) +![GitHub](https://img.shields.io/github/license/yeyupiaoling/AudioClassification-Pytorch) +![支持系统](https://img.shields.io/badge/支持系统-Win/Linux/MAC-9cf) + +**Disclaimer, this document was obtained through machine translation, please check the original document [here](./README.md).** + + +# Introduction + +This project is a sound classification project based on Pytorch, aiming to realize the recognition of various environmental sounds, animal calls and languages. Several sound classification models such as EcapaTdnn, PANNS, ResNetSE, CAMPPlus, and ERes2Net are provided to support different application scenarios. In addition, the project also provides the commonly used Urbansound8K dataset test report and some dialect datasets download and use examples. Users can choose suitable models and datasets according to their needs to achieve more accurate sound classification. The project has a wide range of application scenarios, and can be used in outdoor environmental monitoring, wildlife protection, speech recognition and other fields. At the same time, the project also encourages users to explore more usage scenarios to promote the development and application of sound classification technology. + + +# Environment + + - Anaconda 3 + - Python 3.11 + - Pytorch 2.0.1 + - Windows 11 or Ubuntu 22.04 + +# Project Features + +1. Supporting models: EcapaTdnn、PANNS、TDNN、Res2Net、ResNetSE、CAMPPlus、ERes2Net +2. Supporting pooling: AttentiveStatsPool(ASP)、SelfAttentivePooling(SAP)、TemporalStatisticsPooling(TSP)、TemporalAveragePooling(TAP) +3. Support preprocessing methods: MelSpectrogram、Spectrogram、MFCC、Fbank、Wav2vec2.0、WavLM + +**Model Paper:** + +- EcapaTdnn:[ECAPA-TDNN: Emphasized Channel Attention, Propagation and Aggregation in TDNN Based Speaker Verification](https://arxiv.org/abs/2005.07143v3) +- PANNS:[PANNs: Large-Scale Pretrained Audio Neural Networks for Audio Pattern Recognition](https://arxiv.org/abs/1912.10211v5) +- TDNN:[Prediction of speech intelligibility with DNN-based performance measures](https://arxiv.org/abs/2203.09148) +- Res2Net:[Res2Net: A New Multi-scale Backbone Architecture](https://arxiv.org/abs/1904.01169) +- ResNetSE:[Squeeze-and-Excitation Networks](https://arxiv.org/abs/1709.01507) +- CAMPPlus:[CAM++: A Fast and Efficient Network for Speaker Verification Using Context-Aware Masking](https://arxiv.org/abs/2303.00332v3) +- ERes2Net:[An Enhanced Res2Net with Local and Global Feature Fusion for Speaker Verification](https://arxiv.org/abs/2305.12838v1) + +# Model Test + +| Model | Params(M) | Preprocessing method | Dataset | Number Class | Accuracy | +|:------------:|:---------:|:--------------------:|:------------:|:------------:|:--------:| +| ResNetSE | 7.8 | Flank | UrbanSound8K | 10 | 0.96233 | +| ERes2NetV2 | 5.4 | Flank | UrbanSound8K | 10 | 0.95662 | +| CAMPPlus | 7.1 | Flank | UrbanSound8K | 10 | 0.95454 | +| EcapaTdnn | 6.4 | Flank | UrbanSound8K | 10 | 0.95227 | +| ERes2Net | 6.6 | Flank | UrbanSound8K | 10 | 0.94292 | +| TDNN | 2.6 | Flank | UrbanSound8K | 10 | 0.93977 | +| PANNS(CNN10) | 5.2 | Flank | UrbanSound8K | 10 | 0.92954 | +| Res2Net | 5.0 | Flank | UrbanSound8K | 10 | 0.92580 | + +## Installation Environment + + - The GPU version of Pytorch will be installed first, please skip it if you already have it installed. +```shell +conda install pytorch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 pytorch-cuda=11.8 -c pytorch -c nvidia +``` + + - Install macls. + +Install it using pip with the following command: +```shell +python -m pip install macls -U -i https://pypi.tuna.tsinghua.edu.cn/simple +``` + +**Source installation is recommended**, which ensures that the latest code is used. +```shell +git clone https://github.com/yeyupiaoling/AudioClassification_Pytorch.git +cd AudioClassification_Pytorch/ +python setup.py install +``` + +## Preparing Data + +The `audio_path` is the audio file path. The user needs to store the audio dataset in the `dataset/audio` directory in advance. Each folder stores a category of audio data, and the length of each audio data is more than 3 seconds. For example, `dataset/audio/ bird song /······`. `audio` is where the data list is stored, and the format of the generated data category is`audio_path\tcategory_label_audio`, and the audio path and label are separated by a TAB character `\t`. You can also modify the following functions depending on how you store your data: + +Taking Urbansound8K as an example, it is a widely used public dataset for automatic urban environmental sound classification research. Urbansound8K contains 10 categories: air condition sound, car whistle sound, children playing sound, dog bark, drilling sound, engine idling sound, gun sound, jackdrill, siren sound, and street music sound. Data set download address: [UrbanSound8K](https://zenodo.org/record/1203745/files/UrbanSound8K.tar.gz). Here is the function to generate a list of data for Urbansound8K. If you want to use this dataset, please download and unzip it into the `dataset` directory and change the code to generate the list of data as follows. + +`create_data.py` can be used to generate a list of data sets. There are many ways to generate a list of data sets. +```shell +python create_data.py +``` + +The resulting list looks like this, with the path to the audio followed by the tag for that audio, starting at 0, and separated by `\t`. +```shell +dataset/UrbanSound8K/audio/fold2/104817-4-0-2.wav 4 +dataset/UrbanSound8K/audio/fold9/105029-7-2-5.wav 7 +dataset/UrbanSound8K/audio/fold3/107228-5-0-0.wav 5 +dataset/UrbanSound8K/audio/fold4/109711-3-2-4.wav 3 +``` + +# Change preprocessing methods + +By default, the Fbank preprocessing method is used in the configuration file. If you want to use other preprocessing methods, you can modify the following installation in the configuration file, and the specific value can be modified according to your own situation. If it's not clear how to set the parameters, you can remove that section and just use the default values. + +```yaml +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 +``` + +## 训练 + +Now we can train the model. We will create `train.py`. The parameters in the configuration file generally do not need to be modified, but these few need to be adjusted according to your actual dataset. The first and most important is the class size `dataset_conf.num_class`, which may be different for each dataset. Then there is` dataset_conf.batch_size `, which can be reduced if memory is insufficient. + +```shell +# Single GPU training +CUDA_VISIBLE_DEVICES=0 python train.py +# Multi GPU training +CUDA_VISIBLE_DEVICES=0,1 torchrun --standalone --nnodes=1 --nproc_per_node=2 train.py +``` + +Train log: +``` +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:14 - ----------- 额外配置参数 ----------- +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - configs: configs/ecapa_tdnn.yml +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - local_rank: 0 +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - pretrained_model: None +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - resume_model: None +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - save_model_path: models/ +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:16 - use_gpu: True +[2023-08-07 22:54:22.148973 INFO ] utils:print_arguments:17 - ------------------------------------------------ +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:19 - ----------- 配置文件参数 ----------- +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:22 - dataset_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - aug_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - noise_aug_prob: 0.2 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - noise_dir: dataset/noise +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - speed_perturb: True +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - volume_aug_prob: 0.2 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - volume_perturb: False +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - dataLoader: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - batch_size: 64 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - num_workers: 4 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - do_vad: False +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - eval_conf: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - batch_size: 1 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - max_duration: 20 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - label_list_path: dataset/label_list.txt +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - max_duration: 3 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - min_duration: 0.5 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:29 - sample_rate: 16000 +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:25 - spec_aug_args: +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - freq_mask_width: [0, 8] +[2023-08-07 22:54:22.202166 INFO ] utils:print_arguments:27 - time_mask_width: [0, 10] +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - target_dB: -20 +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - test_list: dataset/test_list.txt +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - train_list: dataset/train_list.txt +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - use_dB_normalization: True +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:29 - use_spec_aug: True +[2023-08-07 22:54:22.203167 INFO ] utils:print_arguments:22 - model_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - num_class: 10 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - pooling_type: ASP +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:22 - optimizer_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - learning_rate: 0.001 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - optimizer: Adam +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - scheduler: WarmupCosineSchedulerLR +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:25 - scheduler_args: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - max_lr: 0.001 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - min_lr: 1e-05 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:27 - warmup_epoch: 5 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - weight_decay: 1e-06 +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:22 - preprocess_conf: +[2023-08-07 22:54:22.207167 INFO ] utils:print_arguments:29 - feature_method: Fbank +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:25 - method_args: +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:27 - num_mel_bins: 80 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:27 - sample_frequency: 16000 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:22 - train_conf: +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:29 - log_interval: 10 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:29 - max_epoch: 30 +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:31 - use_model: EcapaTdnn +[2023-08-07 22:54:22.208167 INFO ] utils:print_arguments:32 - ------------------------------------------------ +[2023-08-07 22:54:22.213166 WARNING] trainer:__init__:67 - Windows系统不支持多线程读取数据,已自动关闭! +========================================================================================== +Layer (type:depth-idx) Output Shape Param # +========================================================================================== +EcapaTdnn [1, 10] -- +├─Conv1dReluBn: 1-1 [1, 512, 98] -- +│ └─Conv1d: 2-1 [1, 512, 98] 204,800 +│ └─BatchNorm1d: 2-2 [1, 512, 98] 1,024 +├─Sequential: 1-2 [1, 512, 98] -- +│ └─Conv1dReluBn: 2-3 [1, 512, 98] -- +│ │ └─Conv1d: 3-1 [1, 512, 98] 262,144 +│ │ └─BatchNorm1d: 3-2 [1, 512, 98] 1,024 +│ └─Res2Conv1dReluBn: 2-4 [1, 512, 98] -- +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +│ │ └─ModuleList: 3-15 -- (recursive) +│ │ └─ModuleList: 3-16 -- (recursive) +··································· +│ │ └─ModuleList: 3-56 -- (recursive) +│ │ └─ModuleList: 3-55 -- (recursive) +│ │ └─ModuleList: 3-56 -- (recursive) +│ │ └─ModuleList: 3-55 -- (recursive) +│ │ └─ModuleList: 3-56 -- (recursive) +│ └─Conv1dReluBn: 2-13 [1, 512, 98] -- +│ │ └─Conv1d: 3-57 [1, 512, 98] 262,144 +│ │ └─BatchNorm1d: 3-58 [1, 512, 98] 1,024 +│ └─SE_Connect: 2-14 [1, 512, 98] -- +│ │ └─Linear: 3-59 [1, 256] 131,328 +│ │ └─Linear: 3-60 [1, 512] 131,584 +├─Conv1d: 1-5 [1, 1536, 98] 2,360,832 +├─AttentiveStatsPool: 1-6 [1, 3072] -- +│ └─Conv1d: 2-15 [1, 128, 98] 196,736 +│ └─Conv1d: 2-16 [1, 1536, 98] 198,144 +├─BatchNorm1d: 1-7 [1, 3072] 6,144 +├─Linear: 1-8 [1, 192] 590,016 +├─BatchNorm1d: 1-9 [1, 192] 384 +├─Linear: 1-10 [1, 10] 1,930 +========================================================================================== +Total params: 6,188,490 +Trainable params: 6,188,490 +Non-trainable params: 0 +Total mult-adds (M): 470.96 +========================================================================================== +Input size (MB): 0.03 +Forward/backward pass size (MB): 10.28 +Params size (MB): 24.75 +Estimated Total Size (MB): 35.07 +========================================================================================== +[2023-08-07 22:54:26.726095 INFO ] trainer:train:344 - 训练数据:8644 +[2023-08-07 22:54:30.092504 INFO ] trainer:__train_epoch:296 - Train epoch: [1/30], batch: [0/4], loss: 2.57033, accuracy: 0.06250, learning rate: 0.00001000, speed: 19.02 data/sec, eta: 0:06:43 +``` + +# Eval + +At the end of each training round, we can perform an evaluation, which will output the accuracy. We also save the mixture matrix image, and save the path `output/images/` as follows. +![混合矩阵](docs/images/image1.png) + +# Inference + +At the end of the training, we are given a model parameter file, and we use this model to predict the audio. + +```shell +python infer.py --audio_path=dataset/UrbanSound8K/audio/fold5/156634-5-2-5.wav +``` + +# Other Functions + + - In order to read the recorded data and make a dataset easily, we provide the recording program `record_audio.py`, which is used to record audio with a sample rate of 16,000, single channel, 16bit. + +```shell +python record_audio.py +``` + + - `infer_record.py`This program is used to continuously perform recording recognition, and we can roughly understand this program as recording recognition in real time. And this should allow us to do some interesting things, like put a microphone in a place where birds often come, and recognize it by recording it in real time, and once you recognize that there's a bird calling, if your dataset is powerful enough, and you have a dataset of every bird calling, then you can identify exactly which bird is calling. If the target bird is identified, the procedure is initiated, such as taking photos, etc. + +```shell +python infer_record.py --record_seconds=3 +``` + +# Reference + +1. https://github.com/PaddlePaddle/PaddleSpeech +2. https://github.com/yeyupiaoling/PaddlePaddle-MobileFaceNets +3. https://github.com/yeyupiaoling/PPASR +4. https://github.com/alibaba-damo-academy/3D-Speaker diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/README.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/README.md new file mode 100644 index 0000000..d3ecd35 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/README.md @@ -0,0 +1,136 @@ +# 声纹识别系统 + +这是一个基于深度学习的声纹识别系统,包含Flask后端和Vue前端。 + +## 功能特性 + +- 🎵 支持多种音频格式上传识别 +- 🎤 实时录音识别功能 +- 📊 置信度可视化展示 +- 📱 响应式设计,支持移动端 +- 📝 识别历史记录 +- 📋 结果导出功能 + +## 技术栈 + +### 后端 +- Flask + Flask-CORS +- PyTorch + MAClsPredictor +- librosa + soundfile + +### 前端 +- Vue 3 + Composition API +- Element Plus UI框架 +- Axios HTTP客户端 +- Vite构建工具 + +## 快速开始 + +### 环境要求 + +- Python 3.8+ +- Node.js 16+ +- 已训练好的音频分类模型 + +### 1. 安装后端依赖 + +```bash +cd audio-classification-platform/backend +pip install -r requirements.txt +``` + +### 2. 安装前端依赖 + +```bash +cd audio-classification-platform/frontend +npm install +``` + +### 3. 启动后端服务 + +```bash +cd audio-classification-platform/backend +python app.py +``` + +后端服务将在 http://localhost:5000 启动 + +### 4. 启动前端服务 + +```bash +cd audio-classification-platform/frontend +npm run dev +``` + +前端服务将在 http://localhost:3000 启动 + +## 使用说明 + +1. 打开浏览器访问 http://localhost:3000 +2. 首次使用需要初始化模型(确保模型文件路径正确) +3. 使用文件上传功能或实时录音功能进行音频识别 +4. 查看识别结果和置信度 +5. 可以查看历史识别记录 + +## 配置说明 + +### 后端配置 + +在 `backend/config.py` 中可以配置: + +- 模型路径 +- 上传文件限制 +- GPU使用设置 +- 音频处理参数 + +### 前端配置 + +在 `frontend/vite.config.js` 中可以配置: + +- 开发服务器端口 +- 代理设置 +- 构建选项 + +## API接口 + +- `GET /api/health` - 健康检查 +- `POST /api/init` - 初始化模型 +- `POST /api/upload` - 上传音频文件识别 +- `POST /api/predict` - 录音数据识别 +- `GET /api/labels` - 获取分类标签 +- `GET /api/model/info` - 获取模型信息 + +## 部署 + +### 生产环境构建 + +```bash +# 构建前端 +cd frontend +npm run build + +# 启动后端(推荐使用gunicorn) +cd backend +gunicorn -w 4 -b 0.0.0.0:5000 app:app +``` + +## 故障排除 + +1. **模型初始化失败** + - 检查模型文件路径是否正确 + - 确保配置文件存在 + - 检查GPU驱动(如果使用GPU) + +2. **音频上传失败** + - 检查文件格式是否支持 + - 检查文件大小是否超限 + - 检查网络连接 + +3. **录音功能不可用** + - 检查浏览器麦克风权限 + - 使用HTTPS协议(录音功能需要) + - 检查设备麦克风是否正常 + +## 许可证 + +Apache License 2.0 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/app.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/app.py new file mode 100644 index 0000000..d9e1caa --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/app.py @@ -0,0 +1,350 @@ +import os +import sys +import tempfile +import uuid +from datetime import datetime +from flask import Flask, request, jsonify, send_from_directory +from flask_cors import CORS +from werkzeug.utils import secure_filename +import librosa +import soundfile as sf +import numpy as np +from loguru import logger + +# 添加项目根目录到Python路径 +sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) + +from macls.predict import MAClsPredictor + +app = Flask(__name__) +CORS(app) # 允许跨域请求 + +# 配置 +app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # 最大50MB +app.config['UPLOAD_FOLDER'] = 'uploads' +app.config['ALLOWED_EXTENSIONS'] = {'wav', 'mp3', 'flac', 'm4a', 'ogg', 'aac'} + +# 确保上传目录存在 +os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) + +# 全局预测器实例 +predictor = None + +def allowed_file(filename): + """检查文件扩展名是否被允许""" + return '.' in filename and \ + filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS'] + +def convert_audio_format(input_path, target_sample_rate=16000): + """将音频转换为模型需要的格式""" + try: + # 使用librosa加载音频,自动转换采样率 + audio_data, sr = librosa.load(input_path, sr=target_sample_rate) + + # 创建临时文件 + temp_file = tempfile.NamedTemporaryFile(suffix='.wav', delete=False) + temp_path = temp_file.name + temp_file.close() + + # 保存为wav格式 + sf.write(temp_path, audio_data, target_sample_rate) + + return temp_path, audio_data, target_sample_rate + except Exception as e: + logger.error(f"音频格式转换失败: {str(e)}") + raise e + +@app.route('/api/health', methods=['GET']) +def health_check(): + """健康检查接口""" + return jsonify({ + 'status': 'success', + 'message': '服务正常运行', + 'timestamp': datetime.now().isoformat() + }) + +@app.route('/api/init', methods=['POST']) +def init_model(): + """初始化模型""" + global predictor + try: + data = request.get_json() + + # 默认配置路径 + configs = data.get('configs', '../../configs/cam++.yml') + model_path = data.get('model_path', '../../models/CAMPPlus_Fbank/best_model/') + use_gpu = data.get('use_gpu', True) + + # 转换为绝对路径 + configs = os.path.abspath(os.path.join(os.path.dirname(__file__), configs)) + model_path = os.path.abspath(os.path.join(os.path.dirname(__file__), model_path)) + + if not os.path.exists(configs): + return jsonify({ + 'status': 'error', + 'message': f'配置文件不存在: {configs}' + }), 400 + + if not os.path.exists(model_path): + return jsonify({ + 'status': 'error', + 'message': f'模型路径不存在: {model_path}' + }), 400 + + # 初始化预测器 + predictor = MAClsPredictor( + configs=configs, + model_path=model_path, + use_gpu=use_gpu + ) + + logger.info("模型初始化成功") + + return jsonify({ + 'status': 'success', + 'message': '模型初始化成功', + 'config': { + 'configs': configs, + 'model_path': model_path, + 'use_gpu': use_gpu + } + }) + + except Exception as e: + logger.error(f"模型初始化失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'模型初始化失败: {str(e)}' + }), 500 + +@app.route('/api/upload', methods=['POST']) +def upload_and_predict(): + """上传音频文件并进行预测""" + global predictor + + if predictor is None: + return jsonify({ + 'status': 'error', + 'message': '模型未初始化,请先调用 /api/init 接口' + }), 400 + + if 'file' not in request.files: + return jsonify({ + 'status': 'error', + 'message': '没有上传文件' + }), 400 + + file = request.files['file'] + + if file.filename == '': + return jsonify({ + 'status': 'error', + 'message': '没有选择文件' + }), 400 + + if file and allowed_file(file.filename): + try: + # 生成唯一文件名 + filename = secure_filename(file.filename) + unique_filename = f"{uuid.uuid4()}_{filename}" + filepath = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename) + + # 保存上传的文件 + file.save(filepath) + + # 转换音频格式 + converted_path, audio_data, sample_rate = convert_audio_format(filepath) + + # 进行预测 + start_time = datetime.now() + label, score = predictor.predict(audio_data=converted_path) + end_time = datetime.now() + + # 计算预测时间 + prediction_time = (end_time - start_time).total_seconds() + + # 清理临时文件 + if os.path.exists(converted_path): + os.remove(converted_path) + # 可选:保留原始文件或删除 + # os.remove(filepath) + + logger.info(f"预测完成 - 文件: {filename}, 结果: {label}, 得分: {score:.4f}, 耗时: {prediction_time:.3f}s") + + return jsonify({ + 'status': 'success', + 'result': { + 'predicted_class': label, # 前端期望的字段名 + 'confidence': float(score), # 前端期望的字段名 + 'label': label, # 保持兼容性 + 'score': float(score), # 保持兼容性 + 'filename': filename, + 'prediction_time': prediction_time, + 'audio_info': { + 'sample_rate': sample_rate, + 'duration': len(audio_data) / sample_rate + } + } + }) + + except Exception as e: + logger.error(f"预测失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'预测失败: {str(e)}' + }), 500 + else: + return jsonify({ + 'status': 'error', + 'message': '不支持的文件格式,支持的格式:wav, mp3, flac, m4a, ogg, aac' + }), 400 + +@app.route('/api/predict', methods=['POST']) +def predict_audio_data(): + """直接预测音频数据(用于录音功能)""" + global predictor + + if predictor is None: + return jsonify({ + 'status': 'error', + 'message': '模型未初始化,请先调用 /api/init 接口' + }), 400 + + try: + data = request.get_json() + + if 'audio_data' not in data: + return jsonify({ + 'status': 'error', + 'message': '缺少音频数据' + }), 400 + + audio_data = np.array(data['audio_data'], dtype=np.float32) + sample_rate = data.get('sample_rate', 16000) + + # 创建临时文件 + temp_file = tempfile.NamedTemporaryFile(suffix='.wav', delete=False) + temp_path = temp_file.name + temp_file.close() + + # 保存音频数据 + sf.write(temp_path, audio_data, sample_rate) + + # 进行预测 + start_time = datetime.now() + label, score = predictor.predict(audio_data=temp_path) + end_time = datetime.now() + + prediction_time = (end_time - start_time).total_seconds() + # 清理临时文件 + os.remove(temp_path) + + logger.info(f"录音预测完成 - 结果: {label}, 得分: {score:.4f}, 耗时: {prediction_time:.3f}s") + + return jsonify({ + 'status': 'success', + 'result': { + 'predicted_class': label, # 前端期望的字段名 + 'confidence': float(score), # 前端期望的字段名 + 'label': label, # 保持兼容性 + 'score': float(score), # 保持兼容性 + 'prediction_time': prediction_time, + 'audio_info': { + 'sample_rate': sample_rate, + 'duration': len(audio_data) / sample_rate + } + } + }) + + except Exception as e: + logger.error(f"录音预测失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'录音预测失败: {str(e)}' + }), 500 + +@app.route('/api/labels', methods=['GET']) +def get_labels(): + """获取分类标签列表""" + try: + # 读取标签文件 + label_file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../dataset/label_list.txt')) + + if not os.path.exists(label_file_path): + return jsonify({ + 'status': 'error', + 'message': '标签文件不存在' + }), 404 + + with open(label_file_path, 'r', encoding='utf-8') as f: + labels = [line.strip() for line in f.readlines() if line.strip()] + + return jsonify({ + 'status': 'success', + 'labels': labels, + 'count': len(labels) + }) + + except Exception as e: + logger.error(f"读取标签失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'读取标签失败: {str(e)}' + }), 500 + +@app.route('/api/model/info', methods=['GET']) +def get_model_info(): + """获取模型信息""" + global predictor + + if predictor is None: + return jsonify({ + 'status': 'error', + 'message': '模型未初始化' + }), 400 + + try: + # 获取模型配置信息 + return jsonify({ + 'status': 'success', + 'model_info': { + 'initialized': True, + 'model_type': 'AudioClassification', + 'framework': 'PyTorch' + } + }) + + except Exception as e: + logger.error(f"获取模型信息失败: {str(e)}") + return jsonify({ + 'status': 'error', + 'message': f'获取模型信息失败: {str(e)}' + }), 500 + +@app.errorhandler(413) +def too_large(e): + """文件过大错误处理""" + return jsonify({ + 'status': 'error', + 'message': '文件过大,最大支持50MB' + }), 413 + +@app.errorhandler(404) +def not_found(e): + """404错误处理""" + return jsonify({ + 'status': 'error', + 'message': '接口不存在' + }), 404 + +@app.errorhandler(500) +def internal_error(e): + """500错误处理""" + return jsonify({ + 'status': 'error', + 'message': '服务器内部错误' + }), 500 + +if __name__ == '__main__': + logger.info("启动音频分类API服务器...") + app.run(host='0.0.0.0', port=5000, debug=True) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/config.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/config.py new file mode 100644 index 0000000..039439f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/config.py @@ -0,0 +1,39 @@ +import os +import sys + +# 配置 +class Config: + # 模型配置 + MODEL_CONFIG_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../configs/cam++.yml')) + MODEL_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../models/CAMPPlus_Fbank/best_model/')) + LABEL_FILE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../dataset/label_list.txt')) + + # Flask配置 + SECRET_KEY = 'your-secret-key-here' + MAX_CONTENT_LENGTH = 50 * 1024 * 1024 # 50MB + + # 文件上传配置 + UPLOAD_FOLDER = 'uploads' + ALLOWED_EXTENSIONS = {'wav', 'mp3', 'flac', 'm4a', 'ogg', 'aac'} + + # 音频处理配置 + TARGET_SAMPLE_RATE = 16000 + + # 日志配置 + LOG_LEVEL = 'INFO' + + # GPU配置 + USE_GPU = True + +class DevelopmentConfig(Config): + DEBUG = True + +class ProductionConfig(Config): + DEBUG = False + +# 根据环境变量选择配置 +config = { + 'development': DevelopmentConfig, + 'production': ProductionConfig, + 'default': DevelopmentConfig +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/requirements.txt b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/requirements.txt new file mode 100644 index 0000000..de8b375 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/backend/requirements.txt @@ -0,0 +1,7 @@ +Flask==2.3.3 +Flask-CORS==4.0.0 +librosa==0.10.1 +soundfile==0.12.1 +numpy==1.24.3 +loguru==0.7.2 +Werkzeug==2.3.7 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/index.html b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/index.html new file mode 100644 index 0000000..e8eba15 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/index.html @@ -0,0 +1,26 @@ + + + + + + + 声纹识别系统 + + + +
+ + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/package.json b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/package.json new file mode 100644 index 0000000..39dcbc3 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/package.json @@ -0,0 +1,24 @@ +{ + "name": "audio-classification-frontend", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "serve": "vite preview" + }, "dependencies": { + "vue": "^3.3.4", + "vue-router": "^4.2.4", + "axios": "^1.5.0", + "element-plus": "^2.3.9", + "@element-plus/icons-vue": "^2.1.0", + "echarts": "^5.4.3" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^4.3.4", + "vite": "^4.4.9", + "unplugin-vue-components": "^0.25.2", + "unplugin-auto-import": "^0.16.6" + } +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/App.vue b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/App.vue new file mode 100644 index 0000000..0908a7a --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/App.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder.vue b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder.vue new file mode 100644 index 0000000..887c51f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder.vue @@ -0,0 +1,743 @@ + + + + + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue new file mode 100644 index 0000000..0f6f9b7 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioRecorder_new.vue @@ -0,0 +1,1076 @@ + + + + + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioUpload.vue b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioUpload.vue new file mode 100644 index 0000000..34325b7 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/AudioUpload.vue @@ -0,0 +1,741 @@ + + + + + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/HistoryList.vue b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/HistoryList.vue new file mode 100644 index 0000000..9f6cf9c --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/HistoryList.vue @@ -0,0 +1,635 @@ + + + + + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/PredictionResult.vue b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/PredictionResult.vue new file mode 100644 index 0000000..360a0c4 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/components/PredictionResult.vue @@ -0,0 +1,995 @@ + + + + + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/main.js b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/main.js new file mode 100644 index 0000000..99badf7 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/main.js @@ -0,0 +1,18 @@ +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' +import * as ElementPlusIconsVue from '@element-plus/icons-vue' + +const app = createApp(App) + +// 注册所有图标 +for (const [key, component] of Object.entries(ElementPlusIconsVue)) { + app.component(key, component) +} + +app.use(ElementPlus) +app.use(router) + +app.mount('#app') diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/router/index.js b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/router/index.js new file mode 100644 index 0000000..3109046 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/router/index.js @@ -0,0 +1,17 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomePage from '../views/HomePage.vue' + +const routes = [ + { + path: '/', + name: 'Home', + component: HomePage + } +] + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +export default router diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/utils/api.js b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/utils/api.js new file mode 100644 index 0000000..0db7b1a --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/utils/api.js @@ -0,0 +1,213 @@ +import axios from 'axios' +import { ElMessage } from 'element-plus' + +// 创建axios实例 +const api = axios.create({ + baseURL: '/api', + timeout: 30000, + headers: { + 'Content-Type': 'application/json' + } +}) + +// 请求拦截器 +api.interceptors.request.use( + (config) => { + // 可以在这里添加token等认证信息 + return config + }, + (error) => { + return Promise.reject(error) + } +) + +// 响应拦截器 +api.interceptors.response.use( + (response) => { + return response + }, + (error) => { + let errorMessage = '请求失败' + + if (error.response) { + // 服务器返回错误状态码 + const { status, data } = error.response + + switch (status) { + case 400: + errorMessage = data.message || '请求参数错误' + break + case 401: + errorMessage = '未授权访问' + break + case 403: + errorMessage = '禁止访问' + break + case 404: + errorMessage = '请求的资源不存在' + break + case 413: + errorMessage = '文件过大,最大支持50MB' + break + case 500: + errorMessage = data.message || '服务器内部错误' + break + default: + errorMessage = data.message || `请求失败 (${status})` + } + } else if (error.request) { + // 网络错误 + errorMessage = '网络连接失败,请检查网络设置' + } else { + // 其他错误 + errorMessage = error.message || '未知错误' + } + + // 显示错误消息 + ElMessage.error(errorMessage) + + return Promise.reject(new Error(errorMessage)) + } +) + +// API服务类 +export const apiService = { + // 健康检查 + healthCheck: () => { + return api.get('/health') + }, + + // 初始化模型 + initModel: (config) => { + return api.post('/init', config) + }, + // 上传文件并预测 + uploadAndPredict: (file, onProgress) => { + const formData = new FormData() + formData.append('file', file) + + return api.post('/upload', formData, { + // 不要手动设置 Content-Type,让浏览器自动设置 boundary + onUploadProgress: (progressEvent) => { + if (onProgress && progressEvent.total) { + const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total) + onProgress(percent) + } + } + }) + }, + + // 预测音频数据(录音) + predictAudioData: (audioData) => { + return api.post('/predict', audioData) + }, + + // 获取标签列表 + getLabels: () => { + return api.get('/labels') + }, + + // 获取模型信息 + getModelInfo: () => { + return api.get('/model/info') + } +} + +// 工具函数 +export const utils = { + // 格式化文件大小 + formatFileSize: (bytes) => { + if (bytes === 0) return '0 B' + + const k = 1024 + const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] + const i = Math.floor(Math.log(bytes) / Math.log(k)) + + return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] + }, + + // 格式化时长 + formatDuration: (seconds) => { + if (!seconds) return '0s' + + const hrs = Math.floor(seconds / 3600) + const mins = Math.floor((seconds % 3600) / 60) + const secs = Math.floor(seconds % 60) + + if (hrs > 0) { + return `${hrs}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}` + } else if (mins > 0) { + return `${mins}:${secs.toString().padStart(2, '0')}` + } else { + return `${secs}s` + } + }, + + // 检查音频文件格式 + isAudioFile: (file) => { + const allowedTypes = ['audio/wav', 'audio/mpeg', 'audio/flac', 'audio/m4a', 'audio/ogg', 'audio/aac'] + const allowedExtensions = ['wav', 'mp3', 'flac', 'm4a', 'ogg', 'aac'] + + const fileExtension = file.name.split('.').pop().toLowerCase() + + return allowedTypes.includes(file.type) || allowedExtensions.includes(fileExtension) + }, + + // 检查文件大小 + isFileSizeValid: (file, maxSizeMB = 50) => { + const maxSize = maxSizeMB * 1024 * 1024 + return file.size <= maxSize + }, + + // 生成唯一ID + generateId: () => { + return Date.now().toString(36) + Math.random().toString(36).substr(2) + }, + + // 下载文件 + downloadFile: (content, filename, type = 'application/json') => { + const blob = new Blob([content], { type }) + const url = URL.createObjectURL(blob) + + const link = document.createElement('a') + link.href = url + link.download = filename + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + URL.revokeObjectURL(url) + }, + + // 复制到剪贴板 + copyToClipboard: async (text) => { + try { + await navigator.clipboard.writeText(text) + return true + } catch (error) { + console.error('复制失败:', error) + return false + } + }, + + // 获取音频时长 + getAudioDuration: (file) => { + return new Promise((resolve, reject) => { + const audio = new Audio() + const url = URL.createObjectURL(file) + + audio.addEventListener('loadedmetadata', () => { + URL.revokeObjectURL(url) + resolve(audio.duration) + }) + + audio.addEventListener('error', (error) => { + URL.revokeObjectURL(url) + reject(error) + }) + + audio.src = url + }) + } +} + +export default api diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/views/HomePage.vue b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/views/HomePage.vue new file mode 100644 index 0000000..f313fea --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/src/views/HomePage.vue @@ -0,0 +1,841 @@ + + + + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/vite.config.js b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/vite.config.js new file mode 100644 index 0000000..34b05a8 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/vite.config.js @@ -0,0 +1,33 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import AutoImport from 'unplugin-auto-import/vite' +import Components from 'unplugin-vue-components/vite' +import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' + +export default defineConfig({ + plugins: [ + vue(), + AutoImport({ + resolvers: [ElementPlusResolver()], + }), + Components({ + resolvers: [ElementPlusResolver()], + }), + ], + server: { + port: 3000, + host: '0.0.0.0', + proxy: { + '/api': { + target: 'http://localhost:5000', + changeOrigin: true, + secure: false, + } + } + }, + build: { + outDir: 'dist', + assetsDir: 'assets', + chunkSizeWarningLimit: 1000 + } +}) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/yarn.lock b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/yarn.lock new file mode 100644 index 0000000..47a4043 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/frontend/yarn.lock @@ -0,0 +1,1092 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@antfu/utils@^0.7.5", "@antfu/utils@^0.7.6": + version "0.7.10" + resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.7.10.tgz#ae829f170158e297a9b6a28f161a8e487d00814d" + integrity sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@babel/parser@^7.27.2": + version "7.27.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.4.tgz#f92e89e4f51847be05427285836fc88341c956df" + integrity sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g== + dependencies: + "@babel/types" "^7.27.3" + +"@babel/types@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.27.3.tgz#c0257bedf33aad6aad1f406d35c44758321eb3ec" + integrity sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + +"@ctrl/tinycolor@^3.4.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31" + integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA== + +"@element-plus/icons-vue@^2.1.0", "@element-plus/icons-vue@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz#1f635ad5fdd5c85ed936481525570e82b5a8307a" + integrity sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg== + +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + +"@floating-ui/core@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.0.tgz#1aff27a993ea1b254a586318c29c3b16ea0f4d0a" + integrity sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA== + dependencies: + "@floating-ui/utils" "^0.2.9" + +"@floating-ui/dom@^1.0.1": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.0.tgz#f9f83ee4fee78ac23ad9e65b128fc11a27857532" + integrity sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg== + dependencies: + "@floating-ui/core" "^1.7.0" + "@floating-ui/utils" "^0.2.9" + +"@floating-ui/utils@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.9.tgz#50dea3616bc8191fb8e112283b49eaff03e78429" + integrity sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg== + +"@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7": + version "2.11.7" + resolved "https://registry.yarnpkg.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671" + integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ== + +"@rollup/pluginutils@^5.0.2", "@rollup/pluginutils@^5.0.5", "@rollup/pluginutils@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a" + integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" + +"@types/estree@^1.0.0": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" + integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== + +"@types/lodash-es@^4.17.6": + version "4.17.12" + resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b" + integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*", "@types/lodash@^4.14.182": + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.17.tgz#fb85a04f47e9e4da888384feead0de05f7070355" + integrity sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ== + +"@types/web-bluetooth@^0.0.16": + version "0.0.16" + resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8" + integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ== + +"@vitejs/plugin-vue@^4.3.4": + version "4.6.2" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz#057d2ded94c4e71b94e9814f92dcd9306317aa46" + integrity sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw== + +"@vue/compiler-core@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.16.tgz#2f95f4f17c16c09c57bbf64399075b921506630b" + integrity sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ== + dependencies: + "@babel/parser" "^7.27.2" + "@vue/shared" "3.5.16" + entities "^4.5.0" + estree-walker "^2.0.2" + source-map-js "^1.2.1" + +"@vue/compiler-dom@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz#151d8390252975c0b1a773029220fdfcfaa2d743" + integrity sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ== + dependencies: + "@vue/compiler-core" "3.5.16" + "@vue/shared" "3.5.16" + +"@vue/compiler-sfc@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz#577f7fd42a46fac8357ffed46e8fb34d32698419" + integrity sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw== + dependencies: + "@babel/parser" "^7.27.2" + "@vue/compiler-core" "3.5.16" + "@vue/compiler-dom" "3.5.16" + "@vue/compiler-ssr" "3.5.16" + "@vue/shared" "3.5.16" + estree-walker "^2.0.2" + magic-string "^0.30.17" + postcss "^8.5.3" + source-map-js "^1.2.1" + +"@vue/compiler-ssr@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz#3b7874dff771ab2f85fb09be71f6c76a75fcc5ac" + integrity sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A== + dependencies: + "@vue/compiler-dom" "3.5.16" + "@vue/shared" "3.5.16" + +"@vue/devtools-api@^6.6.4": + version "6.6.4" + resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz#cbe97fe0162b365edc1dba80e173f90492535343" + integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g== + +"@vue/reactivity@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.16.tgz#528c535a088b3c1b67f285f1f2211be79425b962" + integrity sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA== + dependencies: + "@vue/shared" "3.5.16" + +"@vue/runtime-core@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.16.tgz#0a828c322224ada26f81a2e227c3d4aebcb72c7a" + integrity sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ== + dependencies: + "@vue/reactivity" "3.5.16" + "@vue/shared" "3.5.16" + +"@vue/runtime-dom@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.16.tgz#c1bcbcca862b77186f81c92edd5176e74670f078" + integrity sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww== + dependencies: + "@vue/reactivity" "3.5.16" + "@vue/runtime-core" "3.5.16" + "@vue/shared" "3.5.16" + csstype "^3.1.3" + +"@vue/server-renderer@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.16.tgz#5a68cd1d423d843f74c9e6b37133850abab07c13" + integrity sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg== + dependencies: + "@vue/compiler-ssr" "3.5.16" + "@vue/shared" "3.5.16" + +"@vue/shared@3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.16.tgz#d5ea7671182742192938a4b4cbf86ef12bef7418" + integrity sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg== + +"@vueuse/core@^9.1.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4" + integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw== + dependencies: + "@types/web-bluetooth" "^0.0.16" + "@vueuse/metadata" "9.13.0" + "@vueuse/shared" "9.13.0" + vue-demi "*" + +"@vueuse/metadata@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff" + integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ== + +"@vueuse/shared@9.13.0": + version "9.13.0" + resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9" + integrity sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw== + dependencies: + vue-demi "*" + +acorn@^8.14.0: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +async-validator@^4.2.5: + version "4.2.5" + resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339" + integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^1.5.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.9.0.tgz#25534e3b72b54540077d33046f77e3b8d7081901" + integrity sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + +confbox@^0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110" + integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ== + +csstype@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +dayjs@^1.11.13: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + +debug@^4.3.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +echarts@^5.4.3: + version "5.6.0" + resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.6.0.tgz#2377874dca9fb50f104051c3553544752da3c9d6" + integrity sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA== + dependencies: + tslib "2.3.0" + zrender "5.6.1" + +element-plus@^2.3.9: + version "2.9.11" + resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-2.9.11.tgz#c939a8d945330f596b7a35aae0e501ea170874a2" + integrity sha512-x4L/6YC8de4JtuE3vpaEugJdQIeHQaHtIYKyk67IeF6dTIiVax45aX4nWOygnh+xX+0gTvL6xO+9BZhPA3G82w== + dependencies: + "@ctrl/tinycolor" "^3.4.1" + "@element-plus/icons-vue" "^2.3.1" + "@floating-ui/dom" "^1.0.1" + "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7" + "@types/lodash" "^4.14.182" + "@types/lodash-es" "^4.17.6" + "@vueuse/core" "^9.1.0" + async-validator "^4.2.5" + dayjs "^1.11.13" + escape-html "^1.0.3" + lodash "^4.17.21" + lodash-es "^4.17.21" + lodash-unified "^1.0.2" + memoize-one "^6.0.0" + normalize-wheel-es "^1.2.0" + +entities@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +esbuild@^0.18.10: + version "0.18.20" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +exsolve@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.5.tgz#1f5b6b4fe82ad6b28a173ccb955a635d77859dcf" + integrity sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg== + +fast-glob@^3.3.0, fast-glob@^3.3.1, fast-glob@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + +form-data@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c" + integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + mime-types "^2.1.12" + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +js-tokens@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4" + integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== + +local-pkg@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963" + integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g== + +local-pkg@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.1.tgz#69658638d2a95287534d4c2fff757980100dbb6d" + integrity sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ== + dependencies: + mlly "^1.7.3" + pkg-types "^1.2.1" + +local-pkg@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.1.tgz#f5fe74a97a3bd3c165788ee08ca9fbe998dc58dd" + integrity sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg== + dependencies: + mlly "^1.7.4" + pkg-types "^2.0.1" + quansync "^0.2.8" + +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash-unified@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/lodash-unified/-/lodash-unified-1.0.3.tgz#80b1eac10ed2eb02ed189f08614a29c27d07c894" + integrity sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +magic-string@^0.30.1, magic-string@^0.30.17, magic-string@^0.30.5: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimatch@^9.0.3: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +mlly@^1.7.3, mlly@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.4.tgz#3d7295ea2358ec7a271eaa5d000a0f84febe100f" + integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw== + dependencies: + acorn "^8.14.0" + pathe "^2.0.1" + pkg-types "^1.3.0" + ufo "^1.5.4" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-wheel-es@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz#0fa2593d619f7245a541652619105ab076acf09e" + integrity sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +pathe@^2.0.1, pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +pkg-types@^1.2.1, pkg-types@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" + integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== + dependencies: + confbox "^0.1.8" + mlly "^1.7.4" + pathe "^2.0.1" + +pkg-types@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-2.1.0.tgz#70c9e1b9c74b63fdde749876ee0aa007ea9edead" + integrity sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A== + dependencies: + confbox "^0.2.1" + exsolve "^1.0.1" + pathe "^2.0.3" + +postcss@^8.4.27, postcss@^8.5.3: + version "8.5.4" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.4.tgz#d61014ac00e11d5f58458ed7247d899bd65f99c0" + integrity sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +quansync@^0.2.8: + version "0.2.10" + resolved "https://registry.yarnpkg.com/quansync/-/quansync-0.2.10.tgz#32053cf166fa36511aae95fc49796116f2dc20e1" + integrity sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +resolve@^1.22.2: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +rollup@^3.27.1: + version "3.29.5" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54" + integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w== + optionalDependencies: + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +scule@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/scule/-/scule-1.3.0.tgz#6efbd22fd0bb801bdcc585c89266a7d2daa8fbd3" + integrity sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +strip-literal@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.1.1.tgz#26906e65f606d49f748454a08084e94190c2e5ad" + integrity sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q== + dependencies: + js-tokens "^9.0.1" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tslib@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + +ufo@^1.5.4: + version "1.6.1" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" + integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== + +unimport@^3.4.0: + version "3.14.6" + resolved "https://registry.yarnpkg.com/unimport/-/unimport-3.14.6.tgz#f01170aa2fb94c4f97b22c0ac2822ef7e8e0726d" + integrity sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g== + dependencies: + "@rollup/pluginutils" "^5.1.4" + acorn "^8.14.0" + escape-string-regexp "^5.0.0" + estree-walker "^3.0.3" + fast-glob "^3.3.3" + local-pkg "^1.0.0" + magic-string "^0.30.17" + mlly "^1.7.4" + pathe "^2.0.1" + picomatch "^4.0.2" + pkg-types "^1.3.0" + scule "^1.3.0" + strip-literal "^2.1.1" + unplugin "^1.16.1" + +unplugin-auto-import@^0.16.6: + version "0.16.7" + resolved "https://registry.yarnpkg.com/unplugin-auto-import/-/unplugin-auto-import-0.16.7.tgz#f4f1f7ab3fba24129bc38e47f83782684030d6e4" + integrity sha512-w7XmnRlchq6YUFJVFGSvG1T/6j8GrdYN6Em9Wf0Ye+HXgD/22kont+WnuCAA0UaUoxtuvRR1u/mXKy63g/hfqQ== + dependencies: + "@antfu/utils" "^0.7.6" + "@rollup/pluginutils" "^5.0.5" + fast-glob "^3.3.1" + local-pkg "^0.5.0" + magic-string "^0.30.5" + minimatch "^9.0.3" + unimport "^3.4.0" + unplugin "^1.5.0" + +unplugin-vue-components@^0.25.2: + version "0.25.2" + resolved "https://registry.yarnpkg.com/unplugin-vue-components/-/unplugin-vue-components-0.25.2.tgz#99d9d02a4066a24e720edbe74a82a4ee6ff86153" + integrity sha512-OVmLFqILH6w+eM8fyt/d/eoJT9A6WO51NZLf1vC5c1FZ4rmq2bbGxTy8WP2Jm7xwFdukaIdv819+UI7RClPyCA== + dependencies: + "@antfu/utils" "^0.7.5" + "@rollup/pluginutils" "^5.0.2" + chokidar "^3.5.3" + debug "^4.3.4" + fast-glob "^3.3.0" + local-pkg "^0.4.3" + magic-string "^0.30.1" + minimatch "^9.0.3" + resolve "^1.22.2" + unplugin "^1.4.0" + +unplugin@^1.16.1, unplugin@^1.4.0, unplugin@^1.5.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.16.1.tgz#a844d2e3c3b14a4ac2945c42be80409321b61199" + integrity sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w== + dependencies: + acorn "^8.14.0" + webpack-virtual-modules "^0.6.2" + +vite@^4.4.9: + version "4.5.14" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.14.tgz#2e652bc1d898265d987d6543ce866ecd65fa4086" + integrity sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g== + dependencies: + esbuild "^0.18.10" + postcss "^8.4.27" + rollup "^3.27.1" + optionalDependencies: + fsevents "~2.3.2" + +vue-demi@*: + version "0.14.10" + resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04" + integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg== + +vue-router@^4.2.4: + version "4.5.1" + resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.5.1.tgz#47bffe2d3a5479d2886a9a244547a853aa0abf69" + integrity sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw== + dependencies: + "@vue/devtools-api" "^6.6.4" + +vue@^3.3.4: + version "3.5.16" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.16.tgz#f0cde88c2688354f00ff2d77eb295c26440f8c7a" + integrity sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w== + dependencies: + "@vue/compiler-dom" "3.5.16" + "@vue/compiler-sfc" "3.5.16" + "@vue/runtime-dom" "3.5.16" + "@vue/server-renderer" "3.5.16" + "@vue/shared" "3.5.16" + +webpack-virtual-modules@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8" + integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ== + +zrender@5.6.1: + version "5.6.1" + resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.6.1.tgz#e08d57ecf4acac708c4fcb7481eb201df7f10a6b" + integrity sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag== + dependencies: + tslib "2.3.0" diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/start.bat b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/start.bat new file mode 100644 index 0000000..8094d48 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/start.bat @@ -0,0 +1,24 @@ +@echo off +echo ================================ +echo 声纹识别系统启动脚本 +echo ================================ +echo. + +echo 正在启动后端服务... +cd /d "%~dp0backend" +start "后端服务" cmd /k "python app.py" + +echo 等待后端服务启动... +timeout /t 3 /nobreak >nul + +echo 正在启动前端服务... +cd /d "%~dp0frontend" +start "前端服务" cmd /k "npm run dev" + +echo. +echo 启动完成! +echo 后端服务: http://localhost:5000 +echo 前端服务: http://localhost:3000 +echo. +echo 请等待服务完全启动后访问前端地址 +pause diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/start.sh b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/start.sh new file mode 100644 index 0000000..06674da --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/audio-classification-platform/start.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +echo "================================" +echo " 声纹识别系统启动脚本" +echo "================================" +echo + +# 获取脚本所在目录 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +echo "正在启动后端服务..." +cd "$SCRIPT_DIR/backend" +python app.py & +BACKEND_PID=$! + +echo "等待后端服务启动..." +sleep 3 + +echo "正在启动前端服务..." +cd "$SCRIPT_DIR/frontend" +npm run dev & +FRONTEND_PID=$! + +echo +echo "启动完成!" +echo "后端服务: http://localhost:5000" +echo "前端服务: http://localhost:3000" +echo +echo "后端进程 PID: $BACKEND_PID" +echo "前端进程 PID: $FRONTEND_PID" +echo +echo "按 Ctrl+C 停止所有服务" + +# 等待用户中断 +trap 'echo "正在停止服务..."; kill $BACKEND_PID $FRONTEND_PID; exit' INT +wait diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/augmentation.yml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/augmentation.yml new file mode 100644 index 0000000..5ffe3c5 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/augmentation.yml @@ -0,0 +1,46 @@ +# 语速增强 +speed: + # 增强概率 + prob: 1.0 + +# 音量增强 +volume: + # 增强概率 + prob: 0.0 + # 最小增益 + min_gain_dBFS: -15 + # 最大增益 + max_gain_dBFS: 15 + +# 噪声增强 +noise: + # 增强概率 + prob: 0.5 + # 噪声增强的噪声文件夹 + noise_dir: 'dataset/noise' + # 针对噪声的最小音量增益 + min_snr_dB: 10 + # 针对噪声的最大音量增益 + max_snr_dB: 50 + +# 混响增强 +reverb: + # 增强概率 + prob: 0.5 + # 混响增强的混响文件夹 + reverb_dir: 'dataset/reverb' + +# Spec增强 +spec_aug: + # 增强概率 + prob: 0.5 + # 频域掩蔽的比例 + freq_mask_ratio: 0.1 + # 频域掩蔽次数 + n_freq_masks: 1 + # 频域掩蔽的比例 + time_mask_ratio: 0.05 + # 频域掩蔽次数 + n_time_masks: 1 + # 最大时间扭曲 + max_time_warp: 0 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/cam++.yml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/cam++.yml new file mode 100644 index 0000000..ce68da9 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/cam++.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 64 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 8 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'CAMPPlus' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/ecapa_tdnn.yml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/ecapa_tdnn.yml new file mode 100644 index 0000000..6c13e50 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/ecapa_tdnn.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 128 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 16 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'EcapaTdnn' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/eres2net.yml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/eres2net.yml new file mode 100644 index 0000000..6bc1170 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/eres2net.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 32 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 4 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型,支持ERes2Net、ERes2NetV2 + model: 'ERes2Net' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/panns.yml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/panns.yml new file mode 100644 index 0000000..5d000f1 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/panns.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 64 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 8 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: +# 所使用的模型,支持PANNS_CNN6、PANNS_CNN10、PANNS_CNN14 + model: 'PANNS_CNN10' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/res2net.yml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/res2net.yml new file mode 100644 index 0000000..072e2e4 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/res2net.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 32 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 4 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'Res2Net' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/resnet_se.yml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/resnet_se.yml new file mode 100644 index 0000000..5af006d --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/resnet_se.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 32 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 4 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'ResNetSE' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/tdnn.yml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/tdnn.yml new file mode 100644 index 0000000..9cd3d2a --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/configs/tdnn.yml @@ -0,0 +1,80 @@ +# 数据集参数 +dataset_conf: + dataset: + # 过滤最短的音频长度 + min_duration: 0.4 + # 最长的音频长度,大于这个长度会裁剪掉 + max_duration: 3 + # 音频的采样率 + sample_rate: 16000 + # 是否对音频进行音量归一化 + use_dB_normalization: True + # 对音频进行音量归一化的音量分贝值 + target_dB: -20 + dataLoader: + # 训练的批量大小 + batch_size: 64 + # 是否丢弃最后一个样本 + drop_last: True + # 读取数据的线程数量 + num_workers: 8 + # 评估的数据要特殊处理 + eval_conf: + # 评估的批量大小 + batch_size: 8 + # 最长的音频长度 + max_duration: 20 + # 训练数据的数据列表路径 + train_list: 'dataset/train_list.txt' + # 测试数据的数据列表路径 + test_list: 'dataset/test_list.txt' + # 标签列表 + label_list_path: 'dataset/label_list.txt' + +# 数据预处理参数 +preprocess_conf: + # 是否使用HF上的Wav2Vec2类似模型提取音频特征 + use_hf_model: False + # 音频预处理方法,也可以叫特征提取方法 + # 当use_hf_model为False时,支持:MelSpectrogram、Spectrogram、MFCC、Fbank + # 当use_hf_model为True时,指定的是HuggingFace的模型或者本地路径,比如facebook/w2v-bert-2.0或者./feature_models/w2v-bert-2.0 + feature_method: 'Fbank' + # 当use_hf_model为False时,设置API参数,更参数查看对应API,不清楚的可以直接删除该部分,直接使用默认值。 + # 当use_hf_model为True时,可以设置参数use_gpu,指定是否使用GPU提取特征 + method_args: + sample_frequency: 16000 + num_mel_bins: 80 + +model_conf: + # 所使用的模型 + model: 'TDNN' + # 模型参数 + model_args: + # 分类大小,如果为null,自动通过标签列表获取 + num_class: null + +optimizer_conf: + # 优化方法 + optimizer: 'Adam' + # 优化方法参数 + optimizer_args: + lr: 0.001 + weight_decay: !!float 1e-5 + # 学习率衰减函数,支持Pytorch支持的和项目提供的WarmupCosineSchedulerLR + scheduler: 'WarmupCosineSchedulerLR' + # 学习率衰减函数参数 + scheduler_args: + min_lr: !!float 1e-5 + max_lr: 0.001 + warmup_epoch: 5 + +train_conf: + # 是否开启自动混合精度 + enable_amp: False + # 是否使用Pytorch2.0的编译器 + use_compile: False + # CrossEntropyLoss类的label_smoothing参数 + label_smoothing: 0.0 + # 训练的轮数 + max_epoch: 60 + log_interval: 10 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/create_data.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/create_data.py new file mode 100644 index 0000000..da73e90 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/create_data.py @@ -0,0 +1,99 @@ +import os + + +# 生成数据列表 +def get_data_list(audio_path, list_path): + sound_sum = 0 + audios = os.listdir(audio_path) + os.makedirs(list_path, exist_ok=True) + f_train = open(os.path.join(list_path, 'train_list.txt'), 'w', encoding='utf-8') + f_test = open(os.path.join(list_path, 'test_list.txt'), 'w', encoding='utf-8') + f_label = open(os.path.join(list_path, 'label_list.txt'), 'w', encoding='utf-8') + + for i in range(len(audios)): + f_label.write(f'{audios[i]}\n') + sounds = os.listdir(os.path.join(audio_path, audios[i])) + for sound in sounds: + sound_path = os.path.join(audio_path, audios[i], sound).replace('\\', '/') + if sound_sum % 10 == 0: + f_test.write(f'{sound_path}\t{i}\n') + else: + f_train.write(f'{sound_path}\t{i}\n') + sound_sum += 1 + print(f"Audio:{i + 1}/{len(audios)}") + f_label.close() + f_test.close() + f_train.close() + + +# 下载数据方式,执行:./tools/download_3dspeaker_data.sh +# 生成生成方言数据列表 +def get_language_identification_data_list(audio_path, list_path): + labels_dict = {0: 'Standard Mandarin', 3: 'Southwestern Mandarin', 6: 'Central Plains Mandarin', + 4: 'JiangHuai Mandarin', 2: 'Wu dialect', 8: 'Gan dialect', 9: 'Jin dialect', + 11: 'LiaoJiao Mandarin', 12: 'JiLu Mandarin', 10: 'Min dialect', 7: 'Yue dialect', + 5: 'Hakka dialect', 1: 'Xiang dialect', 13: 'Northern Mandarin'} + + with open(os.path.join(list_path, 'train_list.txt'), 'w', encoding='utf-8') as f: + train_dir = os.path.join(audio_path, 'train') + for root, dirs, files in os.walk(train_dir): + for file in files: + if not file.endswith('.wav'): continue + label = int(file.split('_')[-1].replace('.wav', '')[-2:]) + file = os.path.join(root, file) + f.write(f'{file}\t{label}\n') + + with open(os.path.join(list_path, 'test_list.txt'), 'w', encoding='utf-8') as f: + test_dir = os.path.join(audio_path, 'test') + for root, dirs, files in os.walk(test_dir): + for file in files: + if not file.endswith('.wav'): continue + label = int(file.split('_')[-1].replace('.wav', '')[-2:]) + file = os.path.join(root, file) + f.write(f'{file}\t{label}\n') + + with open(os.path.join(list_path, 'label_list.txt'), 'w', encoding='utf-8') as f: + for i in range(len(labels_dict)): + f.write(f'{labels_dict[i]}\n') + + +# 创建UrbanSound8K数据列表 +def create_UrbanSound8K_list(audio_path, metadata_path, list_path): + sound_sum = 0 + + f_train = open(os.path.join(list_path, 'train_list.txt'), 'w', encoding='utf-8') + f_test = open(os.path.join(list_path, 'test_list.txt'), 'w', encoding='utf-8') + f_label = open(os.path.join(list_path, 'label_list.txt'), 'w', encoding='utf-8') + + with open(metadata_path) as f: + lines = f.readlines() + + labels = {} + for i, line in enumerate(lines): + if i == 0:continue + data = line.replace('\n', '').split(',') + class_id = int(data[6]) + if class_id not in labels.keys(): + labels[class_id] = data[-1] + sound_path = os.path.join(audio_path, f'fold{data[5]}', data[0]).replace('\\', '/') + if sound_sum % 10 == 0: + f_test.write(f'{sound_path}\t{data[6]}\n') + else: + f_train.write(f'{sound_path}\t{data[6]}\n') + sound_sum += 1 + for i in range(len(labels)): + f_label.write(f'{labels[i]}\n') + f_label.close() + f_test.close() + f_train.close() + + +if __name__ == '__main__': + # get_data_list('dataset/audio', 'dataset') + # 生成生成方言数据列表 + # get_language_identification_data_list(audio_path='dataset/language', + # list_path='dataset/') + # 创建UrbanSound8K数据列表 + create_UrbanSound8K_list(audio_path='dataset/UrbanSound8K/audio', + metadata_path='dataset/UrbanSound8K/metadata/UrbanSound8K.csv', + list_path='dataset') diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/docs/images/image1.png b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/docs/images/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..6bba58a14c8d2e9aea2a11ea36b75a8c7e2c3d40 GIT binary patch literal 69600 zcmeFZcT`mS)+LHL9mGJ8EE1F~S&*P2p~z7vq6!6)6)18#Dq=uF0YwItB&kqx#z-oH zWXUSAiX=J1Tbpz4y?y)pzV7k5Uyt`s*En}rx7f9J?O#}Ht~ux0&$Kj@D33E7r=Xyq zL@D3Yp`bYUj)LOA`J;#76OkYB`{5r+R|P{?T_-D7_dCuQ3iUg#_wAir?QQO!cf&Zl z*f=?g2wV{m<~x7S)%CuMl%Sx)KMxRaa<&#czq#`TPIBzNGTMcLg6azWZ(9_?kn{Q2w)x!lWDGQ!XlQ{A4xr*S0@)J+x_8lS~S2@C{qvskP za>?ym;30RK>k8D@uaS6;9)0*>KdslrR5i&OIpMRq4L5b3G;JErrX!u3jg8H`b+E$S$)UekU9j@^!y*4&UonS1QS(-Vu#F`W zJ29X7?AeI1sWqZtO?^He8lU#;?8Wi&9l4z~d5hZMHax%a!mA<}A5Wt8cS`tIq0Tzl zH@#+ed+zv&6S{e3ReB|krkocqPW3z0bp8JMdAUPVj`UJus6N`|A_vF4!E&tE1}Q`A z_J;r;Nu?+r{m8JeS7BjcKACbCPX@`;37CAlnC$b$aj-nCU&4LXBrqt5S4e1Huxq=H z)&Jh~_xD*wMOh5u_LHj*V06aJrC4F#I-Wvyu;(xT-OXgLrODSk`dRnBKBsy9@}>G< zPmRC-OmBfwvhNDII&t^=dkb9Z8BUeaen~!}j)#Xwbysr4yLXqxoQ6zxcUEge4!s+1 zj?V~TzDoW~CC3+5Y*KpvdU$yFaY{=5u*H280Y7S~Z%|N#UF1@Wd9^svIyF-=tU*_~ zkcloxKYWrYW@BK?nFOIr_a%cEH7#v=mVP!lGb2d{UgaZMw{o*I5~WDU&|rH^Gk*WR zub*dTI#;!7W*aMHQTtXUiU*ha^K%d}pHDy6NMEP1^Xl-b%}aU_MLZ_0zu3N4xaeNn z4NjFvEj_(R+pes%j3h4}tiPMx?Oen6HzWpKBc9Xnro-*MRgD(tD|4~NPxKd9hr-0B zARl_n|0>_z*~I?*6gX}E{SU8|>C9HSU6TyWWR1aMn+~q+1)?Cix4=4m;i6_z=es+f z_43SQ6ciM=xwsT(`b&C3<#u9>ti~Fn%2)dAI8m#^{{CdWo91%H#rB!y*eUYnTuo22 z#Bff1eSK#S=LmygmG|l`7~}Mv5{Ld<1||;zVF^>!Y(lpBA&*4t(Px^n>o>cy4SHaO zOd72FZEuizt&{afYF~yhaC+OO7$F8>%ctE0(`;A(cCgE08{Mb6)hAjKJ6;G@zl9ZPvohVw zaMdkmc%~ArW(hlTV=|@FVR5{y$nGlEMqDF-IguD{r! zd<<`_^9a>r;_?y>yNL3dd>yp3vpF}ly*i8xS%Oh3?6b~lUvDw{?^^KFyK+m0;xL=( z>hbBqn8vs6b3@J*gSgZlbAMA<_i0v5F|T>^D%E|8#F5(5UYL)S z*!SM$h=tKi>zB3vewn=?$MF3HtTAl2V2%Qa3Y`v0p)6u|?%c7O{PsGtAJ+XYJ!*U` z+FZlHdTyvn9S#&Oy0bLd#x;}nEs|R|n8O9Oo_+t!)w+tg>iF{9JD;DV+xO;=e|dH` zv)^xPUdf`MR}D75aN^vbM_7~%ta}Ki>X|xe`7+jhe$>3Tn$B4?4ezW-xNOdpFj@pZ zs2EK5SzoY%lcK8+KYRA9cE-(`tYl~yLoeZILM~R17srs}Tlq@{;5N_&R+zFmys;yy zWCmv9GOlT{RnBQ;rr-L_n>S5~?nAK_tdPp{ygBrhWJ%Wkk@?@JltIzL`3Xjm$Zrxe>ydBkcgfhjt zP*wvUAD{9W`b}r}va$|gqy4q~5g0hTj}H&UU3DiAs#f~c^3p=9hor4u3wc6OkQkFI)kea?S3+t{f}->GK17)e&* z4t;O+vv0+ko%Mh8Z0BicXb;4MyuKp4snJAS;4n&ua#s6S@JH z)rARm9jy;n+gzO;%!Y$dDzW=7a(5)|hv?0RB15W6D#})T$spx29$f4=7*{^??X|p7 z>HRz9&TvGNtNrIEl$=OpM0YbYGG;%aWVCHbkRpkN(P)?h&v9vm2?@OY`Hqui9|>18FE`nkYWf^Cc(6VJYUD!6L^Ad zsn0Htl$A|TDS5hH`e3BcYuOe%{asr>ORudhMQIt9SJvIH&uw9=7cbXrEf8&otE=L~ z?9!`!H+k6Du8UYTX#v_2gZL^vrKAWuu2p(bEo4jzOHO?-QcHr6jijo#u$XLMLbJ@O zyvm)$Y&*4{o#7O<>*j;)lWq9^Zu!o}6bwL-Ns%2)l-F{Xftc6QJu$}tL)_AA#atGw zQ5c9wzz|{C8!#>$!cdl6V<{gAxmt*wx&=wjzvGRGYsh7eh8y=kj7jtjXi?PTlZry-JUH`zfcctSG#IX%?ISNx@wZ*|DD~CGIuH ziItt)84UuYp&}o2vJ2T_e;znOhH&-`L4E*P(s=34oOuINQ}0+Z6|Th6hNNIv(qm*3 zBzqp9l70oNkVMJ=nBfP(*XGBEKjTDgaNT+4$rra_M}GV&T!t2+hJk?BrQ4SOJC&Kz z9SI7G1snt|R{yQnlau$*c>V9qkRL9&)}Bke>aJm6=9y++OcV@a6B5#HXlOX()$;9| z7KC5ANy&XCOi(l`G$LPx8>4X(fgiNLC9h^D3kHhTO~jcKzI6KZ=|g@)uo)Q%9Z%zUv(2o~)pgwa(=X-O5fkuWd1Q$&BTy|bEtPGy^ z?MR)C4LImfv$u-ei;&wSyLU^v$CIj)q&;=Ivh-D}G|CgGUB{zZ0YXG2B&boGIC>tc zS8DF+S5X+Wf>Z#M1Q*!ZY0jS2O%*Ini}V+G_&V=nyC%2C2AnVHpXZZG)IgO_=e<0h zwOt#tUy>?dplpll+Fv#F`L}z>8E*30HH+hH$nc+kMYFVUN{#*Cek%HZR?UCU$bJU+ zs2;)E@Pcajz+TaP>f3Rt11GNiVEgO;BK6}RdzJTJNBrw7|Ej%XZX88UarB-V+reu{ z+D2Y`XNP~Gnum{&9f7<~ef#@@2Swqdus;u-zZA%rqOFlp%*9F4yZdH^lgk$0k;(hA z0c+ahDZO!C5?#Z^MTWn?0XD%Mne|L$=W{9h1fr`^D(&H4ZZa>jY#Q|cc^(&b-frn0 z+Q6KjS6JuP*XQ{gD^Y&CGOO4`DNeg@=h0nR4bPt{dooEIO8H7nEmXLnbTb;sy}Gwd z671b7;J-ru-Lxg-K1we^Tz;q#BV-hpkdrass6d~h=^(ysg(lCq*_rC#vb?1Idb&Q( zbT5orVplv|zvV9lHm6^<5N)67?rCUv-okYX8z^KHn~)Q2DxiN^(Y)W@$gzN1TgR!y zSpV22*Iml<({!0KfLf8JP1^u1WXHT&skPoX}ZxwCS5S zF^W=5JiH`qMn|3(&$$$XL=8y}nd$p)Jq=^L9zV%)G>oDBZlC28Tw7rhOC_qf zn4lphq}bX&^L&w|hh0>!2NHDLH?5fq3M{?v%sj4lZ!8Np$2Dwi6*O(F3r}@7h&*_c zV^L?hJT>8O`sfI;uRtl?&LB4NsxG;&T;J*g1-inW$RH)!A(ZZD8he_3bp6Kx&y|^o zOnqL#iX#-)@IJanPmqy?7I5hN+sEfplm;A8?XSX4ea$Gl7CU?YUN(kgWzkt5%9pe2 zQbEH;;*D3IliV@U`DTM=U^?@rK&2s_CzdUq>=>%VFT>({uYeR7cB)Logkz?p*Y)9v zi{=r~DToTXJ$*qb*y0}>wZ)V4SBZ{^~ucV#EaPcq}iTceLrM#V~sa2_BM)nd*A zh7@%txGvq>7=hK}Ij=yPtw`h1UwC5x1AQ$7D5j%4&C)DUVTC>UODX(|r%Jy$Msr|) zA1)I}e=kvAB=y2e1C1{>#^2y5BA)uAV%T`q?&NIBpC(2Hirujy!eX|{FBvd>4ztz9 zI7{CRn-(m;DGzZZ+_4`S{WmwC`8XI{&zfs~(uZpfeCFgWBiH@v z`I2l>i&c%_i!8r53jF7DgOl_1+%^%IOhR3Xb)rV|eW~SCVwzW(q5p~N_olid>-ZiT zkcu}OO&>?eo2EY)iFEES9?N=$jDX*d5&!eiP>!cU>c|981iwagrA>*In}dU6*%QK? z*u8JBT(9TO4pwBtA%Wk@x3n7=V>V>sDez9-oO1gO>#9Pd3b?0?pUTYa*w$XU(S8RN zS~18l;@prl9%IeXT-Yymp?P!vn&A)mv>u3n>zEXlGAe<5b1#xwfwHl@163P9 zl0cQnORpjSWa>GuntnP3)XDm%7-O#=b&=>Ce~w;^7ic|I94O*B(nD^57y-yapPpgYL;8ta3@^H3;Cjd^_MU zB|~a^nrb${C&}vcLk`u0gkcVS{E~TwZjlTN#LfOe$L*_<=xT5J^hD}OMpt0!NEw!rx7m`8l$@6d9klUOVL4G!~lIe2rAtI8ptBb>I)UEE1FmA~$Hzy&KpB#EU`7y5z-uDWeF=CV@@PW@ z0epv6?=#{sR=70#~I3Du}877Bi)*RNk26mt7|B-FKV4x#XxYZ!}tb}inh9PU1qiEh^$=5kQgp-q`o1xo)PqP_1^iwlK za@;3wZnz{PQ98!Y_zYsT>w+fKM%h;WgUX zm7xYA-0qNetT3j~qVA+ZT9tz@1MoGvP_b=i?FQ1BX@#=L06_iT=|IUK8peT;N=B6) z@4Iu*DU42)+Bi|5^#G5f0A#)20qQ{&m!OdWH;@K5sf;`P$GKO4w9~pJuw*@%_0b4~ z+2KGHST!TnUARNM3Z9Rfo>eiy(8MTubfM3T2&l^6EwmoIODq`;*U zdbS_dG}Fl-Le0)br$d@bln(69LYIk_P6ybMnICykz<+i@(Zh+dZb@i+Eg#h0_4ED} z=dRl6>47p`UaOz@QBjVYkK}KN*8Ti;h}cd!R9=lb`$5VM zy^&lpdj?(jQCN|)ayYrQknVcxs&|p6OZTR4zf1l8D2@nu({3uc)W~cDK?C)J6zAnG z2cDv!hjk|9KAQs*G6~dJC(IN#l;*G}&0N{$?^YiQ-98mQ_@<%k6z-=07LUOgjbvTM zbjc1=Hvu7=4I{8IA-5Y#D*gWbd*__XV%&yZVsm;2&h}i&21{shUwhqrMLBS3oM^Q< z;>&WDP{#$2r3j3T=@SBl{Wx^`;>oTwO zc<{BhHa+_@@X8Q?Y9=4RmUs3(aHY3wJkG8V_Kj;lY^@RZevVAoH^8kY>lNARcjcf( z1`YfU=C(T<;jKI$De5L_D5M|TkePMPtQInIK=&nZO)fnprtt$Y8f`@>oD5?#O}{^= zNSbB4pA^YyqfG0bop7gw7uC-0SVB-OXwm1kSjt~zn(LiW;R*;0z9FBsv(1U>wg}xW z(}?0wkG)_wbt~4`F}&SMuqA;z+sy&3DHByq_->e~M1^i>$lq9vZXdYvfk9HI`@Kbb z)oMDG{XPmUWq|ik0)%~}F)%@rAEFg#+1uxwWRZS*G0EeCW~&gC&d7?-(oT5-gb7q zS9{`}sx!T3%aqs^gSCJdEV6E8X-<|icdA;(Pe;dWM@B?5og5sWe;X^*mlT;QCLYhj zm@*aIrj4Squ4m!J1l!W5ETAn*tEOGawiboWRviyeG%wqhYwML6e%!x@rS+8rO!^>5 zKCjHg2%nHciBA*3r!fM4#4kOxsx{l?J)L~}&I3vEkq;HDkhLw~ryP=$AdX@8ckws9>Oh4w=FH0`<#(@A> zULgofklS4kr4=;Gf#pgr?sx0}W?Of)W^=Z}wmtP3!kEC~Y&e$!lVur)cNap~1K-ub z3{a=Cfzy2+5^@VzVnMGags1V}_3L`8Ef3UULq5XkWzm2UzPTQNG zHtbM=(1=#e3}u6kMK&FZz#w%1qSbqI^H{I_x*Q)T8sGQiiEZT|;RHUdg(Z}SK4o>< zZSWjz`gYm9&owh{+xF+twQ-I?puY-7(m}0Ip z3v&UV%*6e-*n4k(t&dXm9;1pzSDTE-TBp`4+q7LEeb^T}RE2?*oMkq+Tdop~N7tBH zeW2i$L~pEFkecXY>sTV-BObKyqL6iKW8b@aptxCo1tdw}AP{^Muj9H-Dd3PcOM{zK8e_vv4SJ-j{tgGTQ#UMT%q z%YpOm{|%q;PxXCIV?!tg-g<=rG#|@RwSWEK@IUuN|D*Tdqx1hW%Hh8tF8@5QFz{_h zKFr8dc1T~{*G}Uh36OyIFDInDFDq35XC+@o`jovU2*^CLqvP~_epXdYizLM zjX8FcB~(c%gsF_rT=3N;pjfVjcY+FZ!S~}&SE(XU00C4fgJKdmnBYUh!a{&zAqyDP z4tpDQZgL;eG=G$v48>mLXYE2kep7+yTLcq&(K#FKxxZJ*%{vl5aWIsx z?wMmKjv9e3tgvyT^P-T@`}!mAd>)R;P~!bmK6W6>>hsT|&*A-I(qUD(v^T>&Zw4eN zK0ZV*7*N%|`p?5!5ygZ^dUfKwwM?q`4%21VT70smS~ui!=k{^Fc~ zB}aH7(>V2Hr1uV`eLy$tP%E3ht_XrgD9@inSwO=vp;up_s_Gt>0I{W6qt znD4YEO2O z74AK9GBQP*JrGL3uwP$kbZV-n*_Bl4LQI`|C`JW`sXsm3*ni3cHr=(;v{u2iiE??T zQ79g(VEp69lkV~AyU__b`V%dg&--WGP5m`Bx+mZ_JtC%=JBah2IHnEaW?W>dU`wK| zEA921*@g!4ETx{WQ^{0B*ePH?I{U`jx7IvfswmeNRPR4}|JgI=LI>W>wRs(%O6kO_ zM7^9#n+cM~%XYkMhGloBr2I_Sn&XMGF6ovfM3*{dVQuaFnuX^#j0(dvlGF?ajH-;- z5~Uhs?eIBk9&T+Dz*)rK(yd*0DsqZ>C(F zOVRfQjqcRsJsD;ef^h9*)Csz+tO=D+r49j;F!}a?r$+}Fm~+j(KF>s{1@ADPc?0OJ z7IQi{j+!<-PDsd>)~C#LVFQntQcWDANRGBUNV?C6_)r9QppKH9~UjH6{g z4@;IfMSIVhlvQuvBKYs<0w8gg-g>u-rDWu?n=|tSvZS?K+zG$gri9sEcrnecm@4gKVq@pX>6d%m~iOC=*A?wr2BMO2G$N8L`9tcChs|5LE-rf79ud6ubv(kQl#SI zMB$z&+`J^){PlbG&!2sc1(|{UxrYS|La>7o2{}hmyi6yXDNm>l&KB}fhCcm(k9M}L=fL`9IJ&kI(m9!f!0^o7do>q z_LIBv{nps_SSp8)`(wXpl>rIJzum415^}w`QxXtWWH*0^!k6aiZxk6j}`q|pI&foIz4{E?mt6CMGZFksf6gTE{N`?L=X7IH|1LI|v`Y@(=rj7`l1Qo|Lu z$`aoT^hcXFE_hhRNklhBsn&?_sU?LlW6B2e`Ax~@BZNwwbhX$>Hx{YUVIhj+Oh6v* zEqVPOM%Rrt$5!XvTXQQ?ethGz#;Mz`;&iSTtNN!lB$?k8_vaEcGH{%}i3(bOTx+}Q zFvx>i5VegQ^E1~X_7ykJm8-FIa&lwZR&_IULYmK=0s?&Bqg@7y)QE(H94#j+jmrro zm$D}*rMAPrQdbxD^RA!%AoY_{3u93H+}+!4vtKfi3`d?q(a5lvPPh@dZEjnpu2`SF zeL&0Aux2N2K|Sy|n(nQk(AfNs>orrty`5wIj_cad9KBY}xH0Dj-4cRcZk%}?#U&<7 z#eE-vB7b%Cw}*7x&M`~In?|wOo=&n#d^u!2Rw9m+S{C-vLN_qnn3{pJ;sUYP%svI&= z#HWgUvD|GYtG-?tsc%8&ie5W@DC6!B#Vxnh^%twMikJthAA-BR3Q}h^G;S$BS)eo} zbn+3V$ypVa=WUa4ct@Tdy60>F**;~oN8-pi<9v#2G-y; z06!8^_JQWy&Rhc!+js3}5JIRFLgic2A_;cV{xt#x8^@=pY+AE)Y}0ppAh7-xi}j23Umi}ABvU;H&9a_9@it7}Y> z7nDjI^Us_e^P3imb(=X}p#c2)1yDCk##<7vW+1nM@C=|bbD|KH@C7YD2MSRXZF^w` zZNI;}6DQ|it(aQ&)dLjJA@4bvsCj|AQ=uEnQ+D9Kz#)Z872sW?YM(ODsdHhL5jV-k z@a|3qKra*y`AS!&t`Z1M?L|Ws*D&rwvc4OWN#3*J94}er%sMhOdjOVqh4>3Ne|7Kq z_|$&I+lAV7DAaY!gQyew_ENK)zgez{K#@vB@4FtWj;3!~lqxEXZZG+gIf(5V6{err z*~jop_nq@uR8-p4z6BNu|7^62pIvSkABU@ ztQ4nBT?n(3??$0*4$)FbHtl9au1Y(qpfApv&s=Zy+M7b)YKX+Up+O5yN zFYE=yEf=Twm56l;YR~anM$B`%=pv`&99I9P!eQY1aU7a;A(Gu=P_NZmMHE@Rj1;;m z!Hpz@i1+Zm=0hrke;?*o}Tss zuUw(~oLR1UjTvH~K1N-`Ma*l1z@%;f)mr#q1gR8N z5g$RExI-M=*6|DssrlVyRQngecIgeSUZO(USdfM6N~Y>WuV);Iz!m^RerY;8DmPzqWc$)|tHOtT3--OU(j&3J16Nt)$sO3?%jWwGo{-imL5~ zix}psT$-&(I=%U%lLdegH!D4bi)NL~^bzXc|xryDCX*&iPrvHK9PPenyV2c{GP&?T@Ea+&vApz*Z)MyYiy z-f9xVJ_YvT@vty5=tZnXr#!=Zzx=*G_{*8(Rbo7xD3gsn8N}l$UEV#@EktY&_@m^t zAZdP*Csb(|BZOJ}`uJeif=A(?W6v?7&LJlm#r7XhkNU>5Mew$tQ&&~~w)Xho_PvrR zs(AJA+P6>YQjCT+te*su&Vodxbzg2h6&zER;HzT8lIuGv%W@ta!St7Er>oJInfc3@ zdQN>g29ls^5S2B-?$^y;ar-cbpEm*l>}W=C<-1LX&1587+IBY;UaBbact0&-t%6en z8CP!IvfF`4T&;YAEKL>y?}_TccL5hZSQQ`!gl=%7CfW=miG%HP;1&=EIyI~!R%(O; zM!W`urox$#P&tj&N~pz*3h!wbV=djyA{2^SzIGy4~`D5x0+Yib5sW#hRk8dVnEzu><{db76rt~MaT z{`vDz^aNZGXv<%^d-JhbW&Oil+1=o$-{cCoSN#lQhE_FDOG*zhHi{ml^%V!gcrM(S zZA;PJe@pUyC0Zr#x&Va~d8=_)VoGK0KI^nau3{GZVP06mdw?2i*Xko~IK*>1ck7O@`#BY@pr z?y&>agN|PgWD3Nt0j7{Fy-eI;DwdotU%u3AEKpqk^Y2y!|F(yRPKa98pL)q6VP6&Ksa{7UTfnOOo>2DuwOGW)W;6 z5Y6H_dK#u!@_&g_0cNt%v4pN(a?r5^+|xLlO&D^-+~wMjIFS*e7#TDWmvl-(K?8+B z*(2Y(3Y^DO5aT4+qbosR@j@Kr2$_tGJ;+95SoeSnk6@K6=m7E(s5ntLa9=9XsMtQ% zv1<92B$I;oCHFED#246A;$+Ur!9nfjvY-xWc*t+lp~!I%;ad;_XKZtwpX^In?1xyp zFV&`iXnMH$AETz3a7FvOdMV#FoQ6cWC}L%f(gC6xQ__!x0>QOElu2^Wk%yjxpM;nu zGtF!KaH(ML<(8E-qmo$)OY+;W>9x;UI$)XhZ!}Nc&-(`zy>dQK$bI6#p>&?uxAG>Z#p zn`+m2%-!hErUp#^O|<+FM68)!tFyU4Uy(t@>i~Z$4J&INvUYKuAo(D}FIWvFLMCW7 z2se*-;-muaLqbCgYk#Uo928LcM|jA+Ec|Y(tIFFQ(7al!>}C#PxJ4|BFeI5LDp;jG zE}PbNiL^>X3&Wnq0v>P!5Ggys1z+|1(+ST$s#kCSZW#K&dG7MUL0ylXE&KfQ z8?r1wTiAb(Ud#1wOVq)_Yb{{wx?Ebd7X4kZZK z>5gX_>8}K_Y=A@M-1j_r4f)<_8RZKRfr6AgEpX^e1uLZ32*Q$#(-6)Lyq;bxnL5cw=5Y!ZS7G4Fj7e?foQZIaPF=7n_0S?iD+gc{kN5pCtg@%+{V?%tV&fd@fqdXdxMl?|ii&u0p~A%(^HcJra<=Sg)b zd-Ru0(n}?Zg`mBRLUE8~j{@th4UKmAeAv^m^g1Eg59d83UDlHm?)~W?x-KNmQg*FD z*7a?UjQ42SqDEOU5LfW`V*Bt4e}8n%)`iXAKj}3bBPM{GvIAAbZ4STrh-%cVREv;! z6#?AcKR<_he9E5QtN|aShW(z(IDdxM@!vU!e}UJNo+M7#@0QK+7nx<^$_EF$vIiE&8%(?%Hp-zK*?cJh z4Ak;e+JPeiuOoDx3X$iw{Q^?gM3dt*-t%o=%1leG^*b20q5M2-DJ|8#qjRK?Plk(> zqmy5*lAf9UMu^PUz)jLd(X}&`)aQ$u>(Ha9Myu_vwS|B77@ZGM!Y7Y}H(zA|)=g7_ zrL1ZsoIiX1-s}Kh9lHTb2+TO*rre{lFuA6@Q=ktqh@~pN6rNcfz(#X4tdKG!dzQzd z^QBp0Y57x~$J*!qI1xemu8r^Kw)fq{8BQl-VDPSboaD3+7z#Qt8t^g8Xh@uy>TH#X(5CrcCD7y zzm|RYJ6_$ijJ}_vLEH|{7p;B_;zJ3pCD4AQ z&YLx5`|T9toCQ@{PHxn#vle=CFUrMLR3i1vbozt$@mO?TZPxYgqo77rzh{dV`XW(m zxD%`-*%=l8zPT@7!EM+BnhzwC!BbDou;1_~4`@bbxzx14tW5(=XN^(3Q-Pv%Ih!jp z9pIEl2tV-IT?3e>IvCv%d8MR37rJ8J-h6fjJQk6P!ROc_ekS*Vq-zW59KdN9A|V1m zRlyZI4HKZ#2H|G_sC6Ln?MPi{#?@KGZVv`?y?jd)*l^6CHE_OS7>^+p^_c0xWob^I zeht*+6w(){u-OhE2o!a71S9Kb;{gxg%l)Ao2hpkx+|3=#68FBHA9U?d$K@wGuYgV z=pdNhDY=wbhV#=`5%0Qy!Uk(c3fVdY?_@^?_Hi~ujK>t<(|Rh0Tk)qR?ahE<&;n z`z*fn`#lk&SC5+?9OGqUo7z8=!=tbnPB+?o@11~U#KdSeZ*$^TVM%w55J=KR{x#C> z!~Csaq)P6gs!qtWcNWs=dAq=#CqED3yvnh=MG=MS-0mz}H+1q-8-|?edn&wi+Wk4A zB9_8aJ8*t5MXA?q8WUGiD53sfWXz|R_px{}Z!O*UTA-%3*kxjLvR$G3&jZfGz9j>m zq6nPW8mTWkswJ8LPXCT{^}V*0p(Y}cD6S;QPB9JTNlE;O2-J)FtqBW zK$FfS^oF#&-vK?9+;B0u({$)6H!?rwKJyCc&JP|uhzlFPu?{tg0pc2yZPv?z7>G2m zwnKcvcIiVvyv_x#zQ_&ei@H(#YbUBjf;piU1h1c__XYo z+7f94cfJuK1Ak2La%yp+t_m|n*rUk;Hcy0XFJ=boJiNWgxxR4Oe;$9}VK^j2@bGq# zVYcK(!kz4i=>(>_;{TpVU9^|pALf5tSmZf)O)j7QaO2x|@U-D@IGsoAXr!7UuflG} zr9yw^__+^A8`DWZA zstB6+dJqNeL&ckJC(s$E&z!++RLw=ug@*n^E#1F z71s1pqLErq05nn?A}zN%g$~Z1)t3Xc;7X2kF?Hyx|8AcTlB$%Ko=U|ve;r)T9>FV; z2c`V<_6CA-z`jslb+0Y?1m8rsm`ZG%fv(O0izSOEn(A{avVP9bCNiyq9m5Mv+l~C? zV#O3gy=r_H&$LpRwCL2O_-;`|9PO3_EYmaGhO1Km+m*C@G#vJ*I!V>Q4MFH4*TIh$zX@U;4lT zV!0+l@PHr}J3Do^SFNlF_N`iL9$4-8hy-+jqQsC#3XAWOHgKuR(2I$5+KWU@_2ebf z@)^E@KguI259Eej=glmGJVIF5DPUo^vHj3)RR{!ijfwTQf1`&@&+XB}4*guM%@V3F zcbiP}t2VNjuv3jIOC6-C=P#p3kl38_r$c49($I`8E29zlAFefn7%dzA*=nzW0$aB zYa0P6GKI<|IZEey*RgBTLY+6M)$2RbW}Q4n^Z@LRz}%w@KY#vYkaSK3VDTDStB}@u zpr3(x-F9uW3EV+k(2!m@L4zbg%5eH=uT zk|8fuw~B3CKNo6uz16?7&_);Of(Oo^3#6@O@KRc%#bI_q8c3>M`*i|YwR1JQ)zDa( zigft$_7po9gBCgo!Mg{%W&)YMAUBesyYLAWD*?x;ngvUqLB^}lUYs%cq3QlsUCjog z_cw~c1Kvg82VNR1cJ_=Cjgj2!tBg*mazEA{04+^yydQ)@Icvso*o`Rm(h5ZC=Ow9) z)FQkzJn}$T%&rlP&!k4<7j(p(MqZpwcg}mc`I~qLS1MM4_4h3UU!?^}Zm4F?8T`^q zp{xs}!zd-r3W_pOyKX`P}k#OiG?udfcLz>$u!hnxtQFfm%&jML|HL953Nn3R0z0)gogu; zq@Yzc8+i-_gk-PLaHWORS@0Ai4mD&bK|^5i_^}Uh)`Qy^dh3xkJH+x0!c7*mb0ZoA zB+E{M>DAta``W!Alp!69Uf{5#f!>?T7~ zt)@YXRY9g^vMhs~UnL+JY=c7rkVXhWh;;aa2*@CG_p#shvH>*nnL7_&=an{@#Skrb z)-`)+`NBXW(92H+61zdhDj3Z9A^NF2rbYxYJ4?vQy|jY(qI=`65TD>$j>whr{x4x8T=OMA7#&bNBJ7sm7M2vf`q^PW?ZfP z)R!QS;rY;Spo`nu$T;UMz(It(L`-RqA3y%&s8Rjw>C8ZD{;Sr^zwYVZ z$$N=^QuK;oaReh{be_M$`b2kKPu-iLp4(H_mtQJ@v5|Ip&jI*mNRHy;N8#F-PmTvE zMx&sn$%5yIfN-A#-KQriB;n$LvryT@(R77$^LFoQf=10L|2)9F#$`h1wk7`UHS{3O%Kzj0T(-8tcl3c;`iy`-y zTV? zqJKEx6%BOYrV8HlWjd*(g>=}iiURNbFPEbfQ^*C@4-3cs#e0uc?>ox!@j=wy^q1Ph zI{a{J?^!pDCw;A#y#Eufc`bU= zmQna-NSxT%)91JpEA`$dC!5RjG%|7^%rail3VA{~cFD{nB<7qXWEqE1WzzTesxxS< z;}VJ%FWXvcCm#xJG@q+-2quVf^?l!F$o z-_QBp4rbU2Tx37W$#Dr9;Anc^y?!1gkXv7RC2)I$HGgM~9qH9g`*xb08eLKR9Qx4f z`-*6!oGptjoW6gi;^mQ&>KCl*cQQ8`rWoZlKYZ)D@4lnbuvbs{oH>grvgNef_KN*( zND8@{dfIQvtW_Ywqp8;4T5nSL~ z`$sQcKs}RJ-8{D|du;N%HqJ8ZR+LS@IOp4Ov3l9J{FW+}kBcZ0 zImIHDf>IT5St{k`I!dVK;I`eZ%E?)qU@P9S8$Y~JM>xd7mm*6D@h{uT{=h~_0Gpk~ zMhXMoIw~4?>lWPXWkq7?q>|g2vovk*Q>Np^8+5BHO_;AXy8V82V`o{gH(Egd({mc( zuB>%~p81jI_FXE)Ro-Knx6}z5iI)9ky07!9dFrCg$)6U+Vr$J>~x8F+*i4l0qwr)i=093 zhRj#Ax_R@I0l!vmI+k0g4VJe*JuR#ruc98`Xgh2M&w}vmQ)2C3n@5JWl~SU<%CaHZ zH&IG|Hh`80eVx`>mm&P93;Rd!bQ9j3zjj;r+sQAJ;MIQ*!Yt95vX ztM$i6;U2Tii4_rR%bHcQ-s&x#l_RW?-pgd^DJSh!C|nKfIE$jF=O}3@#T6qss`yFb za^%e0!9#kD3fIh0b6!)&gcRpg$lN3hD%A4IEH>?69$uNuMS8eeDgZ46xE;>SCqh!1 zr%s@cCSJb2q8>k54K5l!qev;1KzL5iJ9zxlT1qI-&&Ag5EZ*s77cKiM3J54-9PxgNjv=N(8l$ci<=MWn@waH6bggFF3S zaiE}mx-(DEu8RkHf?Nnw-`H$+e1Hp&jTPDb!we;Sma87nYI7nlFyT9;)xH=rAMNr@ z$4r%|%1QlhTm;5@Mhqy)zCu^ulSr)@EVUbtHW8 zecdR**kHw}CJLUk#FU+Xk`+H9w;O(pQolWtn^c=JI*}Zm;c6oZ5bvuf2A(lO4Po*j zF-|PMB_TXhTOJ6z4o8>OK^(_aho%bw*mN{YC~%F?%|KcW3`BuZ*|`EbiWc6Cm09JQ zdbd@3&6ca;EEiMqy8p7O8Wq;(=cQXHL8Em}n(DUQK$JoH!8Hza(8+aowJ%EbEno~=OXDg?SwhWxAJr7BKz9+p1f%6c(63sW1)E^eVYI)m_u@_ z{zJZ?F&C(3o3)H0nukCEsPOfMt4>4XBc1w@Q|Ao<10Xiad(a63y|jAgCm2Mmf{{{Q z5SwRGrUL}5tJ{m@iNIWAU6z8Qld1i)yzZxOoy5l0a_=q}@AYMSe(jNsXx_wB&a7nk zdZMFKBNgzPi7Jxf7T5kjFKiQ&O{)`-MsPCExUY0n^UhiNmUV;BeLnU>?>{Cg{8rJi z)gl)AdbeObiIy}+BRE3c6B-Euo4>vuXBJnx^XLe#CArfl{u4YKZh_VgX@Kwk_=tO0 zFDC}OZ`jSe?8Q7@sJBc1^^Hc0JL=(^K<4+Bw0iVguebFin3Z&vZ%t><6!ln^nQ%}2 zxn6P4B`kZ|w`q1LyvCDtJ2sLWZy05Y9=@t0*(~lK%FUS>BScESvLEjx4Nn*1Tg?bz z8*-+zSnL{Ov=I62(Rv4Xr*G(jb~*nQwB+Wp?!x0^q;z&LIe&mg`G9~QU}qS=InkOS zt*B^KRTCr8IyxY^JN5i2^t>+o85KSAA~c#KHo;6{SW?hx(W)1A5pMMVq3u23x$fV# zacOIpLPaH`Y*HelL^fF=dsRkc@6j-lotaQsNs&D>B9d^0LROi{%HI5skGihs_j~U9 ze(wAKyk5`uRoD2=&-e5FywCS}9_Mi!CykKcz(gS3{FUtmfwe34WBOS~Y+QO=hM$IH zXEzw@`To2v-+W2pzGVK8PMhzLDOFsjQOrW)rVSJ|=R6H~W)>m?t|{ARtV}odw-K%mfbvQ2h{$dn8o)!Jt)wCX~1ndLiS9-fE(YllpZWWP+qG zfVg?0d94_1x`4$u71)>%woZVwn&G(h>h^{D*1@@JPZ_4Rr`8B01<^0_o`Jx5`<08o^`stK>IN=h5pc%3dc0*FhLtK7G~ zohMAa@K_y}y)~!P%RcGsQRFRWh2#B`~77Vt&+E5=n8p3@-Ccn`&YhBs9 zxr}GO0rKiv`;f*K+w}1hJL*q2zwdZ@7p<(BQ08U6P3Ox9*Oqw-tg#8?@H4_k+gX4*| z2Us+plUCYo>S5L>PXIAY_RU9NY3RvkJN%reL}6K0Fp|^O5bD*so|Ek8 z1YN1aZFM=hes-jdQG(BT?sb9PSSpy$ghUx)*L;`c3_~WBFnWnrmk*#FJoxU)? zZ7mx3H7BoP91X30lf&HWt}24|CW?yEcNiTOSPc>Nr(!Na*GH)uOg91<_D-+k9V-O2 z8LV}}q=3!{n#iA^V-`530ch6P_?k&2_3=S$k%XACXZ!{pX3{P$@(20ndW^#*RIyFy zIrP~U!qssj^~cw$_JGB~qe5j|0AIN*oifta5!;fszVL<4&n{=o>l{nW3)9*~BNnC= z@94HR89JQmkrr?p-4;IUo4X67eYMftwXGpsDZGZ>sXiv-)m3`A%xjizzix+kU8vR> zkDE=mI72A7t?Fww)HEEHu;MZ`@7L@x{tpoL9)5mo8Y?{kcu$91r=MSH^V!U))NO4X zs!qE7oJe7uyu6zE zdaX-wf2He-z0!Jf^_;E2$JO`iAw>F(NS}P5IJNN{3u3JM&bhKBxr;dK!pxUZ#8gPycy<_Ex0IMX;xp97|NM3 zJH*(Q6#Ieu#?jelqDyz@C|=2bXexRXe9%BcM6;ozvr3L_oPXN)6Kime)YYM}jYXUj zGPJIMs{@`@yOi(XdiS6v$2`_lJ@?wzvAH>YiQp8M#m7U&9aq7Db{V-!kUP2}L+BO< zVryDPEOT!TY4-#N8?1Ie2q`$k{c8*osmtGpfENT_)CoE|5l9}yJ8XY8ogC?WqaJKs zi>2LXnb772@CCMpQs4uI(GgTcfFqJB=9L4yywHNIh@aYFfWAgXt7&qi4ty^^f#RBq zKFV|W-w}Qy<2_Z&sjCU$S_+UU*ubB0z-2cxx6;op?O+3enU+|S1aTx<898R5`F#hH zB_0apg6i_0s=GB(n>4??4?4N3+ToO@lw;aCQ>Oj&>BLgckzl&T(%XXz#!-CAUvh3v zv^!@u&DB4qX-i4_AfKCR3QjJe6Oa7OgkEXU$5WjqByfVNr-mbw({i3(G(;>&yuz9f zE$W0ZYvxhplC@K=t3L7Xxi7pdt9*W2fh*Bfe4q7Cb6;D^xN)@&MF%O5J9&<%I8j*S z(h0PyeiLe5s~214(u7G4L3}gCNYA9%)l4_u8cbgG`(zHG+q;#UdGO2UwLe^AFrT_z{|8lj->ux-0ZxL3mG;im?*8)yGuQbJ!1K~eeq zf3x3Cgqz5T1}@TGZ@(f^le*xm@gzh^`v4vbmuNpK}v>XH&ynFc>ei;=iV(r^mTq?LrZly4F}V|rp1Z7`J2!(A?na)S+$&eNZvyx+%Y zu-F&QQWX~;t`+Rk$iRDmRl(pPgC&nKU0Ypr##qZSIlqIF@UykI9u>5rV0@=!Z$d8|mvJkMD8cNP6J6+EwG47M$Y2~h~^dU0#~G8 zzb+;;Temz``~H2jM8YLI!fLxK+!E4&)AzdmJb98!;Y;_sjGZ(gNh<95XH4JQXlsJ- z4vKroV-^#r?uXU#H*XI#8TtCrW%||0?{KU$ z?a;6q{c6vVg4dRYiR14TGZTXsXTy_#jkzvJ_?%@=Ie0o`2~IYz&7!3>G&*M} z5DZS%M6mSlC)vUTcE%F|1a|>JgRsZ4of%f!&#t9Gm^n#HOY8D5cAbruWz{TDBGTF& zvImr5B?u;nBJ7ELthJ+mBl$4`PE3F`A^1T?{t8@T2rnuV z!Y7pL`5Iceg%0|PqlCalCW7Mv3?CH%`JZ-Ku%4bw%~eX0rKbLsS{?EUUHepsadMAF z5wi+j|Mn^4AU-FfBNtaKZ*(2YEcnlCC6CsK{pWMA^@$TIx8DW>N2#G`xA^e-6|BA?5z>aQT0y1o%Vt{o8|Z?I8Yh{W)71Y?+kdz(N@MqSzwjckEYJP$>LF zdlP~-f}lmD%&=8B`Q!^}IOE@Pb=JUBuZcD?s987AIU|zA(-0SA!#carb_8-D!&9Mh z&}D+gMcC^u!?ao1gKR$(T%ArH?zAiSqh-dqL?x`fUMZ?`aN?dwbYQ%KZ^#pjj%OPtP{;QZ)(G$optWnCmCPUA_aDd>)+uP?Q%EhuJHLA79RI3!PczAjq zn2*(rV(rW9()kI1&J~ITE3#8Of>I#qh%qs;M?UyO3sQCMlL}(YOggjsOHUZnms!1kxs&ybHD9A zG7*k9Nf1%84>OQ^;~21_6n;&e{!NhA%DaUHcS{Yr4~2pOkW{`vfy&EURKV*_C@N~i|lwxrln`<|zGdl*hD#k}ukZEba+(q3^tR$48g z9zbvW&QAftO#CkG`jqD-No8kg_D>Tu{eNk5yaX*CEzf4_=7&^pL?%4;GTKH6$#203 zTqNYdLdtw81Wgze2Y4X4jd0zi7Iap{B8Q_}?E^CsQQ1$+awO+3Z-a$I1I05zc!)|s zP1Sd-K+s&+R1b{HXiAw)~k@XOA_7M`JMm&nD77eB{K>?6oXphP9b zhip&zM;XvqXmwcqk_rd3EK;>YSHs41Y50XN^G!C9Y`LciB&mbqUF7p8~u8 zcZbZqG=W#ANMQ?gw2pCNXh=rR7sALETVe`!zZaLE-hp}l zbM&eYT%mBUA^l@K!B*zJZhb~HS040W(rtuIFucVEtWw-zD7a=?3bWKo+EEhHZ2-E~ zV!~R-hWM}l*Y+gDXKdi-igW))n5C}Wh?urT92e_s;V`!Dm;lyww_3%;1EIHWxU;dL z>@L(~3T-)DJ(UvsnR-)G6_X77sF_)>(oqYtgtD`DI3#_9&g}l)$eOXQ^e!v;FZ~WB z$V3?sMft>V2ea}k$7;=OSH4%?5LXBuwar)h)br_NO@qo#FRd-x8jq=u3f?t=afY~M zhS{w`<&TuhP~7QzU3~cVt#w(w+!V#Ts+5E_R*3=zCP}y6j2$HICH|*hlk6@PK2Oj& zwfk6VXx%rSmy`}coOwAtWT>Z~01DyG!-1!ra;93ZbD1V9AU*w4 zA)KwjpPH~c4Py&c%VeNG8|FzgW?XwCIrOKhJ+>9pjeI#))3Dd;VyFO3$AI;V=$Zt0 zy&9Fou8W77{So8~Uh%AFqFl4vK9`PsdEIM}ZIjPBox;d_QWD9}1UQO=^tBnpBr?3OZMA2B_|n5pOCX0wCl@!q1JUzM+| zI9GpPR^+|)KbkN-_bP^7}}I4>^}_>th6KBnPBk}Y)A)eRpb zgXvD`Uo!qB8O;4(8lFzp1N1+odq+BwtD!x=;ZxjTz)+h?|2v8Vz*jGnsvl@=%-*d( zrDK^vXQXOxPrTVRPY)y5M@6-pot}~%D2#}aO`@fH^}0>*cPHSt+r{dD^-r<@#x_1J zNol2foCh6)j#7{ub(>GzeV~cLy%cQpbz?+t84X|rXk{Xs;J3dV40dh+$hcZey{0q=NqIr)i#(9Dl zn%L1lT1YSPB`LOFqq!jg9Q?t=s5K7$wrvj~;OMiJk_zh;tqJlw)NTeZ*ZPdC&t~;m zZt~*Zbji_;k@}j&N1Jo~KS~UMelOHILKf6?CTf?MnO%NUZC^vhYmViB(`i_uWII&! zw%7x3j3*{00Jc;BQ7X9&K|cY4KXSdAJ5m7ItN~koex=@=Hi2VpggAaOU)eqWH=wVT z@V@|kKgAC>+rm;9XzhMF-jx-)wg(u|kvF&F3n;1|O`PnH9<}3(l53Q6%)PFx63_W4 zIPi()nW)5s>P}J;a(?6-NWn-uAsBv1hz>nTgL<#UuNN@u>N+92R@%1ev+Hl@Q5i z7b8%!iY7#V*x0+TCMq=9XMZN!H{w7zJGmGN3!Lpv@!vX1!75^=Jhds>wVt7;+HST) z(sjdYf2UP5gEjw*K9(7w(2#hh%I6nF?mb>Q1?}hM=kH5}OV1%pe+XlZGIDZu=8yGX z5(R++#PM*r50ZlyL%t!IL@lCE;N@|100eHh6py! zhbmE;fDR7wS>O0M32QvVGb^%)+Wrx>ga;~Nvx1YvwM zDCjC$5Lfd%jQgB+(T`-ePDzS;Zvur^{rJ$QUW3!W?3;x6H5k?Ms7XkL|Hc$kKkWX6 zR>4z*3BYB^aO_`z!zPhI6ZI6)Mj^iE3`QvQ_8MrqEl(%6!D2L-D6^Rdw$b(_z{&1? z%r*Ib!cKB~3P@_z-)}unw+k|rfQ~saHLu%;-+Z&r0mXdF4?HEyVgIzb(lb(qX1f$= zQk1Giw*{$}IILPc53DUvR&mT-{dxVC5ll=I<>eQ|?DMX{nW8pu_l_;QR37NP>n)u9 zR&P|9Xv-GPA3SQoH*JJ59ch-G-&!Bv+u(BWNLpKFzSA+plZgXVs(CB~vE3X4Fm!p2 zKPR7jHT}>_SXj70AeTjoM(BX@QJI}%Yq2BI)kTdWxn@E(`}FkBzKo#v zej}Ya3hT!@wwyBlM$MBmKzojWjp;C@*dU+X~KY7GLuu*p8Qeg7c2k*w4wU8(Mu#MCIK~VmIZ2BJb#Jc z7CWuK4~VHz&T!Z^`Jz{mi4d0>tgN!)e^x$^X?t~(>W-9V5s#bdqhlvx)NQc;*cE1% zUu*Q_c9Y}Nq;oHsZs%3zywofrn$Wpp4@uxE(O_d{-%u2bid{w1CX@i6L9R1~s+FKN z!eb%}V@uwebs9242ZR44V6<$#cVsuaiZwALCg@e*>YhU4n#Xh%0feWoc@}YJ%sXFt z(Kw2ObF3lqt^2=r%arAf;Z?+3nhcC`a?wmrR|ufVK!+X_z=TMeYkr3bUEN@(Q{(2G zz=6kM2|O1s(n}yKS8PVSUy+c2m*I~?g_`OO8**r*Wxpg&4xHxWRdT}+MHuTBTz56miFc`n?R_BqHV-YBsbfS6%3_P@0WxA>dt; z4l|fG?(h~bsc(FgIt^oEYJVN^V_A8v)$J^(lM+Onh3a7&1z;EF1fifn&+ zl|iL%kYvbv=Z~$KAnU)+YWB}jmhf9##V_878@Vmroec*<&Hrmv2ZCQBdcUv zKW)?1&3{xpdqLd0fH(TZ(D?H_PChfWh43?f>kZm(swfa?w8)7VVE(L^93GgkF(o21i zj$)9B>hH>j_uv5SHrJjsi7XbsUAvm?g)%s_VW%Y38sdcDGUkv(r}bjt(+*N{!C5|Y2A=IbrxK+L*IG(U{ZqKtIe0|kaWkduaws*u>wJZ$V0$FpY z@{oBGNTR1Y-s~nSq1_tzI!6giq=WGY`oO@oY@*D6UIjMQ$1wEt{f)MqSKub9x76av z=iQ02kx1>~#0}0T@dlt%qDucS+0O_)<2Nh~z;SFsO z{IM-`d3NEQ&I?W&>g-?3eTn=G=tb6zPqdiOr-WHFaLtwn`h$@laj0J9q48oFX26oh zqIQP82B{XPzeuK-B?vx%H4a5W0oC&q2HBBcYb2gVPIz3Rp3=jUo^b!O(O!%uV zLv@D&Hw*yPwtO4nxgioM<6&`rGV9syrl5fp|v8OWP%!J zt7vtxWL0Xp7%3ayt#9rGq)9lMC7`)p5r&J5Cq1zp+7* zb$0+d5$E{#?H1?%FPM*be_&cOg~QZ#?Lh&oWqlt8t?>u*UMBp~%tiA91d9a=G*St} zi-~FWh|b18?iUl&Y5yB6VgU0FW5%G_MC9NfV>IWEl95U-Gw<$-S-*EhVKScREQA%^?y^Sj~#X3 zk9lhb->KXVTlJvgZ?|9-oUZ3Vn1g|8OE9-B*SOqjL1QMEC$o^5hDLjExx6*IC}fG~ z@-PehDqSxrE`9=Tp^&X^c{5peZfW?yvEo=wu(^96#vsmVo`I-c$fn&*NF{uhM03gc zf4h79gA9QsPD@=n@%?)4kM9Dkd_Karh+&J0-4f zF!t;TluI|@4(!pvPyFKZA9*}pKPg_5({HgSMvx)!lgjGf@;Gi;=p}ZTdONE3dw@7+wf@RCf;|=RP^O-5BKKh^2dpJOIWJJB)=&j zPd@=U5?V^-T(ge1W;DdpN#0*KKpZ7}*Vbff#6Ge%^blay4@~271oeUJ_u`s3gl&hY ze@u`Q|D1)a_%i^iZRx+wb)P)>&{1C+V$JENN;$(`xmscwx5J(fod|Bep&lK z_d6JTyUzTtCl>}|&PB@-x(R~Ig7jotlKk2;o|F>H{m|K4I$>=PW+W5JKzDV*dgsX# zEN>FKV-<#IOV2D|Ug+8oQ9N=qHt4oT%@=4gw82%#_|1bS?%W6-5~&uUKV9C#SxJn# zBTzOiIBN@=V*V&@C$&60C3razPLe9xE;h$>6rNr0u4>RYH+|Bs}DY%VXN) zIZ^*~iGy@TDe>Ea{Uxs+y~UYoTHl>%xbkH2U& zX23r-@3@*np%qvc8=l{@Gg(ixwf|$#@>dhgBV0;Do3#~YJUPGJF4#2Vf81!rOqw?i zR)f9O*6%R!|oo#uh|b_O9xBVoRf+M=Iv+ug!gZ;{Vyj5<*x{2!)D@( zFI8~)F$XufSA&g)2>XMxO2Pj&DJWIrApIb{gq_3-`};Pb!CCSR=Ox%Aj!5w(g?ww; zB%xwp;Y&X#B)Qd6Iba^-aZ@jR{BRTX!%OC6VmjO=J~R52vqx!i+g$ zfakbZmu$+TMjoIpC5!UTlaoXU01F0m=wCIt=440vap zw!V=_(2==d`MTsk+QtYcIW1fE&wLU+bT(m1S|`;M-99TxSV&g)zo1X{igyf7bc&U$ z>yFqQvX{T@Rfum&iB!SoMOEnr4GCwZkaJ}dnTMq9<<{RdC(~WypNCbm@sW^cz)?(U z%`6H6Cs}!U`Q$}RioBAh^$Nwb2?T^5pG7u2`J=VqgQ+)m1}+M5*|6mg%!UB2&{a~1 zyEJIqb_gx;n^78|;mSPHSTX>6S1bEP@2&T5%wv^O+hZ3&C`r2_!{?wddUta|hM|?& z(h;}!aE_s?#@Fv%7G(ZCmn?zk1!DtwJXGwFl#}skV>iK6NP)G!fLx znRaPP*)O`5H43bgNAm}0V2CtlBYh|SR)WE$zDo`gB`4`8Ut}mGu3NarWay|TA)z8E zc}{+wQ6ihZZnUp5lsN)pdhPd-={WW7Az`Tr>nKi(b*p^c$}v{bwIXxEJ)GiNTMp$F z=1MuC1ophW^c)w3yNg#B$EK){cl(?%E9x6+@^yFd@f@^MPqNm(Xd zy4j%Vx9-U=&tgbbFcz4pW_G{vZF6^Odn1E{6K{90N>GIiwX~VV(#^%;?M)iL=tJ3JKvB*Bo}SnxZ-40;I?|RkZWcnQ-~q* zo)zWbk8R%SMblkwJ;m%-SX`>S^PaU8<)B=M_$qn@zDz-vcUj`RWXb{@ z?sBnnf&U&0(MxYl5|s|tJi6YSy}u+N@{0D>w63Y5{%F<6xwevqmYBa{to1Cf`3I>t zS~XAq;IyI1SEEWGW7#thPsU>52p7gJkebW-%pfHm2V%{8l(uRM85!-_vuB&@2FAwZ zFgi7(NlaXPOL1{=E4locd{=?dGq3XY?ls%GXeg%LoQmtBqcB}Mg2a7fB-gy8#GARM zuK9|vwxFQeSj~Oq`K;fk2EZNi zA+4y-?%lgfVI=VmGr>)HJlL}b9oKK#u7h%roJBPdjuV{d=@tsIYZrgSvqbTIZr{Gm zee-L`n{mY-W{mUX!YQ9WAhX}Hb7$h^r@|OE)t$3nw>oL}LC-R5I+$C#4<`V#Y9moB ze5KArU4%}qZ*DFR&^cWs%aopFz@Z!W+r>=P3+34i-m&P}l(TLF%xI2-tGI`vH3d2+t+UGl!6v_M-`|1J2z2Mc;#` zeNHMSz6R{s-qA6L%cVO9z(+7d#}ClW^n$Sl9I2^@+3RgFb~u)~`T2B==tKfqfecVB z-_o#q21c5`pvaCx;+$?ZAPcUH6oB76d=Jm6vlvQ^lBoujZR=~@^%z&ujh~?QmJr+n z9B}M%UC$I z%f|L+uHV0&ZvUEFb=F~TTU>yi(`-jutV+da!zvSI2W=zGjU2~ac+>Aa`jlm?wU5Dy z@zv1#kDQi=plzTLNW>YtxD}TuB<#J=-${NdMv)1@`l!42a7U5D!>#)mIM84R1}X}M z!H65XzFkv;%3l0+zQi!cks^lR4rLp)|Azsfcr`72FZ2ukj9lu>1H zRKra4{+sohDOXr4eW@;@EkD?r$p}I(Ci$+zaPduWn5o3fbs=1J$>4Cq+mHcEBb|@s zIO0bg2F?njVh1ty;Hm3%bSF-nC|{l$?TEr4Zuw*dddyBO1uW2-bMp`h4s0uGB{PJvLj>BZ>GwmAMYi~{Z)3~o(FX%8~PM&k|&03JOUrro2Jyx;zN|%JbVRXez zJoAu2KV|-D0XxkA8pS<(2A+zxzZ-l5&IaZ+M?#GI2{Lt(w{PF7=G{6*IDi~JOnq3u zF$7jT0HbxAX{f1XqUls3la+@`hR%ZTbJ!hMkUTCmBHV6cFVeAFLeHZdpoC+M730XM zr(IS9-E2>aVSbBiJVuW?1x*C+D$#XC$-RUxHEcT=H84o-R|0Z>G7Xb-tvBITJZ6E*YM_C zShfl0P;=Ex$?65BP*2+VhMQXI_eZkL++6rGudw>6PZRZm!-cA=ImL%^bQ~w>1esX7d7kZz#O)r~Q-wqjUtvZP3emdU`IRI91Iy z-jD0a*4kbpKs(S1{EHB2+tYmP>}eGSL0(>BdQNYTh(^_hCHy`M_XN|lOJt#R2D?qh zr^nKYbFSBHzm*xsA@0)cWN**fZl4*xO*iDcPPKS`6A2_Qxnn8H%+e1w>X&aiYq!&f zeBQjLHj1()Ot&CkS8(cb#(EhzEb7jG-wf?vIyB5(Z(q@pqLEuHTdSm%bZKd*$+UTN z#wFX#&nUfgVLG{3c79w;nukZ+@YTB_gN-^H53V~_I#1Wee|x5a{&^UqkFX1< zw?7NLe8wVEG>7KM8Bk2#f^a|bHMpz(IlRm*K@vl}QmjzM8*HE6Pfjj^Q_>10hn~8r zDGLz!j|#rk%E<~I0Et?%4W|bJ?<6r^bIy)xb6>amif0{VW1{YGSHOJf`papZZX-ur zz195=ss^W3DHomX?+MTs5z~jCn)h;=YuUs^4dp<+zU`RV>Zbj#w^Q9QEF=B+LOFe9 zYTsForzg5Y_yxYdqgcnG_fC88YK5kV(rtQ&I-u3W5<|SzL$pwRb;YZ4AGRyR7fM({ zo{91U_a+uB`PVq#r0dt8jPkeHPPk9Rz#9{R$LOyo>$F{__oJwe6ZRmB^iRP^Gz>wC z#nR$3YM>j<>)E-ovS<#V_YxR+TR@q)>;@-L1E3GYj)j_>3+@A^C0yU&k5B`|mx|Yt z4t#6<`WS(a(dQ`McPf~H=d5?nL)Wy^7rowy*{%SKpX8M}HzST6Qx#hLXy(?_E$VyG zi=+OrL~Cy}+rEd~2e(QUB$!cw^Gw~eB~Ir>p! zV%e8hlu}{mr+-?k-dI^VS9yDVL@2YqY-BK(yJjKB!tCnUN^)N46JIf!b?j+*u8T7s zNiiQ9&bE=HG3Li|1ld~!=kUy>S-#-7y#GXur1o9+Memfyd|QS|MmHFfdfh&jeE8Hk zLC?DJs(bHZ<2ZM3<-ed|7#^?f>M+{R=qN2J^7t;(Yr1;XTr+A|F2zGgE*--k2@w(q zQwPMnHkQJKwhUCkIwDPhNa99E!D(5;E5=Bb_3AI2K7ym--?+j*8+Bmd5PgH(iiPP}t8sm2>0 zWEyVT;}jhnGsE*~tgp76H8{V;LL%v2+C83Y5^cf?Lfjq?N(D+6E9l?yt-Da_G(NJL zXz9C^|B{B~kogm8i>+zq?w57cFKwoq@6V4)LyAiFqIB<`@{d2rKGNnB=QjP548$D1tr-~c)E6<_Ft&he3ZIb!ZOkwUov*e#eTahztlaN&YR zk$q5UY3X7AItx^&bKtn$K+WT0^G-uXT6%j;IJ@0^dVjdZTQ~iikV#1eoMvF~go)c< z(4V2hf0$ay~LU_zjxZbbZRZ*Rv@CdOT?u?3*`@iFg1fRW$(`zt{s zQNvb)P+)C+BYzZWRyX8gL_%uXo)-irb@+-zO+V-YxY2dV6V)6XYbwA1vtOAXK!TDH zS6(f@wQ-pke2NbkgC~Ji4mVY!*)UjTrrGsSEF1XeJl^?IFb72Mp?>m%uy*RZP zXWO>>ig{v}C8*my_^Xdh48(Mmk1+yK zpp@!lwyNe^(j&uWIC`}7lWxD-U_Re7Z{l|9^2RXlA58bUry37>5N81A!1(HVDI$=sy%ztFmD&2|A>zSD!Y6(|AS;9O zB(h)i@27P){qq`G8QlF0Ro9=Jg)wo7uicUoako6a+@IUo(?p%Sc2iWu-Oov-{v49X z<41e{esi^77#N^{Dz@m&n|v7TA;nZL@K?{evBy&v+M}w+J1$pj#F_qcWURVmx@Inh z6~H*(p~#^;b!|HsR?kpefp6`Dq^@Hk52-DeX$uE|bcP=B6EA+c;m;z-7vGua<-n#-4iHe z_k@EcEQOt$_&C_$>7tH6ONPv@zeL-6YT8l zo$#r4o{T71AReAZ-^G9Dv6{p3x2LhnzP^c-)^Z7@f|{-eZhyVlyW=o8LTyxzP6$h1 zL?hVC%S)u&<5BfC{sCjdj z&u8IX^78Y?5mQ^TSK(TO2+Hzq1qB_^S|J*i>9yA~*L@outwS_;u9~iQMuffFkw}r( zZsH8~j*b}OEP&EsZyOw`KygMoBJ^$r5x@|O5;2=`oaml#8#UY`_Rxr&6SS-UT;yj@ zi%B1oPQ!x#3w$9YILP>&A_QIduprQS-0Tj*g#sEbgb_Ke?_|u>>=-XAD3=@U+glNlf9*Z~1c-l@ z`@g?GarZyV9j_u5{Mzkz6kvM&_tLLOMmYOBu>1}*h;b_RQ4H*wC3WRIW|td``!e3W zHD+gLm|wK|QpDxaPLK0+Fz$+TxVwb&3SkVL`Bml zxt(*DoSde!zn+-fCKahvkq|hv zr>w=KIl{J&EP$NJy3N%`{grgFO-#UYcZoi99ah=_}CTU2RH-O-!v`Kh?H%JJkGhH?TSjj_ z;`a65^sQ>niazwOFA9y=k*^Bxzar~)-`h$7!QgS2E+tX7`tQ6bB9if=Zf^S3Oj2+W zX$yt+9%TXQA)Wb0472wufdV9rJN42iOj6+9)gdL8oPk)4*Si@TtEY8+!zq>vaHp{BR82evo^MIHq%)JsXj4H9&f6qE}*jxegQ$ zh!GpKwYAZofK?!1~7jkp$&H)d8-CxOyjN8k_i`Z#t9RjqSKPxF6TqVC$naenA$E@C+ zwA0qd=k4*zy(xK14^7egepvY})}N9%1+!Rc!D1NJeh&q21^_bfbgRLmXhp{E zxkz=|m>ke8Q98B5dB7SdaErC{Q~U9E6!{L544^*fBLWs7*P2^gO#0yjT^b%i4 zn06DDH-e(U5Of71Z$XLn3tidpKCHNDzlU-^SC~`8Y@QgkdJ< zSeIM!-hFptYcKUg@kCCKmC#8a&g#gZK#-|6;r6&pw+o{GgJ{a=m)+UOZSrNix71V! z*d^sI5El5NmM7)F6f(>Vl=Y_(kOT?L+(857JAwZKVB7Enb>+z!Oy|udV099pi(D`e z=z}f@U4&E6a-xW-1>!?eLEj6p^IPl_Mh)>>A=o&t@fkt)9Tz_vk|CNs&jg)xk zUz+R>@;5pcbYPpnHu7%|+*T7Lthr^_w4~c@+iU$IU0sXF_vq$c`Z7`%%k4Szh>xy2 z1mA+lvVu3G(f$~z1G+FV6**6y93^I!d@m-nJ##KV5Z1wIx&3CqAr2i9a0(gl{R}=v zZ~~)bzv!|G@+r4z%U@=z*rq2?Eg9Hvr={&~m#s>(P;L)%)KnUuJN;rs((v|l)6(eo z3vq$FH*MO)Rnr{KTU@+->-Knur^0kEoo!l{OX`ix?OcyU`RO$FYM1}Dpn{bwE9v%B zR3k)}GNM}0$X~)zG;srsMCz8%Uq%mE{dndi1g4u5598n&W1WN1BincI;0NfN0$E)U zVoc^)1tXPCg_c|-$?i@{T^)^Csa_}VS=L-!Ttq|pKIQgpmZ@p_4|>PAR}M#YH-8{K z+do>j%7 z*AdyGBYXG01qE*J*b!dKdzj~H>K6yS4L_*KXp`R~vU^xACoHz$bfyDtD9ph{PB3sP z7HMc`R2wZsneaQBwFwC1>rsZ}Ud=xhN_PbvJQCHxk?4d;r3d$)x>|E@?&xTZp}TEU z&e1~YR^qahA8bs~H6wMP9#<_buh@}O_j@m_TeoiN=jR8Yqba`Dxj|{M|+6x1x)(6V$x2q zG6uYkxDs*W<<)E^i&(7oJqHe4!ipT9n0R*nHfigD66`23l;t}9Y3!gdMckTZ(%eRV zl*#o)XXc(g?NoR zW}a&k2UF_`N$lMGClOZabo#F`6G^w2!7a|XkzJf3o0f`>%I>>=8TD2AuMXa zNZzlhFQKw2#6Hw`g71-&o?eUfcT#l$fs=;W3hWG?+YW5Id-u-p4Ev2t`D)_?1ogb0 zG_Ag!DWP5M9r-uXFLMr*@^B`+S)Pxz6PJ)J$N}eRZ-6EaFp-h zddkD(70R#Nkc)I@A@i+{BPAuB16O(9n3#wN5n^H-`l(1T{H_eyrK#OV03Q2F*r9pz zIh}Fm?p?*K1p0YLZ0pz&PA(7`n?jbr>e3`X{u<3RBJ9JwB{tO_8)SY5_jVdq)xhvn z?W9J(Ls`WZcWVx8d*JLG(K}WjY0dU+=P$p2T>&DZ7S~N#Zl5_s!FnLf(P=U$_DD&` zv#<8nI!8CRcMKk)s$T!;lgRoZ0fET=v3h?x#hoZb*Q(H9F?bY2A*r{l7nr@(_hCPZ ziCv{2q78q0k9|PFuAIZ3=cv1#Vq|xCdx$$pVtjfRpq2x33)h%D(_CEU`5spJc=y~O zd+PmM_A1@3D1OX9Gigpl`i+-E@#aWI!S3{Ttq#A{`qsip$<0EOKj`(dgT!eK*OIwY8tq9I?kPA$AML>2VsmXvt% z-rC{Qb~pWr>A(M%sGR?P&F|v)pQHWn)8f2%Yze?`4x_}9pp0S;;Jn~UW#UT3*c+SP zpKIah;J|w}_;EN#<tCL*a-AI4j_3>{@pwm(NF-=r@63049F2)5fAvu z9@{A2X2F>7U;V zXR7JH_>GCW@ZV61zsr`2Wa5JP=fnP+pZ{;T!Q1=yHMw>*tzApMffEZ*Q1Swf1i;eV zp5lbNod=mc|02s{!RYbgm1T+m-SS^A6gG~1(&^Gu(;TM z^9F;ZrQkFaO!_acxIVc5-B@}%qrTo8_nEN0iILxnN7Gy97|w*1^eis0GI)+(VJ^=7 zk&Gid(!4p3$6~zByON>qU@L(AJ$_LxC&=dCa~||8>z``mwjgGT#^5 z5e}))w=OHrMQHY%wV+*g(adviUcc+x$|tdJqyE`0PFuE=E|>2bH*Tkdk?c*1(T5DW zFstxbC*k_t@X?Z9HrI!1<-6v}IOb|Ne%yRy`oJ&2dDC9;4%0JVR9|KB$h^J1-}5%( zuZ-Htf)-U$g~60yqYQyFVHBok+THs+%MO-5A^-KLw$c+1hE@dgpLj~joLl@m;^C-e zt6aK8Sb*MRQia)Yo7l&t`F4$5|A_nhIO}4odh!PvI>M{G_o(_)mxFHC-d@O)nnr!j z+hxUpMa=)(_(V-Ef9F~I-LusX(`N=Be%6%`{Pm)?(j~F_TKP9wJ3Gg`LaUO(bLFfD zd`M!iz8d_Q6mP`UX#9@a{%ft@B0v9+?onAAJG%o^o3h>SpHcVeVNiWVzD_Vl^*OSg zp3zZjYrCY3!gK1|@BS=(qU661A*Bdj)xGgYJP%2U#7OeKpi$4k^Z!q`i0YMU{u=(U)(96WRHndk_Q zql2!?k7L_Y_U8g@U7l0Ryw#RX@TzEKpjQZ{}z*r?e-z8B8B%mUz6bP3{o}omdDG$w?rQbD;X-&mE}=4lS;GT&6#D_s2?0vN~*heXjV;HJlme9`jWh zeJA0)Ob*&9-Sy)yYCY+zbIvy!+;HwTO%+`w74M8g%(W<4W}^+J0{HH~vn)Xb%W!aT z@CSzo9fj)3(y7s?V0y(4v&!5<-@oHyy~k=kifG4N^epu|R3RPf+BWG;65?O7%oE+IxbB)oL9l{+W=!B`y3`?ajB;>=80>f21Sa#~w%QrhoPp|)NBqp!d6DzV4W z?P}0w4>}xdP4*qNVczP>;@01!jx3XAe*k-}Bdg8YZiKxY*#Q=Bl$dBno1%yFxj2CO z+$Dlb&{ZOIEtn@&Xm#lnDy8zSu2`twL6(ZFxC!z_647&D(}+N20&@7rRD+=^kUx;~ z3jB!>PeQG{(Ob2X>72EJDU^VJ+Xywe@_2cUXf0(#9XQVu+ z^%TpXQ`U^~d$e^x+O}QD^MaL~oh#?|59_049_A!UtkZd*`&ud#IbN_BQ44QF+@Rz# z*a8LKQ5Kf%58er*%lP_T_yne3L}N>{f`S#``3E#*s5tdRx@Y21$yP1TcF92j4}-N! zdiSji4Csg)6?W<`)pPw}1%&!6%)TA@(hu~!2rwTTE77b3&*T;Wgu<0B`<@*z`>qBU z2yrA6yw(R$x%6RHwJwm#h(rmL*(3hEw!@S{%TxQ{Go*tSjWgOHM56`m>IZo533NPu zeKkpIrSGM28s-GtS4H$o@b6^xTsBz8^(X|_v>pNH0hOdDy;Rt1kla~>cGA)gT801KMT)RA(4WD*Z96Uo$AS1dfS7|qNvA-Q7( zqOg;|M+_nj@^5LibUP=MJ&r;jzB5k$PHVmKD5&A zhbjXI#`(Jo4Ei#z*@|9eV+=+$`t)og!4M*-fax90%{-hA8!v-ZUq_$MvV=unZj$z< z5_~h@42Q8qL5F$!@YSLM&S1sZgG%l66xiI^-b5Dm4Lk@Gd8C)oh{4Gmp0Tj9Di1dB z^Fzykp)&I~4Mr9Wy5TzN{re4h1ky3ZK~n2}@5P*kaptYjg3&*1j~92aDE8;LM2@>q zQT?dNaOO?SQ%ys&VWP<#6C9Yxt{^-xt zi`(xW93AC1e$>P%)9$UlWyPdi$6(3ne%He(n=~VZ$gH$GbAIpM7M?jYn?foz@udBw zuL4R20y3nd0MZ|Wo;Cppz;|;ifP72_Im*X(kR&$i%QXpFI=Xv%=_Oy^`YudBR}uV@ z-@bp>wd>;8UO1f&X4N~Odk&DpA_HVA zbvT;}zNfGYjysjy`>=ISwaUl2_Jr#0l$S+u@e)fe|7V_w60`E)Hjs*l(v< z>f%#&UtAp1Z!I}u5_c)WW{4rD5ZqNQyABV`x1Dj>&+eZsMdAD72LI+Acj$(;IQSm) z0Ndt^S;z1`b=pXBeM;xUv6mg|joWo2av+EMH| z2!;2>CjvTN5gW}C!gmwgh6uQC-TFJ;6*h{#hTGdyfs6_#@xm93d4 z7knbQx2k)P<+;pK6DLlrKE}Sog=h4L%e_|$^m+^EUBuTFf?Tu z(${xrzSeX2mvlzSh{tWF^XW>7)Ur8OdG{ZxnP^ch#wOL=qH6oDQemfkS*>4o^+I|h+nj|u3C_~8NQhe*u-uro;@BjYa_x*p3#~zzosz?qbS| z-m~DR>FMc%ppHgN6Mi<*mysBdu~R$bpxUe;46&&Ij8t*wgc`jc@DHFM-y^m5OOq7* z+#)6Ut-pzY{sKMgb^NoVs?_<1DBo;&fsBmFz4G53ex7qbUD{8~P_1HJKNTSq&Z)Fk z>taz5FU>0U&!3BY{7ZhYktFEI(7t*;)$pM1<#txbSI6IbDim*w+hlWdi+wX;!>iy0Dclz39p9q-#kwnN_>@RM_Ocd-*$E z)1{d|x$txc`+?0R?hicnG^ZlbM3)b(SpJl%>T0i+{DAZIFbr1O|q4D)1fCcppWN&JmxRb~np+4R3RQ45;s zK6^pbgx=lVoeW|`)8o?T((6G}oY?0C8fF#V8-f;7r&lmj1mN>O4?#l^(l8S`bbBy7 zG#9dOG@^8I)Z_5CxI33)mVX9hUL1Fa@osf6$Jx0xPXO}}U-iFGonZUdCCD9J{vNwL z0HX;(@?m(FWpWVp!pzT~QZR8gnqEL;3Ftn}UI@gKWV4_GK6lCoa(#(=hX_;RZ3OU2 z0nC45WMSz=+g|7S2aAAcnm@#W?lQ^h>S}qQTNfpiO%}nVmbSLGXK{V^!p8eE2!{0K zOK;sKcx*o^{?^}rIx#WP@_@IuG#HkBNS8HT^G!FyZSM-e^Ne9d;9VI0zBkwA**)ql zJB!4pq0{ttFTh;L zU%!7J?Z48JV?6*;wN9flbkLX*=+ZKUT?+w&CSs@xD26O;>d_p};1vws=kSr&)6Z$e z$G|w4L>uf$V5kMZC|M+8nZQf~Mpv7w5ye_b)PqJs?1E zgl^Zx5^!vrUP}USH;GrJL37M&*7Og0cwNA`4rYq)Y|Zz-=oC`Lg~yy;FCY6CrGgug z{RMI~(|o6M@g{r)-5(czglm-cBU@~8S79kEE*^;T+&#ZYod7SxxYt_=CfE??Pf^i9tz4PAKNN9g*5T8N^RP&k`jtMQi+*3;sTh9GH3!We`J zO(jCQ22lbup&M`%r+oj~ngI3w1ho50$58P|9Q%FGvChg;uK<@HSLY1>eT|M~fk2(eXv18ZFSO&|n+{rpb>>wlOL z|CI>!udwi6AjbbqZWe*ne{B+3Wna$`eb-nrFi2AC;`6~42EFUA{H+(}qa+V8s?APt zC@XswoT9Giugm-vJjkeXJ*M%gf?EGe)AshO8_gYsVI76k%et%{ zZ+3%M@X!PEGjz|M?h|PL{o6Cgh^Fq%%}g*0SJ?M!ZC*;6b?@yu4>)Bk#dn$P}!wdSy|SB%2LmE<^aTS5($i#`%nA zWi$S*6&T*PL&nWU+C66cbBf1rFySb-we9P#Mj7PraP7D@Un*u%UieKpnn9W3=jT6T z3kcGGAt?IikM5@1tYXYI|(k&yDrt}palT5xHLXNm+BAD={9LCt34Rdpo+ zg`G$B&(wVRl)J%gt5Zm^g40?0u5Ynz)Vy7va&03YtQ~&e{ps-*H{M{nxVWVI=C<2i zRG^_w>)nz;cV-xC6sT)A4Wgt z)+%!J4jR-$B(X5FF&i9yiMi<-*+35a!8fcmN!t$F#BiJ(8P0jYy(7l#ww5pb>lnx9 z%Qhb9=>{@#x6{)H_m+^JfY-qM$1cdRJ?`RTZ?{iD@u!(c>r$!FN6 zCA)3f=QCZkiM8#qV|KcCwrdZ%^r+OIXN+D>`?dP;cIQwZ5b28(f>!XbhGAwPRjzC6 zk_4$6mE)Q46lECi%vJ-K2RxBI|;AY!Kh7^=oHN7HVe{Xf|2V-_dI?GO61)bo7tH(1=Tm)KG|x z4rYIJgQ=+%8rOs7dfW^(2R}RlX@s`=$WJMhQEl!E^K_?^ESY<@ek&4vH{ul7J`^FY zFt?i< ziOp4s?x{I27qqoaZ%Rs?8(|tRpfXcbn|R!Q9J#36GHS}mBB*!Z=Bz|0|Ow+!G{ z8ptHk+zQ(h)i=p~xgP8h{L3?XolGvk{??*LsT&uYjB$#j^`e;wG>nk60Z!CmH1soI z41?`YjwTyY4>Y8l&Bzb}725$xm_=zIVejvQlMpIZa=e1^9y|!HXJjwP#H7ZB|Eb-t znels2c+IVd_Yf$3A+4N$E=QVgJ@@ri!S5LCM;_DVtK(HBrkn+HPXwOcwfAbt?*4Rh zX?1PF2cCdsZE2bXJ95Iq3roU2c1Rx%jK~=maDM6m;bn<#RAE#&(q@e!%&s_tu_%~# ztJ9k2DXK;Mup54(k653^PZLRmjPUW2*id`n0qBf|Fg~W|Rj!9njcO;J9!R@7cHpMg z1A~o*xwb={Y`v7D1Z7^!{#|s~6cLJDGy0`mZ5T| zAHO`r;nJgAFf4li!KcEL2L@ho6#Ln`G%gt~39xBA2oCcS8d1sg2e%yTjyD;z{o6V! z!a&RvKwbtYiHX_{KrN}?HtoH!^X^)*#~edJPgedW zJeruTbW0)Q3R>#?fpM$w%H9u>8Umd5fs?B#PQ|_uY5BN7r1d`MY@g=i6q)WCUdfL3 z8@eg3D;0a|SFCoE+g}$iK>5%lxj)}gdr{4G#;E4-<^yMjK40?E6>Y8@$;`<8HM7xa zS{BCN_L=6Pkl3zAikfqpU4A|3jE{A1zgF*c4}S4#r>aWj zO%gY~x6+*gZY~9yh3~gd*wsRvpvV@*z$8wLs766MP6c-CYh9aQDfhCO1@aFHG{*A> zifL>peQvxbigB)Upse~u9FEmJu{?Xz zH1uMGk6gR<;aV^crQqb!k?O;jmAUN~PPj5CQhXNX>f0t7)eBqhoOFCEOvF<)f!M2q zhuWdBa=UlQ#Oj%BFi-yRX;%A3blj0dk0oLpZdu9|dMZEo3R(+7B`beX@t4hiHG>1g z^1x+<0l+wMAx`j2bax6Wv*>t$?4w&lP(Nrc+}hNA|5pkm33~45ibn+< zt^Zwy6p_;zTqEm2$@g-s-(a{NB5=d&ky6JXdLlTqBwWiyi$7lPE>>twe(i>+v1>7S{pO1g^PI7_& zuk=oZ^tvM~wVkB=8e-<)c!BZ^vY6EbvC4TmwHExMZiuqATE+#mF4zFffocsFG@6L? zoYIFF(QPpGIxdMyyFOQ%n;k$-~Lo9j+}e5Ge3#oBqd3 zfm$}^VoRne-&hh?4li3q^{uL4A?2l{;24Kz?ftTozLf$crBu659^vFZPsj%q(hWx9 z*97?D*)5+QyNE8|{O@V&MRLF1BDo)qW5n;Os>n7Q=F(@N0cuLuU6;t?^0%4@r6Xrn z_0Tbt?=01=|B?|+{E-ofEhJe%l7zzXC^oF(^t><#C$OESS-JAX#iLfmzUOcX{Lv5n z!v`nVMJQ&AKY9%k(G~}mYP%eXkQMr;Ncw+FA1CMy;Q{?0;BG8dd;bS&J+a!ukL(_q z6B&kQ|AX5wZLeh}4qTwJ=ZBF>##Zm}Tw4oXdaML%(DN@yug zrPi8ZLNl^}ct8g%fAEB8peay~ND-P;g|u#SQ@ZZ9u2DwadCSW-1F2 zrDi`jdz$bPO4Bcy_rR$@hbVGag?I*%u#0s&(jk!nLfw9Pfu|XM;F(M67U^LY)8aYd zeJ&txiY=tCn|S?4XA;c<3X+mF6eo+6p&J9)qOcY58d`Qqup>NNbnkx>xlC|xfBj^n z|BVs+cRZZ`Q}6Q6Qr9<}Q<;$YZx%Tb8vO@_Z1LJDhMaO}5FLqr+CseFvKRECQ{mbrWQCSvn7VH!hdH?2yd0 zUH6twLVkK}OSaE~QAbn@bdbN&JHRb?#e5)GP|FJ`jT3``UrciFoa7n ziO$R`-crx6D5ZW$6%_J#XHavWiaZNXhi<}?%HJ%HS!9>LU21ji+b~sgpLt$sZD!S-xsP?Y&m$}%h zyg@AB5!W3$@9lJJIab70PX7oF30A&a38Y4Q5!Ue(Yixw_jgrJ02vlp~$T~$1qV<2| zVmt6^v5?(t9yT--G24B%Yux$W>Ps?Zx|aT0Qm@&hA8k9v>~XR1Zg!~VPZ7uD zhtzf<>>)4sYl7T4HZR#7Qp(9|ek~Qn5GfyJ-=1Pnet~+2i~CHtY{I#9gz0n7lnI01 zAG8L-MJJj!xFpD0bid69*Ee^VShpN5YpA3B_^2Y++;(>2Yq-UP0$!`$p7k8EtG;Rq zWRB~?0mu8hvCO>h5s|j}ZFEyqJe9fvIw$IB)+=6|%!w!)IUh3_72fAV$UX5$!kf|K zOH{IUf;Uo_%qRbfMq4N+TMNWTw_jWqVtM@ei2|GUbn$$*_Oi3p^S?P)8Son;s$BUv zUQkS|Vyw1u2hCP>&ZksQMb*B#+-h%ek*p2WFS3`xzC?x$_GR{_B-e2>CZ<1?>+OA= z8*VDumK})btkKEJi5KW~)4%$1XBb~5@te62QKmcmGcLHQGyP!R=h?Qe2b5dowtDGo zD1R+Ik}iuOmTR%K9rDphHbiw17#K)8n82wI&Wv@}r^v*D2d+GB2=dGOKZ21iIDy>q z?5!pYN(gzENFcKV#(D-mEJS?@lrm4@HQKhC;ENM07n^6Hioi#%M3<>d!4Jq#sq;R6 zsLt?+2-5#1b^`b;oH?&j+)FhfV`(jL=OrFR0Esm` zOTQD%DCRa~z+M0QNLwQE6=GokGo!PRg2GhU79esUxUxfE+(FNwc$EsNbQTzj|FmTJbb!2Sp;-ys!103&90Kp?bfU2y+((0cZ( zj*X9Z;}BhxHhO~TaSJrOi0PVW&I+iUncH3_ioeF7zhVYl2PDVmI5C+O;;t(C$_%(|`>*aRG=KRoeFYXhkFXsKCqA-jKTl2E1n7LKC;>KO) zrqhL@bVW=BjKBDLn2jlALJEQ(CH%Q&%B7uGhf#v7c@xIkWtq#aBe5|=Gj<*H+z-6^ zwa|g8gplbuBsk@F3{rvf3~z~@)HbbIQpi*Gxe6Zm)vyaoxwQ}$1RhUfq1FC<;4zu4 z-P42_0?I*zCH31R&Fz7yM8f@AH0Ba!f_Cntfa7O}hf1gd(L74Y(62;vSVcF_ITkwsUU zgMH@bp#)O2vC5nJIsPr+04zTI#>)+cyd?Z%f{Gl+4wJumb8DZSTXjb5Cp-TfHC_rI@YCev2j^D`n_H>}x zn!hzd2k!5OQ>jfsEG&6Q)NM-BBwkNo>P>(%mOe5f^yhc2E6{_0je< zHm|R-rkryxr7Hgq+nMtv$G(5oomq6AIn*q;Zb@RGKH^<|Tw!Lw#gLD+>;}|45oNzO zL=9v*CrhuOr=&C;&~!{LVO$tFXr>r!bpu^c!lHG3NX)C?orLwdl7ZnM#6DMc1Yd(< z$pAzv!Yzc137#^cmKXPVp)~CsDd_wRy5Rt}+t<#r>)5^$7)nKf2yquUfdOa>o0XkV z64JY3gEvP)Q&~@jkV9Xf88JYDYf3d(P_q7G>(RbbB=!aE7zesz0&c@-B=W$BqY6&O zCmWnnVJEQZC+IO;Xx!aG!A}I25xryz!cl%-CeMA>u8s9XQ8>h(e(yBjK_TunNRtXB z-)2o)&z|B^+xFZ7nhc5tsLnc=If7Ic$Ri>U-wa_oBupQ@MFUzw*J-A2!I znVcc+@%-DRTA5;$`B|=?AbCL!0q7@80IyknN3#h57iJ1v{#dQb|cYwIUn4u3{OPxn$IBJrJ z@&cx`C&3ycre;>U^XXP97T4qsvl4fjkIRhjmj9mK<1btN{yy3rN%>B#BklxK8Dw;d zk9<>Eny!25{sGBLn@@gu*Beh=wh-glMRDqXnPixrMrYF^7Crxap*UE??ex0dIQ8;6 z(d^FBpzh3!Joh&}%p_rTU(yhArrg%%sq;RzLIzpt@7j-pZEuKpnyk`sTf3M0gG=%i zYAqJOHM?2-=}i-~`0j4XJs)o-2 z7|xYp4s_&H->|yC;HRewIED2mEr2E1e=6zA5^A3hblyZ{Ql>nCW6xNRJUu?0?)U9e z#I%y4;tXa!lYjP&Ok+(RBq9Bp%Z*|p=$qv804~0K#i`&L<)7HN4UE1}ItY0T%g(ls4JGm}pFb=MOHjulE${?Vd@vIvz^ zT%a8+k{6{^5L__G$t(UTTH~bA1m?f)55Xuw_3ySJvGbB!OMWx%JAqJeLGk*;2N3l- z;l3~a#L@ku(MPA~--S~oo&W#dqW+t8LzFW_2DSKeCHem!{>(pB?|;g?G}r?F3kSxx z?)L)5@EKr04KY(d;|~<`*S9rb)bTfcMMY`|d9@wbg3+8?&w#LIfb0QBeigI=`#OT* z-$FQq039A2pLT=1K?50{9A=e^sf)!I{8yKe{|OH!7_BejmxRf(8Tf({%!eTd6vUto zHL+TijzoR#xhdUwiN{cr08x7ptR^C2gOpS}0zwb6EKod*{s_N-lE9m=`)`zFvdaE0 z9L#FPUt7+6ll(C;p%uu`9a&OR0$JV5X8RIQc(SjH&dNP4DH)rX$a9H`iE%>4NX(id zj<7|YMuL_P8j8_eXGy@;J!j}1xL|<$n$DnUOX7Y}^ap3rM#Nis15Qu$G30$#%BiTT zQh9z$2n`LzrB)MP46ymN62-1&4g8p%*7tk`R*?j;o_vfjXYllj9tmd9cGgt^By zcZ04g9pC=$H?-s_Kgv}tl8AN5J|dnZCCtv9A=&GRMs2sn>7M|Pgbi+mrS7Sfz`lnE z<1TM+@9b+W(haQN1QJZFBQ!>d4S+>tmEBE@`dhRC0KV7v=w((KUi z#lNW_iNE}Lo{w4mZ#^I1Wod^OjQAU>hYkrtY|MaKL5Pnp6qYfRHz-gruBH~8pVj4P z0Xjos4t)706y}@FABMyIZ4AvCc`pt=J^jDg8*w^hx`JHrydo->&oC4rCa$2?@Oj>x zf_h-{r3Jwq+YY@6LCcU3{Bf@4?1RrGJcSevzrE9aXG3@&&6&%IIk!drV5WS0V*12? z^RFL6B#M9Tl#tB+eXIUMZXuFH6!jV_K+AfAMjfV^_rSS9>MN2(XEz0KY{X!WSBu{z zMk$#0$Hfg5MtHL)v3unUICu6eH4NL1dUHJa3`VGH+v9Vn6m0Wbzdru)wY7Pdfu<9t zW?n*3(cRzg*m45?hsf8_z5CsN<3(O4afCZuY|DW{*APyUXi-t2gW)BY_x0lbeN7T{ zSl46Uzt{JNdlALT2Pg;duRNEsz*#BGlITYcNFTX*4%)=MI7IL5&%(ml2AdYxTHgLC zp0BXA^d)35wrO?nKuK8 z3}UmVU+f&$FwXfKkT^q^ei|Bs*Uy-ouHz9AD;EeZ(O0BUAlea!-zsAL(b0A}5u-ch zclZ|Cgyf(4HY##J=^c;_>dXBa!x}Ux77)bAaC+=H56=;I?%l1$)s=wr4| zmd^ChV!)9q5-?(}L-_y;QkX;ZK5DV*MZb&~+Ci8&x zF5s4Lejh7^6j6zq6oMIG6Ed@~>;cu+@K+FwFcR@pPY`zxR1AuCMmWRN9~lxcd`D0yeU4M->Bf#AHn8eE0bzg(WCdTil1)vfZ(nQZ>b$b#7_lYO0 zny*9wU4b92ts_yKC*}B3!oHdgL@b*Yw2wL`v0#ecem}w#cZDE@;c1x&2JnF0R<)x# z`wmiQLOoFRc}LzkTAOk~Kc$I57gBYLLXT&=44m{1yYOQS@)<0QHvk!mGjnNb6->I2 zq@%0_UGR|$5?KXg)PguFQNO`?eKkB-M{fw{zk)Rzl5qos$Kokc3gU3bK9lq8Sw_rN zzz3y|lo}?02uiC>7KOQ~d*WQBARPk5GXUrXH@8;IIv7S03rYY?-Ox8vdeRy2hZEI# zgD!ycryvWnqk#-^dgOIsy@CS}P0iy^;pOGkX)ftEmk!XygW*&TlttTH0bpKbMMZ_% z@d^F-$vm(hJVx7}u+rR{9C$4x7=lVVA|}RH#ovsXi|fjl$tG!CV)#cm_A~81x2sZ9 zu%F1nhhUyKLNJ;H{lJoFCRVmn-#Yc-lEBUBbm^j)Wilz}s*(e-`2%`BTCsztVnMw* zhd9*}J1`V_PS`EvTL1E>fE^mKW84H|`P7QK?L^=Mw`50b)wdX$Rn^I1lKlP`=J*gO z60!PH;rtC0g+R5i+n+saj0o>rP4cqZFr+Gob?h*8IcLkk1s{%8Yee2)7!@pS%7H#{ zaoasEd>8sU`_flDENYC6aY8-Tjxkp|EpER;KsW@$Pdtr-xEQiiu`^|{OU>}!il&di z*_~c3z8G^_>M(Lv)6~?oXGb+=d5|IukQ*V^;ERd1AwVB*kB65FU|~Z-Jc^Oznf8tc z_SDo2JPx>ZqK70U7uH1IY*;xK^<`KX1pgYRrV#!zAXw?cZ(lr%a|9P^su7-R$Z})@ zCitPOxdp$NlBtg_VQ0@yqB@q9uXIhYPVW`+0SO*s>Y_lx#cNIjIut{%slxx7G@STZ zh@1~8WfHWEc&PRWP6Ru``?-u$V+`qmoV-fy4bU^TA~_-SP|7|C0*NEHOX^lVS;RTrEZHhx@fQT6f%Bwo^psf+N%sk!{(sW&HC&M2JTy(D1y8 zp*KL%x8YAPLzo#yB4vozQXDK1!@ENdES-t($K+{{xB`B(MOp{(Sp}@#l5tN*f6aJO zaFT_Tm6e^^_|gjgC;%%uZ!@op-$D2b2d@R3!5y?c(udm~an*hxBAP?HYLy*QPNRFK zjicY{Fc=aY#8p_B9^T=tuZ%N#89)jK(7zN<<_sODS6$HLF`u+>4YxOI;S_k8k%{SK zPL6xz6v>nO`};$}^R6Q;LG|yM=^Q%L4SRQ7GI3OJ{`hc{3mll(X*Rgq(_(TZ~^2PU0A z&q%Fu;b>EGOeb_`)zn9KB|MEQqRRJ=}+tn2a{;PB*4e}dX`{b)l*gOfcT ze1S#t#vJ0blvDas1Un%EI6nHRWKgDrXHTVc0ymAZSwP1g2Bk{)z1M?XGi>d3C|CzFkR6BE=spHQ@o~~5!0t*d6E?JKdfF=e7ZkEK05GO%7f_pW*Ek6``ZUoKR8?W#dz$F5qK{ zv(mtT$j*uYvlB@%*DnDOA~@haJQ@U#FM}S)ftHb8tix_RS6S>eLPvvIhcK!z0LcnN z_9EHEM+e99bWtL5bMMY3G%VA{u4X+wZ?Z)K950Jbe*dmxaKATF@49jWXnz*+0n5h_ zzYS3~p<5Aede!K@`8F~Gis!_PEwy@L5P}Xd1tk(;9C7I4UB$y`LNro8due2%!u!`U zbRWo}bR&3S9_1Jz$m2|s)J;H7{fULo)o=~HMH>A|j7$i)ByQ~{b53;vgJ{w{up==E zuRE`qnu>7pu+bp!h)UhVRC}ICz~FF5mL&lF59o#9EWVA0g&hILKVhQcRxJ&bW|#d>=U@aZq4&wk-ugNnyf7Uch`~%~ zalP&rHA9JFTI{<8)h(p*ZAaj26>{p<%M<9_*g^b2fD8O(7Wje`k06WnBzYzR&p|L2 z0qLE^QIyV+A$s3s1*o1^zkKUJ@*yjH>uUjUX`BRCzsOn+9rl@ZlvfTxScaJrNxX?> z0OC&UCKdFKFmbdfq@yf()UeLMWYmV7fpELo8Yo&F=9K$wEQ9 zGEB}aBKZ&YC;Bv?vf7PTi#VHLS?ruFw(S)HJE`gnZfmVUyDhorTa>7!5=+nfU&)g8 zD~PD5`1S73Au%J4%h>;Rz=`Q&B<4^Uj9zL(mncCS@)}~^r7&7}3T-#S_CSMmd~B?X z%w+(R6-P*G;x=X(NMsy^L@igOcV1 zIx5So25^zk`Ad6}Rj6qIWwDO1#7b2Iuyh@zWEItnN z9}>j=_U>TFr6@daA+Toh!1lKVqQH4b`g(=An6o$76G>hX?1#V9O9#j+K_%wOhqI+2&DWU=; zA}nl!cCYcN62&dw32YB%oM&xqDd-C>T$(F-S>%N5<28HpJz&Q5F#CFeMNV>1GH#AI zuU?k*yoGXh4Vlt#=FG=OD5Kx+Y6R<9X>slD{#UA5tSz40j>Hh|Sud~}HW}PnMuB$A zX{_rRvZeZGjgFRZTOv6FRKDq?H>TrTi0_A4x-DvVVn+abgRP|0wg)YZeI@rF&rDU_r-4wtL^&3chVAKq{e-$Oj>2F@X~K zStjak)e@8I9^;z?Z2GVt={_tNv@-YI=Hjw_Pg>`wIeYs1t8j?BUnbSFiJ01@ql5qr zDCrQq`^dgV?iyj}@AUfGh}7`P2p71s`R3GxEpJQkdZgMu2l6&{J^rj_q-y&!A2DUh zn>5V?>4GO8Lw_JPF>}QmQAX zQo-UN^Gt?56`+AH$Duh2!kZ0J++_1h42Y`Nkfw|5zxN`XX(JbR41knHh$gHs_{7|g z;Tro`r8BXyv9P!H#D(|5uYiJs;vz{i)GsKx$*hsi#B%ZmggNx75vQUAK%HH&D-LBA_n(c9mE{i;3P`wfE$4tz%)(5QIV*3X2<*MBn2SL4 z1?p$xhl%Y6?5khGVCD3?!?&?iNe>W`0D1X`o6+3r#WK;mXQxRl+c2b3S4AZZ@CJ`& zj=7&gw%5C&U(ewH1G7$I^FaDmSn{SN{*t6X$7ew~_r7t1Qxq0;hu0iD4!t(TUtwRf z=5<cFE5!q$0Bj*2FFyxwe;wcdO`Z=nsT?EM3eQ*TTW)>DN-p!4%il=&r>Srz3mf zmnsTD7L5Z>&uEC_Onu}5!UID}M67Z>9XeQAoErPmgDMpe3>P`}5oOIV83Rv7ODCM5d1x*U z3@v+495`T94o6pIpju12007hRDz^*p4E&nVw`<~0b50J#$Runqq!je8_)BW^}ZA{4I478ybll{oGrU86Aa@WjCE9AZpja^qu^ z)Jj-RFatN?w_JA!BqM^AA`OAKVMWNh!~Lh(tvoUvkf&@VZ=I}0C}1R!IV|hKO238r zl|DvnjugPCjQ}F9g&%m_htX9RPt~fbsWCG$Qp!P%AhU}em~L)|qstX}pO-ifa{ygP z;k;YS8&wS^CX5YKRlK5zxS}=h8Vyr_qH$;9;(}kY)NLeLN$IsHg3v%Y6uId^_Jy?j##wCoN7rgs)jcb^mJWWHu3w8;M_kaf4rlS=I{xWdH~zmak$h?7#SGqRpHw;5V<@qFDoM zRvHnDN*CsjlVFaMi8Liprrtur= zPvlfO=6yFdOZ2{p5MR6@!Duuykkkr@ZC8NF%K^b${%_=uk|J#gBsv`Jju;O|5U9pf z^?_o%EsRX=0{hJ~LR9oqOqHE2ej9_}LXpQU`FT)QTmjuER6F@u*R+#X4Qm-%Po|(E zBC>f@9U~uq6h?-pT_>o<&;{?4?@%o$h%weOp{k28x$qryG?WGu0+y5gM$WRhZcRZ< zz>b6eNDPo41^EjWsg=f`S^#MgrwnAQhL&FsOr)dN0_PnBQQGhL3WxYb;G_#OCjoI6e^LK>Hb{jiBGjh7Ug ze04=As)?=!`3EwcS6dc1U%3w#^!s2v*r6yUgrdfq8rv~7n*v1r6}w9c&SBQY0J-6Q zST)E)sZtiOi&&i4F;UNKs0tft( zZ`+@Q`LDEkeRh-1{9go3fK%zjE*N|Wk(2#)V5&?u^uXv=u1ey^gS>E!qNivNQ0RCR zlL!nJ9K29@1eQ&Rf1UtoA(9%o!^q7CgaUv6^Apkc0vPxUo?l^cP0-_fh&WKFs^F0X zz(#k{(k>5Sgc!Ym(fN_wEjgM1Z)q4rTuMZS3g_&X*#G$ZzHOu-N3DACsq*jdhMxi_ zbxEMdS~c7})q!Ih4K%ayvW4HV*alL8Gh;@)CME~2SgY_0k#2cB6^+SO1)ndh7zFpc zp#f5BD7kPI_9*Dv!KjQ`CD{gxhOXY;3Sxd{kXpTE`Zo%G)GuKjulH0k0qTp-Mv-9y z*jSG1+))}jItNq;0oxl(Frugk?*~ZXKBH$vO?)5Nq68X_WJ|yLCHSbuI0{rUhiF1U za41KBrI0!Rh{8>jKJ+od1Ap3um%X26zREI|N6^-uMj|%kk43TX>Vz}L3KTe42@zP@ zZI)D9#5Jvc7Xq*XO3RWl0@RN~Mn;Cjt?)4}k(^+sSrWg2#(-TVY*kXItz)UDJMmJ= zb2ZI3UZ`Xz|G=n74He|WEQpa1$#y=!zOIj@&JE9+Vwhzx@1QDMWAf8G5cJZLAMXzk z))GEei9#BxK+!QkYg>sh_T%+H1n52|^Qrvx>u-;nFA%;B zIk!;2dVC)=0G^3`<{J6v=)})=4de?)gPP}FpUpqs7pIP#c{z-QuUO8Zck!GM5dl?H z5HcdkMR6>1vpP-*o8|F?7etFjOortg5=#(H1#qeqkR!09biXAc3q19fA&mQ?MJ9%h zI?6X@9v(e!?}r_aO9IEKo;)p?mtVtFt4Vqfni)84SQfd8<`&N8QCZd<^~Ul0I0;Y< zOZsnVhuq)a;{?RHoOCJ4Y{Vzr=8ucP3Pb9l-*^HoSk#T5L&Et*$pEr5^xQAeQ?)$C z^cA0rYgvcJ5wV>B9*f2lX>r22aIvG+cYq}2X@*UinzN3px{(KS0saH*$w(BKf0_z+ zjY;|Bm05R<9heruWETPN1+R621rmHhqkq z)E9K~sBVCL7jY!JaOD(cuRC{^D&Yjf_{DG>G9*;8=qo-WfGPJibmS`*87fOiOOQ-m zMBM{VJcdfkANR1`kwy!TUmqwLMgMOAsqI0ewGoA|rkc!7ZvF^=;T_(r=4eDPV0wF5Lym@PYw-53b$76}i!_Jx=WfF7p} z3TYrQ+O;M)-wTKpkA}Qs-*sX;*k{B41UZ7#k&n`)NR*9Q?4AI9BRy6u@ie%3pr- ziNN4fR)f#C$uxI8DPFKbFA!hpZp{^c03bnP{Y3_2VwLVB9ys7c;(6f3Ja62fMc+i4 z3eJR3r6Io@ZQ>K|$$}7|Zh_4wfS4t4CD0?|E%sfHiNzU@KDDIx;9jfaBirzttNyBk zV9)mu3Bi8Ae>Z_XZ2EZJzlSC<>%H@b+zoK@_Xb^}`t|GAj_=jA8qi)K%@}+oxF zIy&#mVd_XL0+8A{w>{oM+A|nq^WX?hP&h`Hqr@Yy<``z=Hez5y@e~SERQ!A=fWi>O z9!BL6ZHAx1e6S4Lnrz-hNW;Bx^mgk!u7Z$XgwXRcViwrkYQdIwnVb*N*ZU#6z` zqaF%?D;dmAeRp1fbq1MI6{oY3h6cIw>P>9Z%Gism*GhMxItDl7IDkNSy95({2!h@# zL_y+lR};&NBVQgg&?<7r$S_DbfEM|4v?r-6@1OiZjy2RKXc|OR1}R|X)*Xp_(#Isp zHX;2e2a`-5IfEIXL(=E)2#YtsJN)|bQ52Gsj{>>)d{w0UXr7>rAp{0g#spq^jR zK)EO?z~k-+yv!Hlu~Aq^qVE;>NbHj6(3_h}fng7zF|(p4{vOiHXfC-X$LwnXqNAgu zzW}Jl&~I!5PP&7Dj2M`V;#hs6mN`J~&XkqkYa8$-a!!>p&ory*xxj{c{L zhrg!|f<_WX6<~)_-N5ie)ZJH57a_!b-HL0d{Dw-?lXR;J*+^Z-&2hOGJ_ZRerzMUB zz*{zfDgKbu;=+QJ5dfNZhaUx6$E^e#GW|+I)5%dS| zL08Emv(E*EGYtd703ve+t|N2*h{mTl4@?D>25?wjQzNvPH-Uo9i&E-g>T}Rc3>Tv+ zn}ALSQX+2;{?>1xhNmOWL9)`49fVy(h~#hyl^2$(sU1#~{e~@$P}qZ~RglFKi0pwh z5^>V_xQ4_#|Brf37w&Ini|Pofkif>eiShz^nA6x%1oK}5K@2KTGSz@ol&RPyl9;Hb z%Z|Rv5|S$O>yj)F+0CYO88{AK#8FFf7i!hdvH?mbeSoz9`K@Bu@e68HYDT|p1q6vf zoEdy+!biU!4aQPXh*28!4(?sFoFm+AgbRolJMc)lpl1=3kYEI~sD4(6ujl*UQ1My; zL|WZPcQ^3!^Lu_t>)QfApLCx{=Mff|OG5~=9wakrbwM*i_?wv%o;~J9Otb*txByGZ ze7x?=Nl2`)X?rkt?(u=nE#epkCy%5?ip({}T^;q7jn^d`8|?=2(vWsRBpr$bjC4WV zK9$tgU*5{ijbVO^xGq7k*OEbhPB_Cb;}VA(`43@(=OD(Z-To099E!Y9=)?}h^(*x1 zd94T*9H?6WCyM=^JA@lXIHApYm+Zg%!@n3+q`c#h_ZBAgG@c}ALiV6s*i09qZ@d?1 z3ChDV1NzSDl7jkvnHM)L23EP#vYnnNRQ^)diga1RjYF^}<`F?chY z7DvZO-xV`r+L7TY{{G%f<_;hOn#Af;0Kwz3a!^s~p7UIffkWb`xX@$Ai6`5OOo%>G zONHNkv8PCYwySm@Z-}l1od%qiK0rZ>o~@vTs>N{CVkC7>*C7AXcoWm*%a%#Fe^SIF zpp=&_%xhm)4m$MqPF(8l3!B4ZV)P#9T@^is?SuK?w>y?^MW2oW3S)Ez zObTUDFe5*<#YV<6k3gBNATNCu6|lZAXs`e?A0opW13Zn%S?k??Hlg;eCHxqU%MS0! zEO#9Dgq%eyH*U>{xItyOfm?C z1Z`QRY}DeIbB_bVA8gWy=;(SGmkWech}%|>kLF6eb~+d3>}dF#yawDQ=%#^@Q{WpM z1v86Uh2PAlw|X_H@X*Ro1%9{hm$KJIp9a#IM!i>uOJxq`JH%aV#7`UmlsqWyaf-VZ z5AHX|1hR$7Hiva!mK8x%@NI>QRKEXAhwT9%M+}d1%X*Z%rHCrU?f`p{h%L~}CL(vp zz^|gvmqcbsK@a~W8aiB{NBu^(66BunCCgVy9D1`Jfk+Mc9;h}0NVB}W{o^%Jo7&;M z5ttcW0QgDyAhaP9RRXic)7zgk9Be6VJ{tdlHV+t2-t4{EmM!@RwfTewRj4JVV9=LE+Yne*Qle^+mah}qjMYlLnBO$mThr$G(7LT zk>11p;V-M1g5cs+@5Rq%R1GJbKR?&T-jcQZ`lspN6b_Ion3YG!3+ zUC+<2;(bBSz}h-?V#15E6GD$294vB4NQLaduRx+wMGUjWu8MVGnL62H4A z)5s2#OsG_=(SlN~*~sVRuUHQ6ik&$v_Ru+yB=GIwZIm1L?$NzgoTP&n(636aP;UVs zE2q)O-+#|^gZ!$-jRFD!8x$1Qf&3E7^;;1kP3SgXCKv@g@}tfY9E^;NHa`A7VA#Ei zRvU4^flbI1BqqZxoDC}3-GE{8^7F^h@iFgUL+g&AhTBv{g_%rALApaQIq0aUD1|=5 zY@|LXzm7f`+m-V?EeUxmQ;Jrc-fb&4wpW-nw0ZA=4(r|emMwr4!=NJAASua&omlWT z6%KhQKTg($hhL#q$PEwYADfyY=#>O`URgzY85L;y?KLqG66Vxg!_MB)v-Psh88Dpn zbTG`$G6Lv`mbUgyBN1qlXs_y>1?Xn+^w^rU=T<-=vxYk^{6+VJrC{DHfzId`vW4wG zii+eh;F3l|XpX2eWZ2ktauEIa8*UEz;7`)^FIb%R~M!?NclA%A?nATZQcX zkel0yLASMh>WxkF{FilBfUSX|$PNwv`@WpF6(AJ4MK<)? zfmN2{sWGly8wqeAGDe*lbuuknxQHed&E}B1cSR`WC}D2CJG?w&<6&}wV&zfcn5e9( z+8`!IudJ+$5v1xc3cY*x?ifH7;sSpwHJ)2bOAG7`XT#X=@SU2P5g{sXc?b^%7i|xA z<)K4|c6xb9J$COTzC%4Q7-iy)4S%sIm%M^dh-1meyczyMy22Ej@(?PpQ`cOHPSeuW zJ)M;$Dk3U+zgmunlMz~00*7Qxin-$mDRtQXtVd6FA@V+w;GmN|_FY(crfVs})e5j# z*)GI??H?VD!5?2QEBoQDm9a5qe)p7(zPgi{Nkbgy3I3yVU736J>eY9$vi3kbF?a~i z?zDD0;0g+?OZkL^sEMk>Jof;e!a22ys$YG%tgDuz(R+mc&5vVBz&av7el)*u=@Os3 z{Lh=kb1xnc&Y`ifF_|^kf2I~;Y9m%O3d0#F{+0{zZ^9DwK+={%HjKlL7)GQHM0kh? z)%JF)loY|HR$&bqTU#?AsHGG&9ttZiE)G#qnF5cb92lMJ7Zh8eNcJe@U{ahAs(B1H z_%C#@_KIA*6u0-H*6A;xRfNhvz~WDmrCE;4`+2$_@9Bk{s7&(l%F6r&r(%r zp5u~ZCSJGi@0l&_`n1F~zco5Knog`t@a%S+YFM>5a&s9mN0&0%;ZT59R|%N+l#nY| zxIp2g)zO?fhTPY{!Xg@NuALdpkbkfck6ILUU0=S4$n$7QgHU(qkvWc0UXo%#Q*!^B zi}c!Ei+fsqWd!y#ya>_SySYE>{+HXgZv%NL$LY3QU}L73RY~~Fj6XV#eB$B^G&D4Y zD8QrDHtJndj6e&hktxFbA(WPY^j14MI#MW)%+KM2Hp zep$!q$(<|anyt(X>}<{^K~g2)umVLw}6uTz5mzSYa9+4SK*W(s)l;DsEobgCW;ZI3U_W1I46ORoO zQ|n2xVEL0UvzneqaphAh_eU)~;M!>D=&*9f@+4pbMMg!b)~t{31JKF=W}>2!5+dWx zeVI4*WfC&%9V3y(@j=NgI7kuOwr$%6vD0%T+Jx+e%BvgaJ2Q7IKR)GDT>)ngGx>NhJ`gMKvw8RpT*{{Qtk3{3&$bX^6 zdX6UWG69@-JX{<2`M&HVvltMX(dyeQze;Jhp&?6NUY-XI&$FKxA2~M*VvU*m0hwfF zW4jf+Fn=p`uY$y79T@K{_xL6;jI;z_NH&bX?>@!&_;^bDIx0}*1u->i%WEA$7Tl^N z9<;$YPM=i_IDO<9Q!K95pl5=y&oo`1WO^8Wx~tR1ZREsw3{)zco2vI0I;Z8u>^uREvC@1DdWVjUl8F5Sz8u5#8gt$}WK$Sla7Y1*6?y_w{x9B$} zE-YMCWbmckE+ex?Fk$?Cky!a5>098yihmy!8&e#2U+f7QCMJWHw7tTccOYST z(a=x@czMffT3Xt;l$1J#h`u*yzps8`5rg!>78x|ojw)bF24-e7?Ck7~<1gq}oqpbA z`J-#Dsp3R(a`O4hmm?q^T&brUn|kx+v%D({_|qC%TA>zVH6YU4NN_C6z(S+{ip1)e zj$i_fkp8tWwbWe&ZXM=9_i^gCs_%*E#Z6L7Q4|sY)xpWhT={#7j$r*&g+zt07dJ<6 z2Ph`WQHB{98HIs$MNQdz;6N0xrEVPB>_~+ApH1JQ4tCen)TBX=RzZsSQ9e*+@}dBH z?9$Vt$5x`EU@!h!w@1Z6Xq04mqz!Z30%bR<<(67JB8!mq(DvFjN=Sn?Bz=j}Zg7d-#*zUpG-rn8^AOZc!>=r+o z5LrQxjRyVS2FwX0dXJC2@}vxGMRNsJ!8*{;VL3uY=^GfZ2jLi6fJ#5oh625K`7%^TumXY16O)S2Q0G8cXGGEx9)8EtgBmMy z8T4XDvtFaT>Cn`?vk|x}HAP|Qg`BjEjD1IukA}APo;`b(Qcz5FGzn;-B#8L? zw1-?>$%R{5a)SxA5{j3`IQ)9}$JHd#d^N&}ics>R-;0%vnBC-i#Aaq+XIn|?DNpTg<0XYp>=BFO-Q@+_{pqI78&{pNwVq$FYaC5yu4){`XP z@Rj1ABRnq$DNec-d$MwjMJ`@N=1P9<4EJKY8LYc-;lho)Jmz!f&Rt5zCn3TtOaG&W z{9;bRJ^wCM)#U)NLLp5xJ;(g1GozAe_rRM}bq2t{%i$Uho%->tx!h z3}Oh=yOC)~lDs2uEKK2eiUsG&RwT;0isV7$hg`u(( z&+j40ynzY!CIgR^+yhYV27erDlwADH!3~ATp~J74R#jD9>O@(>aDRUk5*i2od z4BP|)T)Ha@3R4#r1zlZU;OOr$;P6de==oEp4gojcbOKukTwb6VBNvyLM}9z63BYbD t@DjBBzO@$?IG#9jMq~omeI4(9%PYLyAGvI2LN)^sc)I$ztaD0e0stSmz0m*w literal 0 HcmV?d00001 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/docs/images/log.jpg b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/docs/images/log.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4a98e48e4dd781313b299c0de7cf3a3ecc9d9c82 GIT binary patch literal 117637 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
-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 literal 0 HcmV?d00001 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/eval.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/eval.py new file mode 100644 index 0000000..ce7b04f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/eval.py @@ -0,0 +1,26 @@ +import argparse +import functools +import time + +from macls.trainer import MAClsTrainer +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', "配置文件") +add_arg("use_gpu", bool, True, "是否使用GPU评估模型") +add_arg('save_matrix_path', str, 'output/images/', "保存混合矩阵的路径") +add_arg('resume_model', str, 'models/CAMPPlus_Fbank/best_model/', "模型的路径") +add_arg('overwrites', str, None, '覆盖配置文件中的参数,比如"train_conf.max_epoch=100",多个用逗号隔开') +args = parser.parse_args() +print_arguments(args=args) + +# 获取训练器 +trainer = MAClsTrainer(configs=args.configs, use_gpu=args.use_gpu, overwrites=args.overwrites) + +# 开始评估 +start = time.time() +loss, accuracy = trainer.evaluate(resume_model=args.resume_model, + save_matrix_path=args.save_matrix_path) +end = time.time() +print('评估消耗时间:{}s,loss:{:.5f},accuracy:{:.5f}'.format(int(end - start), loss, accuracy)) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/extract_features.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/extract_features.py new file mode 100644 index 0000000..c707a58 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/extract_features.py @@ -0,0 +1,19 @@ +import argparse +import functools + +from macls.trainer import MAClsTrainer +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', '配置文件') +add_arg('save_dir', str, 'dataset/features', '保存特征的路径') +add_arg('max_duration', int, 100, '提取特征的最大时长,避免过长显存不足,单位秒') +args = parser.parse_args() +print_arguments(args=args) + +# 获取训练器 +trainer = MAClsTrainer(configs=args.configs) + +# 提取特征保存文件 +trainer.extract_features(save_dir=args.save_dir, max_duration=args.max_duration) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/infer.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/infer.py new file mode 100644 index 0000000..6312cad --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/infer.py @@ -0,0 +1,23 @@ +import argparse +import functools + +from macls.predict import MAClsPredictor +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', '配置文件') +add_arg('use_gpu', bool, True, '是否使用GPU预测') +add_arg('audio_path', str, 'dataset/UrbanSound8K/audio/fold5/156634-5-2-5.wav', '音频路径') +add_arg('model_path', str, 'models/CAMPPlus_Fbank/best_model/', '导出的预测模型文件路径') +args = parser.parse_args() +print_arguments(args=args) + +# 获取识别器 +predictor = MAClsPredictor(configs=args.configs, + model_path=args.model_path, + use_gpu=args.use_gpu) + +label, score = predictor.predict(audio_data=args.audio_path) + +print(f'音频:{args.audio_path} 的预测结果标签为:{label},得分:{score}') diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/infer_record.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/infer_record.py new file mode 100644 index 0000000..4723439 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/infer_record.py @@ -0,0 +1,58 @@ +import argparse +import functools +import threading +import time + +import numpy as np +import soundcard as sc + +from macls.predict import MAClsPredictor +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', '配置文件') +add_arg('use_gpu', bool, True, '是否使用GPU预测') +add_arg('record_seconds', float, 3, '录音长度') +add_arg('model_path', str, 'models/CAMPPlus_Fbank/best_model/', '导出的预测模型文件路径') +args = parser.parse_args() +print_arguments(args=args) + +# 获取识别器 +predictor = MAClsPredictor(configs=args.configs, + model_path=args.model_path, + use_gpu=args.use_gpu) + +all_data = [] +# 获取默认麦克风 +default_mic = sc.default_microphone() +# 录音采样率 +samplerate = 16000 +# 录音块大小 +numframes = 1024 +# 模型输入长度 +infer_len = int(samplerate * args.record_seconds / numframes) + + +def infer_thread(): + global all_data + s = time.time() + while True: + if len(all_data) < infer_len: continue + # 截取最新的音频数据 + seg_data = all_data[-infer_len:] + d = np.concatenate(seg_data) + # 删除旧的音频数据 + del all_data[:len(all_data) - infer_len] + label, score = predictor.predict(audio_data=d, sample_rate=samplerate) + print(f'{int(time.time() - s)}s 预测结果标签为:{label},得分:{score}') + + +thread = threading.Thread(target=infer_thread, args=()) +thread.start() + + +with default_mic.recorder(samplerate=samplerate, channels=1) as mic: + while True: + data = mic.record(numframes=numframes) + all_data.append(data) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/__init__.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/__init__.py new file mode 100644 index 0000000..382021f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/__init__.py @@ -0,0 +1 @@ +__version__ = "1.0.6" diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/__init__.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/collate_fn.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/collate_fn.py new file mode 100644 index 0000000..354e37e --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/collate_fn.py @@ -0,0 +1,23 @@ +import torch + + +# 对一个batch的数据处理 +def collate_fn(batch): + # 找出音频长度最长的 + batch_sorted = sorted(batch, key=lambda sample: sample[0].size(0), reverse=True) + freq_size = batch_sorted[0][0].size(1) + max_freq_length = batch_sorted[0][0].size(0) + batch_size = len(batch_sorted) + # 以最大的长度创建0张量 + features = torch.zeros((batch_size, max_freq_length, freq_size), dtype=torch.float32) + input_lens, labels = [], [] + for x in range(batch_size): + tensor, label = batch[x] + seq_length = tensor.size(0) + # 将数据插入都0张量中,实现了padding + features[x, :seq_length, :] = tensor[:, :] + labels.append(label) + input_lens.append(seq_length) + labels = torch.tensor(labels, dtype=torch.int64) + input_lens = torch.tensor(input_lens, dtype=torch.int64) + return features, labels, input_lens diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/featurizer.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/featurizer.py new file mode 100644 index 0000000..d880f2c --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/featurizer.py @@ -0,0 +1,132 @@ +import numpy as np +import torch +import torchaudio.compliance.kaldi as Kaldi +from torch import nn +from torchaudio.transforms import MelSpectrogram, Spectrogram, MFCC +from loguru import logger + + +class AudioFeaturizer(nn.Module): + """音频特征器 + + :param feature_method: 所使用的预处理方法 + :type feature_method: str + :param use_hf_model: 是否使用HF上的Wav2Vec2类似模型提取音频特征 + :type use_hf_model: bool + :param method_args: 预处理方法的参数 + :type method_args: dict + """ + + def __init__(self, feature_method='MelSpectrogram', use_hf_model=False, method_args={}): + super().__init__() + self._method_args = method_args + self._feature_method = feature_method + self.use_hf_model = use_hf_model + if self.use_hf_model: + from transformers import AutoModel, AutoFeatureExtractor + # 判断是否使用GPU提取特征 + use_gpu = torch.cuda.is_available() and method_args.get('use_gpu', True) + self.device = torch.device("cuda") if use_gpu else torch.device("cpu") + # 加载Wav2Vec2类似模型 + self.processor = AutoFeatureExtractor.from_pretrained(feature_method) + self.feature_model = AutoModel.from_pretrained(feature_method).to(self.device) + logger.info(f'使用模型【{feature_method}】提取特征,使用【{self.device}】设备提取') + # 获取模型的输出通道数 + inputs = self.processor(np.ones(16000 * 1, dtype=np.float32), sampling_rate=16000, + return_tensors="pt").to(self.device) + with torch.no_grad(): + outputs = self.feature_model(**inputs) + self.output_channels = outputs.extract_features.shape[2] + else: + if feature_method == 'MelSpectrogram': + self.feat_fun = MelSpectrogram(**method_args) + elif feature_method == 'Spectrogram': + self.feat_fun = Spectrogram(**method_args) + elif feature_method == 'MFCC': + self.feat_fun = MFCC(**method_args) + elif feature_method == 'Fbank': + self.feat_fun = KaldiFbank(**method_args) + else: + raise Exception(f'预处理方法 {self._feature_method} 不存在!') + logger.info(f'使用【{feature_method}】提取特征') + + def forward(self, waveforms, input_lens_ratio=None): + """从AudioSegment中提取音频特征 + + :param waveforms: Audio segment to extract features from. + :type waveforms: AudioSegment + :param input_lens_ratio: input length ratio + :type input_lens_ratio: tensor + :return: Spectrogram audio feature in 2darray. + :rtype: ndarray + """ + if len(waveforms.shape) == 1: + waveforms = waveforms.unsqueeze(0) + if self.use_hf_model: + # 使用HF上的Wav2Vec2类似模型提取音频特征 + if isinstance(waveforms, torch.Tensor): + waveforms = waveforms.numpy() + inputs = self.processor(waveforms, sampling_rate=16000, + return_tensors="pt").to(self.device) + with torch.no_grad(): + outputs = self.feature_model(**inputs) + feature = outputs.extract_features.cpu().detach() + else: + # 使用普通方法提取音频特征 + feature = self.feat_fun(waveforms) + feature = feature.transpose(2, 1) + # 归一化 + feature = feature - feature.mean(1, keepdim=True) + if input_lens_ratio is not None: + # 对掩码比例进行扩展 + input_lens = (input_lens_ratio * feature.shape[1]) + mask_lens = torch.round(input_lens).long() + mask_lens = mask_lens.unsqueeze(1) + # 生成掩码张量 + idxs = torch.arange(feature.shape[1], device=feature.device).repeat(feature.shape[0], 1) + mask = idxs < mask_lens + mask = mask.unsqueeze(-1) + # 对特征进行掩码操作 + feature = torch.where(mask, feature, torch.zeros_like(feature)) + return feature + + @property + def feature_dim(self): + """返回特征大小 + + :return: 特征大小 + :rtype: int + """ + if self.use_hf_model: + return self.output_channels + if self._feature_method == 'MelSpectrogram': + return self._method_args.get('n_mels', 128) + elif self._feature_method == 'Spectrogram': + return self._method_args.get('n_fft', 400) // 2 + 1 + elif self._feature_method == 'MFCC': + return self._method_args.get('n_mfcc', 40) + elif self._feature_method == 'Fbank': + return self._method_args.get('num_mel_bins', 23) + else: + raise Exception('没有{}预处理方法'.format(self._feature_method)) + + +class KaldiFbank(nn.Module): + def __init__(self, **kwargs): + super(KaldiFbank, self).__init__() + self.kwargs = kwargs + + def forward(self, waveforms): + """ + :param waveforms: [Batch, Length] + :return: [Batch, Feature, Length] + """ + log_fbanks = [] + for waveform in waveforms: + if len(waveform.shape) == 1: + waveform = waveform.unsqueeze(0) + log_fbank = Kaldi.fbank(waveform, **self.kwargs) + log_fbank = log_fbank.transpose(0, 1) + log_fbanks.append(log_fbank) + log_fbank = torch.stack(log_fbanks) + return log_fbank diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/reader.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/reader.py new file mode 100644 index 0000000..7d496da --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/data_utils/reader.py @@ -0,0 +1,157 @@ +import random + +import numpy as np +import torch +from torch.utils.data import Dataset +from tqdm import tqdm +from yeaudio.audio import AudioSegment +from yeaudio.augmentation import SpeedPerturbAugmentor, VolumePerturbAugmentor, NoisePerturbAugmentor, \ + ReverbPerturbAugmentor, SpecAugmentor + +from macls.data_utils.featurizer import AudioFeaturizer + + +class MAClsDataset(Dataset): + def __init__(self, + data_list_path, + audio_featurizer: AudioFeaturizer, + max_duration=3, + min_duration=0.5, + mode='train', + sample_rate=16000, + aug_conf=None, + use_dB_normalization=True, + target_dB=-20): + """音频数据加载器 + + Args: + data_list_path: 包含音频路径和标签的数据列表文件的路径 + audio_featurizer: 声纹特征提取器 + max_duration: 最长的音频长度,大于这个长度会裁剪掉 + min_duration: 过滤最短的音频长度 + aug_conf: 用于指定音频增强的配置 + mode: 数据集模式。在训练模式下,数据集可能会进行一些数据增强的预处理 + sample_rate: 采样率 + use_dB_normalization: 是否对音频进行音量归一化 + target_dB: 音量归一化的大小 + """ + super(MAClsDataset, self).__init__() + assert mode in ['train', 'eval', 'extract_feature'] + self.data_list_path = data_list_path + self.max_duration = max_duration + self.min_duration = min_duration + self.mode = mode + self._target_sample_rate = sample_rate + self._use_dB_normalization = use_dB_normalization + self._target_dB = target_dB + self.speed_augment = None + self.volume_augment = None + self.noise_augment = None + self.reverb_augment = None + self.spec_augment = None + # 获取特征器 + self.audio_featurizer = audio_featurizer + # 获取特征裁剪的大小 + self.max_feature_len = self.get_crop_feature_len() + # 获取数据列表 + with open(self.data_list_path, 'r', encoding='utf-8') as f: + self.lines = f.readlines() + if mode == 'train' and aug_conf is not None: + # 获取数据增强器 + self.get_augmentor(aug_conf) + # 评估模式下,数据列表需要排序 + if self.mode == 'eval': + self.sort_list() + + def __getitem__(self, idx): + # 分割数据文件路径和标签 + data_path, label = self.lines[idx].replace('\n', '').split('\t') + # 如果后缀名为.npy的文件,那么直接读取 + if data_path.endswith('.npy'): + feature = np.load(data_path) + if feature.shape[0] > self.max_feature_len: + crop_start = random.randint(0, feature.shape[0] - self.max_feature_len) if self.mode == 'train' else 0 + feature = feature[crop_start:crop_start + self.max_feature_len, :] + feature = torch.tensor(feature, dtype=torch.float32) + else: + audio_path, label = self.lines[idx].strip().split('\t') + # 读取音频 + audio_segment = AudioSegment.from_file(audio_path) + # 数据太短不利于训练 + if self.mode == 'train' or self.mode == 'extract_feature': + if audio_segment.duration < self.min_duration: + return self.__getitem__(idx + 1 if idx < len(self.lines) - 1 else 0) + # 音频增强 + if self.mode == 'train': + audio_segment = self.augment_audio(audio_segment) + # 重采样 + if audio_segment.sample_rate != self._target_sample_rate: + audio_segment.resample(self._target_sample_rate) + # 音量归一化 + if self._use_dB_normalization: + audio_segment.normalize(target_db=self._target_dB) + # 裁剪需要的数据 + if audio_segment.duration > self.max_duration: + audio_segment.crop(duration=self.max_duration, mode=self.mode) + samples = torch.tensor(audio_segment.samples, dtype=torch.float32) + feature = self.audio_featurizer(samples) + feature = feature.squeeze(0) + if self.mode == 'train' and self.spec_augment is not None: + feature = self.spec_augment(feature.cpu().numpy()) + feature = torch.tensor(feature, dtype=torch.float32) + label = torch.tensor(int(label), dtype=torch.int64) + return feature, label + + def __len__(self): + return len(self.lines) + + # 获取特征裁剪的大小,对应max_duration音频提取特征后的长度 + def get_crop_feature_len(self): + samples = torch.randn((1, self.max_duration * self._target_sample_rate)) + feature = self.audio_featurizer(samples).squeeze(0) + freq_len = feature.size(0) + return freq_len + + # 数据列表需要排序 + def sort_list(self): + lengths = [] + for line in tqdm(self.lines, desc=f"对列表[{self.data_list_path}]进行长度排序"): + # 分割数据文件路径和标签 + data_path, _ = line.split('\t') + if data_path.endswith('.npy'): + feature = np.load(data_path) + length = feature.shape[0] + lengths.append(length) + else: + # 读取音频 + audio_segment = AudioSegment.from_file(data_path) + length = audio_segment.duration + lengths.append(length) + # 对长度排序并获取索引 + sorted_indexes = np.argsort(lengths) + self.lines = [self.lines[i] for i in sorted_indexes] + + # 获取数据增强器 + def get_augmentor(self, aug_conf): + if aug_conf.speed is not None: + self.speed_augment = SpeedPerturbAugmentor(**aug_conf.speed) + if aug_conf.volume is not None: + self.volume_augment = VolumePerturbAugmentor(**aug_conf.volume) + if aug_conf.noise is not None: + self.noise_augment = NoisePerturbAugmentor(**aug_conf.noise) + if aug_conf.reverb is not None: + self.reverb_augment = ReverbPerturbAugmentor(**aug_conf.reverb) + if aug_conf.spec_aug is not None: + self.spec_augment = SpecAugmentor(**aug_conf.spec_aug) + + # 音频增强 + def augment_audio(self, audio_segment): + if self.speed_augment is not None: + audio_segment = self.speed_augment(audio_segment) + if self.volume_augment is not None: + audio_segment = self.volume_augment(audio_segment) + if self.noise_augment is not None: + audio_segment = self.noise_augment(audio_segment) + if self.reverb_augment is not None: + audio_segment = self.reverb_augment(audio_segment) + return audio_segment diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/metric/__init__.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/metric/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/metric/metrics.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/metric/metrics.py new file mode 100644 index 0000000..431c60a --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/metric/metrics.py @@ -0,0 +1,12 @@ +import numpy as np +import torch + + +# 计算准确率 +def accuracy(output, label): + output = torch.nn.functional.softmax(output, dim=-1) + output = output.data.cpu().numpy() + output = np.argmax(output, axis=1) + label = label.data.cpu().numpy() + acc = np.mean((output == label).astype(int)) + return acc diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/optimizer/__init__.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/optimizer/__init__.py new file mode 100644 index 0000000..4362420 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/optimizer/__init__.py @@ -0,0 +1,32 @@ +import importlib + +from loguru import logger +from torch.optim import * +from .scheduler import WarmupCosineSchedulerLR +from torch.optim.lr_scheduler import * + +__all__ = ['build_optimizer', 'build_lr_scheduler'] + + +def build_optimizer(params, configs): + use_optimizer = configs.optimizer_conf.get('optimizer', 'Adam') + optimizer_args = configs.optimizer_conf.get('optimizer_args', {}) + optim = importlib.import_module(__name__) + optimizer = getattr(optim, use_optimizer)(params=params, **optimizer_args) + logger.info(f'成功创建优化方法:{use_optimizer},参数为:{optimizer_args}') + return optimizer + + +def build_lr_scheduler(optimizer, step_per_epoch, configs): + use_scheduler = configs.optimizer_conf.get('scheduler', 'WarmupCosineSchedulerLR') + scheduler_args = configs.optimizer_conf.get('scheduler_args', {}) + if configs.optimizer_conf.scheduler == 'CosineAnnealingLR' and 'T_max' not in scheduler_args: + scheduler_args.T_max = int(configs.train_conf.max_epoch * 1.2) * step_per_epoch + if configs.optimizer_conf.scheduler == 'WarmupCosineSchedulerLR' and 'fix_epoch' not in scheduler_args: + scheduler_args.fix_epoch = configs.train_conf.max_epoch + if configs.optimizer_conf.scheduler == 'WarmupCosineSchedulerLR' and 'step_per_epoch' not in scheduler_args: + scheduler_args.step_per_epoch = step_per_epoch + optim = importlib.import_module(__name__) + scheduler = getattr(optim, use_scheduler)(optimizer=optimizer, **scheduler_args) + logger.info(f'成功创建学习率衰减:{use_scheduler},参数为:{scheduler_args}') + return scheduler diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/optimizer/scheduler.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/optimizer/scheduler.py new file mode 100644 index 0000000..e2ac1b7 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/optimizer/scheduler.py @@ -0,0 +1,48 @@ +import math +from typing import List + + +class WarmupCosineSchedulerLR: + def __init__( + self, + optimizer, + min_lr, + max_lr, + warmup_epoch, + fix_epoch, + step_per_epoch + ): + self.optimizer = optimizer + assert min_lr <= max_lr + self.min_lr = min_lr + self.max_lr = max_lr + self.warmup_step = warmup_epoch * step_per_epoch + self.fix_step = fix_epoch * step_per_epoch + self.current_step = 0.0 + + def set_lr(self, ): + new_lr = self.clr(self.current_step) + for param_group in self.optimizer.param_groups: + param_group['lr'] = new_lr + return new_lr + + def step(self, step=None): + if step is not None: + self.current_step = step + new_lr = self.set_lr() + self.current_step += 1 + return new_lr + + def clr(self, step): + if step < self.warmup_step: + return self.min_lr + (self.max_lr - self.min_lr) * \ + (step / self.warmup_step) + elif self.warmup_step <= step < self.fix_step: + return self.min_lr + 0.5 * (self.max_lr - self.min_lr) * \ + (1 + math.cos(math.pi * (step - self.warmup_step) / + (self.fix_step - self.warmup_step))) + else: + return self.min_lr + + def get_last_lr(self) -> List[float]: + return [self.clr(self.current_step)] diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/predict.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/predict.py new file mode 100644 index 0000000..25e3bbc --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/predict.py @@ -0,0 +1,177 @@ +import os +import sys +from io import BufferedReader +from typing import List + +import numpy as np +import torch +import yaml +from loguru import logger +from yeaudio.audio import AudioSegment +from macls.data_utils.featurizer import AudioFeaturizer +from macls.models import build_model +from macls.utils.utils import dict_to_object, print_arguments, convert_string_based_on_type + + +class MAClsPredictor: + def __init__(self, + configs, + model_path='models/CAMPPlus_Fbank/best_model/', + use_gpu=True, + overwrites=None, + log_level="info"): + """声音分类预测工具 + + :param configs: 配置文件路径,或者模型名称,如果是模型名称则会使用默认的配置文件 + :param model_path: 导出的预测模型文件夹路径 + :param use_gpu: 是否使用GPU预测 + :param overwrites: 覆盖配置文件中的参数,比如"train_conf.max_epoch=100",多个用逗号隔开 + :param log_level: 打印的日志等级,可选值有:"debug", "info", "warning", "error" + """ + if use_gpu: + assert (torch.cuda.is_available()), 'GPU不可用' + self.device = torch.device("cuda") + else: + os.environ['CUDA_VISIBLE_DEVICES'] = '-1' + self.device = torch.device("cpu") + self.log_level = log_level.upper() + logger.remove() + logger.add(sink=sys.stdout, level=self.log_level) + # 读取配置文件 + if isinstance(configs, str): + # 获取当前程序绝对路径 + absolute_path = os.path.dirname(__file__) + # 获取默认配置文件路径 + config_path = os.path.join(absolute_path, f"configs/{configs}.yml") + configs = config_path if os.path.exists(config_path) else configs + with open(configs, 'r', encoding='utf-8') as f: + configs = yaml.load(f.read(), Loader=yaml.FullLoader) + self.configs = dict_to_object(configs) + # 覆盖配置文件中的参数 + if overwrites: + overwrites = overwrites.split(",") + for overwrite in overwrites: + keys, value = overwrite.strip().split("=") + attrs = keys.split('.') + current_level = self.configs + for attr in attrs[:-1]: + current_level = getattr(current_level, attr) + before_value = getattr(current_level, attrs[-1]) + setattr(current_level, attrs[-1], convert_string_based_on_type(before_value, value)) + # 打印配置信息 + print_arguments(configs=self.configs) + # 获取特征器 + self._audio_featurizer = AudioFeaturizer(feature_method=self.configs.preprocess_conf.feature_method, + use_hf_model=self.configs.preprocess_conf.get('use_hf_model', False), + method_args=self.configs.preprocess_conf.get('method_args', {})) + # 获取分类标签 + with open(self.configs.dataset_conf.label_list_path, 'r', encoding='utf-8') as f: + lines = f.readlines() + self.class_labels = [l.replace('\n', '') for l in lines] + # 自动获取列表数量 + if self.configs.model_conf.model_args.get('num_class', None) is None: + self.configs.model_conf.model_args.num_class = len(self.class_labels) + # 获取模型 + self.predictor = build_model(input_size=self._audio_featurizer.feature_dim, configs=self.configs) + self.predictor.to(self.device) + # 加载模型 + if os.path.isdir(model_path): + model_path = os.path.join(model_path, 'model.pth') + assert os.path.exists(model_path), f"{model_path} 模型不存在!" + if torch.cuda.is_available() and use_gpu: + model_state_dict = torch.load(model_path, weights_only=False) + else: + model_state_dict = torch.load(model_path, weights_only=False, map_location='cpu') + self.predictor.load_state_dict(model_state_dict) + logger.info(f"成功加载模型参数:{model_path}") + self.predictor.eval() + + def _load_audio(self, audio_data, sample_rate=16000): + """加载音频 + :param audio_data: 需要识别的数据,支持文件路径,文件对象,字节,numpy。如果是字节的话,必须是完整的字节文件 + :param sample_rate: 如果传入的事numpy数据,需要指定采样率 + :return: 识别的文本结果和解码的得分数 + """ + # 加载音频文件,并进行预处理 + if isinstance(audio_data, str): + audio_segment = AudioSegment.from_file(audio_data) + elif isinstance(audio_data, BufferedReader): + audio_segment = AudioSegment.from_file(audio_data) + elif isinstance(audio_data, np.ndarray): + audio_segment = AudioSegment.from_ndarray(audio_data, sample_rate) + elif isinstance(audio_data, bytes): + audio_segment = AudioSegment.from_bytes(audio_data) + else: + raise Exception(f'不支持该数据类型,当前数据类型为:{type(audio_data)}') + # 重采样 + if audio_segment.sample_rate != self.configs.dataset_conf.dataset.sample_rate: + audio_segment.resample(self.configs.dataset_conf.dataset.sample_rate) + # decibel normalization + if self.configs.dataset_conf.dataset.use_dB_normalization: + audio_segment.normalize(target_db=self.configs.dataset_conf.dataset.target_dB) + assert audio_segment.duration >= self.configs.dataset_conf.dataset.min_duration, \ + f'音频太短,最小应该为{self.configs.dataset_conf.dataset.min_duration}s,当前音频为{audio_segment.duration}s' + return audio_segment + + # 预测一个音频的特征 + def predict(self, + audio_data, + sample_rate=16000): + """预测一个音频 + + :param audio_data: 需要识别的数据,支持文件路径,文件对象,字节,numpy。如果是字节的话,必须是完整并带格式的字节文件 + :param sample_rate: 如果传入的事numpy数据,需要指定采样率 + :return: 结果标签和对应的得分 + """ + # 加载音频文件,并进行预处理 + input_data = self._load_audio(audio_data=audio_data, sample_rate=sample_rate) + input_data = torch.tensor(input_data.samples, dtype=torch.float32).unsqueeze(0) + audio_feature = self._audio_featurizer(input_data).to(self.device) + # 执行预测 + output = self.predictor(audio_feature) + result = torch.nn.functional.softmax(output, dim=-1)[0] + result = result.data.cpu().numpy() + # 最大概率的label + lab = np.argsort(result)[-1] + score = result[lab] + return self.class_labels[lab], round(float(score), 5) + + def predict_batch(self, audios_data: List, sample_rate=16000): + """预测一批音频的特征 + + :param audios_data: 需要识别的数据,支持文件路径,文件对象,字节,numpy。如果是字节的话,必须是完整并带格式的字节文件 + :param sample_rate: 如果传入的事numpy数据,需要指定采样率 + :return: 结果标签和对应的得分 + """ + audios_data1 = [] + for audio_data in audios_data: + # 加载音频文件,并进行预处理 + input_data = self._load_audio(audio_data=audio_data, sample_rate=sample_rate) + audios_data1.append(input_data.samples) + # 找出音频长度最长的 + batch = sorted(audios_data1, key=lambda a: a.shape[0], reverse=True) + max_audio_length = batch[0].shape[0] + batch_size = len(batch) + # 以最大的长度创建0张量 + inputs = np.zeros((batch_size, max_audio_length), dtype=np.float32) + input_lens_ratio = [] + for x in range(batch_size): + tensor = audios_data1[x] + seq_length = tensor.shape[0] + # 将数据插入都0张量中,实现了padding + inputs[x, :seq_length] = tensor[:] + input_lens_ratio.append(seq_length / max_audio_length) + inputs = torch.tensor(inputs, dtype=torch.float32) + input_lens_ratio = torch.tensor(input_lens_ratio, dtype=torch.float32) + audio_feature = self._audio_featurizer(inputs, input_lens_ratio).to(self.device) + # 执行预测 + output = self.predictor(audio_feature) + results = torch.nn.functional.softmax(output, dim=-1) + results = results.data.cpu().numpy() + labels, scores = [], [] + for result in results: + lab = np.argsort(result)[-1] + score = result[lab] + labels.append(self.class_labels[lab]) + scores.append(round(float(score), 5)) + return labels, scores diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/trainer.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/trainer.py new file mode 100644 index 0000000..4412d21 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/trainer.py @@ -0,0 +1,456 @@ +import os +import platform +import sys +import time +import uuid +from datetime import timedelta + +import numpy as np +import torch +import torch.distributed as dist +import yaml +from sklearn.metrics import confusion_matrix +from torch.utils.data import DataLoader, RandomSampler +from torch.utils.data.distributed import DistributedSampler +from torchinfo import summary +from tqdm import tqdm +from loguru import logger +from visualdl import LogWriter + +from macls.data_utils.collate_fn import collate_fn +from macls.data_utils.featurizer import AudioFeaturizer +from macls.data_utils.reader import MAClsDataset +from macls.metric.metrics import accuracy +from macls.models import build_model +from macls.optimizer import build_optimizer, build_lr_scheduler +from macls.utils.checkpoint import load_pretrained, load_checkpoint, save_checkpoint +from macls.utils.utils import dict_to_object, plot_confusion_matrix, print_arguments, convert_string_based_on_type + + +class MAClsTrainer(object): + def __init__(self, + configs, + use_gpu=True, + data_augment_configs=None, + num_class=None, + overwrites=None, + log_level="info"): + """声音分类训练工具类 + + :param configs: 配置文件路径,或者模型名称,如果是模型名称则会使用默认的配置文件 + :param use_gpu: 是否使用GPU训练模型 + :param data_augment_configs: 数据增强配置字典或者其文件路径 + :param num_class: 分类大小,对应配置文件中的model_conf.model_args.num_class + :param overwrites: 覆盖配置文件中的参数,比如"train_conf.max_epoch=100",多个用逗号隔开 + :param log_level: 打印的日志等级,可选值有:"debug", "info", "warning", "error" + """ + if use_gpu: + assert (torch.cuda.is_available()), 'GPU不可用' + self.device = torch.device("cuda") + else: + os.environ['CUDA_VISIBLE_DEVICES'] = '-1' + self.device = torch.device("cpu") + self.use_gpu = use_gpu + self.log_level = log_level.upper() + logger.remove() + logger.add(sink=sys.stdout, level=self.log_level) + # 读取配置文件 + if isinstance(configs, str): + # 获取当前程序绝对路径 + absolute_path = os.path.dirname(__file__) + # 获取默认配置文件路径 + config_path = os.path.join(absolute_path, f"configs/{configs}.yml") + configs = config_path if os.path.exists(config_path) else configs + with open(configs, 'r', encoding='utf-8') as f: + configs = yaml.load(f.read(), Loader=yaml.FullLoader) + self.configs = dict_to_object(configs) + if num_class is not None: + self.configs.model_conf.model_args.num_class = num_class + # 覆盖配置文件中的参数 + if overwrites: + overwrites = overwrites.split(",") + for overwrite in overwrites: + keys, value = overwrite.strip().split("=") + attrs = keys.split('.') + current_level = self.configs + for attr in attrs[:-1]: + current_level = getattr(current_level, attr) + before_value = getattr(current_level, attrs[-1]) + setattr(current_level, attrs[-1], convert_string_based_on_type(before_value, value)) + # 打印配置信息 + print_arguments(configs=self.configs) + self.model = None + self.optimizer = None + self.scheduler = None + self.audio_featurizer = None + self.train_dataset = None + self.train_loader = None + self.test_dataset = None + self.test_loader = None + self.amp_scaler = None + # 读取数据增强配置文件 + if isinstance(data_augment_configs, str): + with open(data_augment_configs, 'r', encoding='utf-8') as f: + data_augment_configs = yaml.load(f.read(), Loader=yaml.FullLoader) + print_arguments(configs=data_augment_configs, title='数据增强配置') + self.data_augment_configs = dict_to_object(data_augment_configs) + # 获取分类标签 + with open(self.configs.dataset_conf.label_list_path, 'r', encoding='utf-8') as f: + lines = f.readlines() + self.class_labels = [l.replace('\n', '') for l in lines] + if platform.system().lower() == 'windows': + self.configs.dataset_conf.dataLoader.num_workers = 0 + logger.warning('Windows系统不支持多线程读取数据,已自动关闭!') + if self.configs.preprocess_conf.get('use_hf_model', False): + self.configs.dataset_conf.dataLoader.num_workers = 0 + logger.warning('使用HuggingFace模型不支持多线程进行特征提取,已自动关闭!') + self.max_step, self.train_step = None, None + self.train_loss, self.train_acc = None, None + self.train_eta_sec = None + self.eval_loss, self.eval_acc = None, None + self.test_log_step, self.train_log_step = 0, 0 + self.stop_train, self.stop_eval = False, False + + def __setup_dataloader(self, is_train=False): + """ 获取数据加载器 + + :param is_train: 是否获取训练数据 + """ + # 获取特征器 + self.audio_featurizer = AudioFeaturizer(feature_method=self.configs.preprocess_conf.feature_method, + use_hf_model=self.configs.preprocess_conf.get('use_hf_model', False), + method_args=self.configs.preprocess_conf.get('method_args', {})) + + dataset_args = self.configs.dataset_conf.get('dataset', {}) + data_loader_args = self.configs.dataset_conf.get('dataLoader', {}) + if is_train: + self.train_dataset = MAClsDataset(data_list_path=self.configs.dataset_conf.train_list, + audio_featurizer=self.audio_featurizer, + aug_conf=self.data_augment_configs, + mode='train', + **dataset_args) + # 设置支持多卡训练 + train_sampler = RandomSampler(self.train_dataset) + if torch.cuda.device_count() > 1: + # 设置支持多卡训练 + train_sampler = DistributedSampler(dataset=self.train_dataset) + self.train_loader = DataLoader(dataset=self.train_dataset, + collate_fn=collate_fn, + sampler=train_sampler, + **data_loader_args) + # 获取测试数据 + data_loader_args.drop_last = False + dataset_args.max_duration = self.configs.dataset_conf.eval_conf.max_duration + data_loader_args.batch_size = self.configs.dataset_conf.eval_conf.batch_size + self.test_dataset = MAClsDataset(data_list_path=self.configs.dataset_conf.test_list, + audio_featurizer=self.audio_featurizer, + mode='eval', + **dataset_args) + self.test_loader = DataLoader(dataset=self.test_dataset, + collate_fn=collate_fn, + shuffle=False, + **data_loader_args) + + def extract_features(self, save_dir='dataset/features', max_duration=100): + """ 提取特征保存文件 + + :param save_dir: 保存路径 + :param max_duration: 提取特征的最大时长,避免过长显存不足,单位秒 + """ + self.audio_featurizer = AudioFeaturizer(feature_method=self.configs.preprocess_conf.feature_method, + use_hf_model=self.configs.preprocess_conf.get('use_hf_model', False), + method_args=self.configs.preprocess_conf.get('method_args', {})) + dataset_args = self.configs.dataset_conf.get('dataset', {}) + dataset_args.max_duration = max_duration + data_loader_args = self.configs.dataset_conf.get('dataLoader', {}) + data_loader_args.drop_last = False + for data_list in [self.configs.dataset_conf.train_list, self.configs.dataset_conf.test_list]: + test_dataset = MAClsDataset(data_list_path=data_list, + audio_featurizer=self.audio_featurizer, + mode='extract_feature', + **dataset_args) + test_loader = DataLoader(dataset=test_dataset, + collate_fn=collate_fn, + shuffle=False, + **data_loader_args) + save_data_list = data_list.replace('.txt', '_features.txt') + with open(save_data_list, 'w', encoding='utf-8') as f: + for features, labels, input_lens in tqdm(test_loader): + for i in range(len(features)): + feature, label, input_len = features[i], labels[i], input_lens[i] + feature = feature.numpy()[:input_len] + label = int(label) + save_path = os.path.join(save_dir, str(label), + f'{str(uuid.uuid4())}.npy').replace('\\', '/') + os.makedirs(os.path.dirname(save_path), exist_ok=True) + np.save(save_path, feature) + f.write(f'{save_path}\t{label}\n') + logger.info(f'{data_list}列表中的数据已提取特征完成,新列表为:{save_data_list}') + + def __setup_model(self, input_size, is_train=False): + """ 获取模型 + + :param input_size: 模型输入特征大小 + :param is_train: 是否获取训练模型 + """ + # 自动获取列表数量 + if self.configs.model_conf.model_args.get('num_class', None) is None: + self.configs.model_conf.model_args.num_class = len(self.class_labels) + # 获取模型 + self.model = build_model(input_size=input_size, configs=self.configs) + self.model.to(self.device) + if self.log_level == "DEBUG" or self.log_level == "INFO": + # 打印模型信息,98是长度,这个取决于输入的音频长度 + summary(self.model, input_size=(1, 98, input_size)) + # 使用Pytorch2.0的编译器 + if self.configs.train_conf.use_compile and torch.__version__ >= "2" and platform.system().lower() == 'windows': + self.model = torch.compile(self.model, mode="reduce-overhead") + # print(self.model) + # 获取损失函数 + label_smoothing = self.configs.train_conf.get('label_smoothing', 0.0) + self.loss = torch.nn.CrossEntropyLoss(label_smoothing=label_smoothing) + if is_train: + if self.configs.train_conf.enable_amp: + self.amp_scaler = torch.GradScaler(init_scale=1024) + # 获取优化方法 + self.optimizer = build_optimizer(params=self.model.parameters(), configs=self.configs) + # 学习率衰减函数 + self.scheduler = build_lr_scheduler(optimizer=self.optimizer, step_per_epoch=len(self.train_loader), + configs=self.configs) + + def __train_epoch(self, epoch_id, local_rank, writer, nranks=0): + """训练一个epoch + + :param epoch_id: 当前epoch + :param local_rank: 当前显卡id + :param writer: VisualDL对象 + :param nranks: 所使用显卡的数量 + """ + train_times, accuracies, loss_sum = [], [], [] + start = time.time() + for batch_id, (features, label, input_len) in enumerate(self.train_loader): + if self.stop_train: break + if nranks > 1: + features = features.to(local_rank) + label = label.to(local_rank).long() + else: + features = features.to(self.device) + label = label.to(self.device).long() + # 执行模型计算,是否开启自动混合精度 + with torch.autocast('cuda', enabled=self.configs.train_conf.enable_amp): + output = self.model(features) + # 计算损失值 + los = self.loss(output, label) + # 是否开启自动混合精度 + if self.configs.train_conf.enable_amp: + # loss缩放,乘以系数loss_scaling + scaled = self.amp_scaler.scale(los) + scaled.backward() + else: + los.backward() + # 是否开启自动混合精度 + if self.configs.train_conf.enable_amp: + self.amp_scaler.unscale_(self.optimizer) + self.amp_scaler.step(self.optimizer) + self.amp_scaler.update() + else: + self.optimizer.step() + self.optimizer.zero_grad() + + # 计算准确率 + acc = accuracy(output, label) + accuracies.append(acc) + loss_sum.append(los.data.cpu().numpy()) + train_times.append((time.time() - start) * 1000) + self.train_step += 1 + + # 多卡训练只使用一个进程打印 + if batch_id % self.configs.train_conf.log_interval == 0 and local_rank == 0: + batch_id = batch_id + 1 + # 计算每秒训练数据量 + train_speed = self.configs.dataset_conf.dataLoader.batch_size / ( + sum(train_times) / len(train_times) / 1000) + # 计算剩余时间 + self.train_eta_sec = (sum(train_times) / len(train_times)) * (self.max_step - self.train_step) / 1000 + eta_str = str(timedelta(seconds=int(self.train_eta_sec))) + self.train_loss = sum(loss_sum) / len(loss_sum) + self.train_acc = sum(accuracies) / len(accuracies) + logger.info(f'Train epoch: [{epoch_id}/{self.configs.train_conf.max_epoch}], ' + f'batch: [{batch_id}/{len(self.train_loader)}], ' + f'loss: {self.train_loss:.5f}, accuracy: {self.train_acc:.5f}, ' + f'learning rate: {self.scheduler.get_last_lr()[0]:>.8f}, ' + f'speed: {train_speed:.2f} data/sec, eta: {eta_str}') + writer.add_scalar('Train/Loss', self.train_loss, self.train_log_step) + writer.add_scalar('Train/Accuracy', self.train_acc, self.train_log_step) + # 记录学习率 + writer.add_scalar('Train/lr', self.scheduler.get_last_lr()[0], self.train_log_step) + train_times, accuracies, loss_sum = [], [], [] + self.train_log_step += 1 + start = time.time() + self.scheduler.step() + + def train(self, + save_model_path='models/', + log_dir='log/', + max_epoch=None, + resume_model=None, + pretrained_model=None): + """ + 训练模型 + :param save_model_path: 模型保存的路径 + :param log_dir: 保存VisualDL日志文件的路径 + :param max_epoch: 最大训练轮数,对应配置文件中的train_conf.max_epoch + :param resume_model: 恢复训练,当为None则不使用预训练模型 + :param pretrained_model: 预训练模型的路径,当为None则不使用预训练模型 + """ + # 获取有多少张显卡训练 + nranks = torch.cuda.device_count() + local_rank = 0 + writer = None + if local_rank == 0: + # 日志记录器 + writer = LogWriter(logdir=log_dir) + + if nranks > 1 and self.use_gpu: + # 初始化NCCL环境 + dist.init_process_group(backend='nccl') + local_rank = int(os.environ["LOCAL_RANK"]) + + # 获取数据 + self.__setup_dataloader(is_train=True) + # 获取模型 + self.__setup_model(input_size=self.audio_featurizer.feature_dim, is_train=True) + # 加载预训练模型 + self.model = load_pretrained(model=self.model, pretrained_model=pretrained_model, use_gpu=self.use_gpu) + # 加载恢复模型 + self.model, self.optimizer, self.amp_scaler, self.scheduler, last_epoch, best_acc = \ + load_checkpoint(configs=self.configs, model=self.model, optimizer=self.optimizer, + amp_scaler=self.amp_scaler, scheduler=self.scheduler, step_epoch=len(self.train_loader), + save_model_path=save_model_path, resume_model=resume_model) + + # 支持多卡训练 + if nranks > 1 and self.use_gpu: + self.model.to(local_rank) + self.model = torch.nn.parallel.DistributedDataParallel(self.model, device_ids=[local_rank]) + logger.info('训练数据:{}'.format(len(self.train_dataset))) + + self.train_loss, self.train_acc = None, None + self.eval_loss, self.eval_acc = None, None + self.test_log_step, self.train_log_step = 0, 0 + if local_rank == 0: + writer.add_scalar('Train/lr', self.scheduler.get_last_lr()[0], last_epoch) + if max_epoch is not None: + self.configs.train_conf.max_epoch = max_epoch + # 最大步数 + self.max_step = len(self.train_loader) * self.configs.train_conf.max_epoch + self.train_step = max(last_epoch, 0) * len(self.train_loader) + # 开始训练 + for epoch_id in range(last_epoch, self.configs.train_conf.max_epoch): + if self.stop_train: break + epoch_id += 1 + start_epoch = time.time() + # 训练一个epoch + self.__train_epoch(epoch_id=epoch_id, local_rank=local_rank, writer=writer, nranks=nranks) + # 多卡训练只使用一个进程执行评估和保存模型 + if local_rank == 0: + if self.stop_eval: continue + logger.info('=' * 70) + self.eval_loss, self.eval_acc = self.evaluate() + logger.info('Test epoch: {}, time/epoch: {}, loss: {:.5f}, accuracy: {:.5f}'.format( + epoch_id, str(timedelta(seconds=(time.time() - start_epoch))), self.eval_loss, self.eval_acc)) + logger.info('=' * 70) + writer.add_scalar('Test/Accuracy', self.eval_acc, self.test_log_step) + writer.add_scalar('Test/Loss', self.eval_loss, self.test_log_step) + self.test_log_step += 1 + self.model.train() + # # 保存最优模型 + if self.eval_acc >= best_acc: + best_acc = self.eval_acc + save_checkpoint(configs=self.configs, model=self.model, optimizer=self.optimizer, + amp_scaler=self.amp_scaler, save_model_path=save_model_path, epoch_id=epoch_id, + accuracy=self.eval_acc, best_model=True) + # 保存模型 + save_checkpoint(configs=self.configs, model=self.model, optimizer=self.optimizer, + amp_scaler=self.amp_scaler, save_model_path=save_model_path, epoch_id=epoch_id, + accuracy=self.eval_acc) + + def evaluate(self, resume_model=None, save_matrix_path=None): + """ + 评估模型 + :param resume_model: 所使用的模型 + :param save_matrix_path: 保存混合矩阵的路径 + :return: 评估结果 + """ + if self.test_loader is None: + self.__setup_dataloader() + if self.model is None: + self.__setup_model(input_size=self.audio_featurizer.feature_dim) + if resume_model is not None: + if os.path.isdir(resume_model): + resume_model = os.path.join(resume_model, 'model.pth') + assert os.path.exists(resume_model), f"{resume_model} 模型不存在!" + model_state_dict = torch.load(resume_model, weights_only=False) + self.model.load_state_dict(model_state_dict) + logger.info(f'成功加载模型:{resume_model}') + self.model.eval() + if isinstance(self.model, torch.nn.parallel.DistributedDataParallel): + eval_model = self.model.module + else: + eval_model = self.model + + accuracies, losses, preds, labels = [], [], [], [] + with torch.no_grad(): + for batch_id, (features, label, input_lens) in enumerate(tqdm(self.test_loader, desc='执行评估')): + if self.stop_eval: break + features = features.to(self.device) + label = label.to(self.device).long() + output = eval_model(features) + los = self.loss(output, label) + # 计算准确率 + acc = accuracy(output, label) + accuracies.append(acc) + # 模型预测标签 + label = label.data.cpu().numpy() + output = output.data.cpu().numpy() + pred = np.argmax(output, axis=1) + preds.extend(pred.tolist()) + # 真实标签 + labels.extend(label.tolist()) + losses.append(los.data.cpu().numpy()) + loss = float(sum(losses) / len(losses)) if len(losses) > 0 else -1 + acc = float(sum(accuracies) / len(accuracies)) if len(accuracies) > 0 else -1 + # 保存混合矩阵 + if save_matrix_path is not None: + try: + cm = confusion_matrix(labels, preds) + plot_confusion_matrix(cm=cm, save_path=os.path.join(save_matrix_path, f'{int(time.time())}.png'), + class_labels=self.class_labels) + except Exception as e: + logger.error(f'保存混淆矩阵失败:{e}') + self.model.train() + return loss, acc + + def export(self, save_model_path='models/', resume_model='models/EcapaTdnn_Fbank/best_model/'): + """ + 导出预测模型 + :param save_model_path: 模型保存的路径 + :param resume_model: 准备转换的模型路径 + :return: + """ + self.__setup_model(input_size=self.audio_featurizer.feature_dim) + # 加载预训练模型 + if os.path.isdir(resume_model): + resume_model = os.path.join(resume_model, 'model.pth') + assert os.path.exists(resume_model), f"{resume_model} 模型不存在!" + model_state_dict = torch.load(resume_model) + self.model.load_state_dict(model_state_dict) + logger.info('成功恢复模型参数和优化方法参数:{}'.format(resume_model)) + self.model.eval() + # 获取静态模型 + infer_model = self.model.export() + infer_model_path = os.path.join(save_model_path, + f'{self.configs.use_model}_{self.configs.preprocess_conf.feature_method}', + 'inference.pth') + os.makedirs(os.path.dirname(infer_model_path), exist_ok=True) + torch.jit.save(infer_model, infer_model_path) + logger.info("预测模型已保存:{}".format(infer_model_path)) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/__init__.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/checkpoint.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/checkpoint.py new file mode 100644 index 0000000..c076929 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/checkpoint.py @@ -0,0 +1,162 @@ +import json +import os +import shutil + +import torch +from loguru import logger +from macls import __version__ + + +def load_pretrained(model, pretrained_model, use_gpu=True): + """加载预训练模型 + + :param model: 使用的模型 + :param pretrained_model: 预训练模型路径 + :param use_gpu: 模型是否使用GPU + :return: 加载的模型 + """ + # 加载预训练模型 + if pretrained_model is None: return model + if os.path.isdir(pretrained_model): + pretrained_model = os.path.join(pretrained_model, 'model.pth') + assert os.path.exists(pretrained_model), f"{pretrained_model} 模型不存在!" + if isinstance(model, torch.nn.parallel.DistributedDataParallel): + model_dict = model.module.state_dict() + else: + model_dict = model.state_dict() + if torch.cuda.is_available() and use_gpu: + model_state_dict = torch.load(pretrained_model, weights_only=False) + else: + model_state_dict = torch.load(pretrained_model, weights_only=False, map_location='cpu') + # 过滤不存在的参数 + for name, weight in model_dict.items(): + if name in model_state_dict.keys(): + if list(weight.shape) != list(model_state_dict[name].shape): + logger.warning(f'{name} not used, shape {list(model_state_dict[name].shape)} ' + f'unmatched with {list(weight.shape)} in model.') + model_state_dict.pop(name, None) + # 加载权重 + if isinstance(model, torch.nn.parallel.DistributedDataParallel): + missing_keys, unexpected_keys = model.module.load_state_dict(model_state_dict, strict=False) + else: + missing_keys, unexpected_keys = model.load_state_dict(model_state_dict, strict=False) + if len(unexpected_keys) > 0: + logger.warning('Unexpected key(s) in state_dict: {}. ' + .format(', '.join('"{}"'.format(k) for k in unexpected_keys))) + if len(missing_keys) > 0: + logger.warning('Missing key(s) in state_dict: {}. ' + .format(', '.join('"{}"'.format(k) for k in missing_keys))) + logger.info('成功加载预训练模型:{}'.format(pretrained_model)) + return model + + +def load_checkpoint(configs, model, optimizer, amp_scaler, scheduler, + step_epoch, save_model_path, resume_model): + """加载模型 + + :param configs: 配置信息 + :param model: 使用的模型 + :param optimizer: 使用的优化方法 + :param amp_scaler: 使用的自动混合精度 + :param scheduler: 使用的学习率调整策略 + :param step_epoch: 每个epoch的step数量 + :param save_model_path: 模型保存路径 + :param resume_model: 恢复训练的模型路径 + """ + last_epoch1 = 0 + accuracy1 = 0. + + def load_model(model_path): + assert os.path.exists(os.path.join(model_path, 'model.pth')), "模型参数文件不存在!" + assert os.path.exists(os.path.join(model_path, 'optimizer.pth')), "优化方法参数文件不存在!" + state_dict = torch.load(os.path.join(model_path, 'model.pth'), weights_only=False) + if isinstance(model, torch.nn.parallel.DistributedDataParallel): + model.module.load_state_dict(state_dict) + else: + model.load_state_dict(state_dict) + optimizer.load_state_dict(torch.load(os.path.join(model_path, 'optimizer.pth'), weights_only=False)) + # 自动混合精度参数 + if amp_scaler is not None and os.path.exists(os.path.join(model_path, 'scaler.pth')): + amp_scaler.load_state_dict(torch.load(os.path.join(model_path, 'scaler.pth')), weights_only=False) + with open(os.path.join(model_path, 'model.state'), 'r', encoding='utf-8') as f: + json_data = json.load(f) + last_epoch = json_data['last_epoch'] + accuracy = json_data['accuracy'] + logger.info('成功恢复模型参数和优化方法参数:{}'.format(model_path)) + optimizer.step() + [scheduler.step() for _ in range(last_epoch * step_epoch)] + return last_epoch, accuracy + + # 获取最后一个保存的模型 + save_feature_method = configs.preprocess_conf.feature_method + if configs.preprocess_conf.get('use_hf_model', False): + save_feature_method = save_feature_method[:-1] if save_feature_method[-1] == '/' else save_feature_method + save_feature_method = os.path.basename(save_feature_method) + last_model_dir = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', + 'last_model') + if resume_model is not None or (os.path.exists(os.path.join(last_model_dir, 'model.pth')) + and os.path.exists(os.path.join(last_model_dir, 'optimizer.pth'))): + if resume_model is not None: + last_epoch1, accuracy1 = load_model(resume_model) + else: + try: + # 自动获取最新保存的模型 + last_epoch1, accuracy1 = load_model(last_model_dir) + except Exception as e: + logger.warning(f'尝试自动恢复最新模型失败,错误信息:{e}') + return model, optimizer, amp_scaler, scheduler, last_epoch1, accuracy1 + + +# 保存模型 +def save_checkpoint(configs, model, optimizer, amp_scaler, save_model_path, epoch_id, + accuracy=0., best_model=False): + """保存模型 + + :param configs: 配置信息 + :param model: 使用的模型 + :param optimizer: 使用的优化方法 + :param amp_scaler: 使用的自动混合精度 + :param save_model_path: 模型保存路径 + :param epoch_id: 当前epoch + :param accuracy: 当前准确率 + :param best_model: 是否为最佳模型 + """ + if isinstance(model, torch.nn.parallel.DistributedDataParallel): + state_dict = model.module.state_dict() + else: + state_dict = model.state_dict() + # 保存模型的路径 + save_feature_method = configs.preprocess_conf.feature_method + if configs.preprocess_conf.get('use_hf_model', False): + save_feature_method = save_feature_method[:-1] if save_feature_method[-1] == '/' else save_feature_method + save_feature_method = os.path.basename(save_feature_method) + if best_model: + model_path = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', 'best_model') + else: + model_path = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', 'epoch_{}'.format(epoch_id)) + os.makedirs(model_path, exist_ok=True) + # 保存模型参数 + torch.save(optimizer.state_dict(), os.path.join(model_path, 'optimizer.pth')) + torch.save(state_dict, os.path.join(model_path, 'model.pth')) + # 自动混合精度参数 + if amp_scaler is not None: + torch.save(amp_scaler.state_dict(), os.path.join(model_path, 'scaler.pth')) + with open(os.path.join(model_path, 'model.state'), 'w', encoding='utf-8') as f: + data = {"last_epoch": epoch_id, "accuracy": accuracy, "version": __version__, + "model": configs.model_conf.model, "feature_method": save_feature_method} + f.write(json.dumps(data, indent=4, ensure_ascii=False)) + if not best_model: + last_model_path = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', 'last_model') + shutil.rmtree(last_model_path, ignore_errors=True) + shutil.copytree(model_path, last_model_path) + # 删除旧的模型 + old_model_path = os.path.join(save_model_path, + f'{configs.model_conf.model}_{save_feature_method}', + 'epoch_{}'.format(epoch_id - 3)) + if os.path.exists(old_model_path): + shutil.rmtree(old_model_path) + logger.info('已保存模型:{}'.format(model_path)) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/record.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/record.py new file mode 100644 index 0000000..db0a992 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/record.py @@ -0,0 +1,31 @@ +import os + +import soundcard +import soundfile + + +class RecordAudio: + def __init__(self, channels=1, sample_rate=16000): + # 录音参数 + self.channels = channels + self.sample_rate = sample_rate + + # 获取麦克风 + self.default_mic = soundcard.default_microphone() + + def record(self, record_seconds=3, save_path=None): + """录音 + + :param record_seconds: 录音时间,默认3秒 + :param save_path: 录音保存的路径,后缀名为wav + :return: 音频的numpy数据 + """ + print("开始录音......") + num_frames = int(record_seconds * self.sample_rate) + data = self.default_mic.record(samplerate=self.sample_rate, numframes=num_frames, channels=self.channels) + audio_data = data.squeeze() + print("录音已结束!") + if save_path is not None: + os.makedirs(os.path.dirname(save_path), exist_ok=True) + soundfile.write(save_path, data=data, samplerate=self.sample_rate) + return audio_data diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/utils.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/utils.py new file mode 100644 index 0000000..c05ecdf --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/macls/utils/utils.py @@ -0,0 +1,131 @@ +import distutils.util +import os + +import matplotlib.pyplot as plt +import numpy as np + +from loguru import logger + + +def print_arguments(args=None, configs=None, title=None): + if args: + logger.info("----------- 额外配置参数 -----------") + for arg, value in sorted(vars(args).items()): + logger.info("%s: %s" % (arg, value)) + logger.info("------------------------------------------------") + if configs: + title = title if title else "配置文件参数" + logger.info(f"----------- {title} -----------") + for arg, value in sorted(configs.items()): + if isinstance(value, dict): + logger.info(f"{arg}:") + for a, v in sorted(value.items()): + if isinstance(v, dict): + logger.info(f"\t{a}:") + for a1, v1 in sorted(v.items()): + logger.info("\t\t%s: %s" % (a1, v1)) + else: + logger.info("\t%s: %s" % (a, v)) + else: + logger.info("%s: %s" % (arg, value)) + logger.info("------------------------------------------------") + + +def add_arguments(argname, type, default, help, argparser, **kwargs): + type = distutils.util.strtobool if type == bool else type + argparser.add_argument("--" + argname, + default=default, + type=type, + help=help + ' 默认: %(default)s.', + **kwargs) + + +class Dict(dict): + __setattr__ = dict.__setitem__ + __getattr__ = dict.__getitem__ + + +def dict_to_object(dict_obj): + if not isinstance(dict_obj, dict): + return dict_obj + inst = Dict() + for k, v in dict_obj.items(): + inst[k] = dict_to_object(v) + return inst + + +def plot_confusion_matrix(cm, save_path, class_labels, show=False): + """ + 绘制混淆矩阵 + @param cm: 混淆矩阵, 一个二维数组,表示预测结果与真实结果的混淆情况。 + @param save_path: 保存路径, 字符串,指定混淆矩阵图像的保存位置。 + @param class_labels: 类别名称, 一个列表,包含各个类别的名称。 + @param show: 是否显示图像, 布尔值,控制是否在绘图窗口显示混淆矩阵图像。 + """ + # 检测类别名称是否包含中文,是则设置相应字体 + s = ''.join(class_labels) + is_ascii = all(ord(c) < 128 for c in s) + if not is_ascii: + plt.rcParams['font.sans-serif'] = ['SimHei'] + plt.rcParams['axes.unicode_minus'] = False + + # 初始化绘图参数并绘制混淆矩阵 + plt.figure(figsize=(12, 8), dpi=100) + np.set_printoptions(precision=2) + # 在混淆矩阵中绘制每个格子的概率值 + ind_array = np.arange(len(class_labels)) + x, y = np.meshgrid(ind_array, ind_array) + for x_val, y_val in zip(x.flatten(), y.flatten()): + c = cm[y_val][x_val] / (np.sum(cm[:, x_val]) + 1e-6) + # 忽略概率值太小的格子 + if c < 1e-4: continue + plt.text(x_val, y_val, "%0.2f" % (c,), color='red', fontsize=15, va='center', ha='center') + m = np.sum(cm, axis=0) + 1e-6 + plt.imshow(cm / m, interpolation='nearest', cmap=plt.cm.binary) + plt.title('Confusion Matrix' if is_ascii else '混合矩阵') + plt.colorbar() + # 设置类别标签 + xlocations = np.array(range(len(class_labels))) + plt.xticks(xlocations, class_labels, rotation=90) + plt.yticks(xlocations, class_labels) + plt.ylabel('Actual label' if is_ascii else '实际标签') + plt.xlabel('Predict label' if is_ascii else '预测标签') + + # 调整刻度标记位置,提高可视化效果 + tick_marks = np.array(range(len(class_labels))) + 0.5 + plt.gca().set_xticks(tick_marks, minor=True) + plt.gca().set_yticks(tick_marks, minor=True) + plt.gca().xaxis.set_ticks_position('none') + plt.gca().yaxis.set_ticks_position('none') + plt.grid(True, which='minor', linestyle='-') + plt.gcf().subplots_adjust(bottom=0.15) + # 保存图片 + os.makedirs(os.path.dirname(save_path), exist_ok=True) + plt.savefig(save_path, format='png') + if show: + # 显示图片 + plt.show() + + +# 根据a的类型,将b转换为相应的类型 +def convert_string_based_on_type(a, b): + if isinstance(a, int): + try: + b = int(b) + except ValueError: + logger.error("无法将字符串转换为整数") + elif isinstance(a, float): + try: + b = float(b) + except ValueError: + logger.error("无法将字符串转换为浮点数") + elif isinstance(a, str): + return b + elif isinstance(a, bool): + b = b.lower() == 'true' + else: + try: + b = eval(b) + except Exception as e: + logger.exception("无法将字符串转换为其他类型,将忽略该参数类型转换") + return b diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/record_audio.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/record_audio.py new file mode 100644 index 0000000..406808f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/record_audio.py @@ -0,0 +1,14 @@ +import time + +from macls.utils.record import RecordAudio + +s = input('请输入你计划录音多少秒:') +record_seconds = int(s) +save_path = "dataset/save_audio/%s.wav" % str(int(time.time()*1000)) + +record_audio = RecordAudio() +input(f"按下回车键开机录音,录音{record_seconds}秒中:") +record_audio.record(record_seconds=record_seconds, + save_path=save_path) + +print('文件保存在:%s' % save_path) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/requirements.txt b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/requirements.txt new file mode 100644 index 0000000..52c91bf --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/requirements.txt @@ -0,0 +1,17 @@ +numpy>=1.19.2 +scipy>=1.6.3 +librosa>=0.9.1 +soundfile>=0.12.1 +soundcard>=0.4.2 +resampy>=0.2.2 +numba>=0.53.0 +pydub~=0.25.1 +matplotlib>=3.5.2 +pillow>=10.3.0 +tqdm>=4.66.3 +visualdl==2.5.3 +pyyaml>=5.4.1 +scikit-learn>=1.0.2 +torchinfo>=1.7.2 +loguru>=0.7.2 +yeaudio>=0.0.7 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/setup.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/setup.py new file mode 100644 index 0000000..7fc9e0b --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/setup.py @@ -0,0 +1,54 @@ +import shutil + +from setuptools import setup, find_packages + +import macls + +VERSION = macls.__version__ + +# 复制配置文件到项目目录下 +shutil.rmtree('./macls/configs/', ignore_errors=True) +shutil.copytree('./configs/', './macls/configs/') + + +def readme(): + with open('README.md', encoding='utf-8') as f: + content = f.read() + return content + + +def parse_requirements(): + with open('./requirements.txt', encoding="utf-8") as f: + requirements = f.readlines() + return requirements + + +if __name__ == "__main__": + setup( + name='macls', + packages=find_packages(), + package_data={'': ['configs/*']}, + author='yeyupiaoling', + version=VERSION, + install_requires=parse_requirements(), + description='Audio Classification toolkit on Pytorch', + long_description=readme(), + long_description_content_type='text/markdown', + url='https://github.com/yeyupiaoling/AudioClassification-Pytorch', + download_url='https://github.com/yeyupiaoling/AudioClassification-Pytorch.git', + keywords=['audio', 'pytorch'], + classifiers=[ + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Natural Language :: Chinese (Simplified)', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Utilities' + ], + license='Apache License 2.0', + ext_modules=[]) + shutil.rmtree('./macls/configs/', ignore_errors=True) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/tools/download_language_data.sh b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/tools/download_language_data.sh new file mode 100644 index 0000000..d0fe5e6 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/tools/download_language_data.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +download_dir=dataset/language + + +[ ! -d ${download_dir} ] && mkdir -p ${download_dir} + +if [ ! -f ${download_dir}/test.tar.gz ]; then + echo "准备下载测试集" + wget --no-check-certificate https://speech-lab-share-data.oss-cn-shanghai.aliyuncs.com/3D-Speaker/test.tar.gz -P ${download_dir} + md5=$(md5sum ${download_dir}/test.tar.gz | awk '{print $1}') + [ $md5 != "45972606dd10d3f7c1c31f27acdfbed7" ] && echo "Wrong md5sum of 3dspeaker test.tar.gz" && exit 1 +fi + +if [ ! -f ${download_dir}/train.tar.gz ]; then + echo "准备下载训练集" + wget --no-check-certificate https://speech-lab-share-data.oss-cn-shanghai.aliyuncs.com/3D-Speaker/train.tar.gz -P ${download_dir} + md5=$(md5sum ${download_dir}/train.tar.gz | awk '{print $1}') + [ $md5 != "c2cea55fd22a2b867d295fb35a2d3340" ] && echo "Wrong md5sum of 3dspeaker train.tar.gz" && exit 1 +fi + +echo "下载完成!" + +echo "准备解压" + +tar -zxvf ${download_dir}/train.tar.gz -C ${rawdata_dir}/ +tar -xzvf ${download_dir}/test.tar.gz -C ${rawdata_dir}/ + +echo "解压完成!" diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/train.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/train.py new file mode 100644 index 0000000..50f1cce --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/audio-classification/train.py @@ -0,0 +1,30 @@ +import argparse +import functools + +from macls.trainer import MAClsTrainer +from macls.utils.utils import add_arguments, print_arguments + +parser = argparse.ArgumentParser(description=__doc__) +add_arg = functools.partial(add_arguments, argparser=parser) +add_arg('configs', str, 'configs/cam++.yml', '配置文件') +add_arg('data_augment_configs', str, 'configs/augmentation.yml', '数据增强配置文件') +add_arg("local_rank", int, 0, '多卡训练需要的参数') +add_arg("use_gpu", bool, True, '是否使用GPU训练') +add_arg('save_model_path', str, 'models/', '模型保存的路径') +add_arg('log_dir', str, 'log/', '保存VisualDL日志文件的路径') +add_arg('resume_model', str, None, '恢复训练,当为None则不使用预训练模型') +add_arg('pretrained_model', str, None, '预训练模型的路径,当为None则不使用预训练模型') +add_arg('overwrites', str, None, '覆盖配置文件中的参数,比如"train_conf.max_epoch=100",多个用逗号隔开') +args = parser.parse_args() +print_arguments(args=args) + +# 获取训练器 +trainer = MAClsTrainer(configs=args.configs, + use_gpu=args.use_gpu, + data_augment_configs=args.data_augment_configs, + overwrites=args.overwrites) + +trainer.train(save_model_path=args.save_model_path, + log_dir=args.log_dir, + resume_model=args.resume_model, + pretrained_model=args.pretrained_model) diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/README.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/README.md new file mode 100644 index 0000000..eaf47f5 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/README.md @@ -0,0 +1,298 @@ +# 数据库配置文件说明 + +## 概述 + +本目录包含基于多模态的战场隐蔽威胁发现和定位系统的数据库配置文件。系统支持多种数据库类型,包括SQLite、MySQL、PostgreSQL和MongoDB。 + +## 文件结构 + +``` +database/ +├── config.py # 数据库配置文件 +├── db_utils.py # 数据库操作工具 +├── init_database.py # 数据库初始化脚本 +├── README.md # 说明文档 +└── database_config.json # 数据库配置文件(自动生成) +``` + +## 功能特性 + +### 支持的数据库类型 + +- **SQLite** (默认) - 轻量级文件数据库 +- **MySQL** - 关系型数据库 +- **PostgreSQL** - 高级关系型数据库 +- **MongoDB** - NoSQL文档数据库 + +### 数据库表结构 + +系统包含以下主要数据表: + +1. **target_detections** - 目标检测记录表 + - 存储检测到的目标信息 + - 包含目标类型、置信度、位置、威胁等级等 + +2. **uav_flights** - 无人机飞行记录表 + - 记录无人机飞行数据 + - 包含飞行时间、高度、距离、模式等 + +3. **sound_locations** - 声源定位记录表 + - 存储声源定位数据 + - 包含声源坐标、强度、角度、频率等 + +4. **system_logs** - 系统日志表 + - 记录系统运行日志 + - 包含日志级别、模块、消息等 + +5. **user_actions** - 用户操作记录表 + - 记录用户操作行为 + - 包含操作类型、详情、IP地址等 + +6. **device_status** - 设备状态记录表 + - 记录设备运行状态 + - 包含设备类型、状态、电池、信号等 + +7. **map_markers** - 地图标记表 + - 存储地图标记信息 + - 包含标记类型、坐标、标题等 + +## 使用方法 + +### 1. 基本配置 + +```python +from database.config import get_db_config, get_connection_string + +# 获取默认数据库配置 +config = get_db_config() + +# 获取指定数据库配置 +mysql_config = get_db_config("mysql") + +# 获取连接字符串 +conn_str = get_connection_string() +``` + +### 2. 数据库操作 + +```python +from database.db_utils import ( + DatabaseOperations, + target_detection_dao, + sound_location_dao, + system_log_dao +) + +# 插入目标检测记录 +detection_id = target_detection_dao.insert_detection( + target_type="vehicle", + confidence=0.95, + distance=150.5, + latitude=39.9042, + longitude=116.4074, + threat_level="high" +) + +# 插入声源定位记录 +sound_id = sound_location_dao.insert_sound_location( + source_x=100.0, + source_y=200.0, + strength=0.8, + angle=45.0, + frequency=1000.0 +) + +# 记录系统日志 +system_log_dao.insert_log( + level="INFO", + module="target_detection", + message="检测到可疑目标" +) +``` + +### 3. 初始化数据库 + +```bash +# 运行数据库初始化脚本 +python init_database.py +``` + +### 4. 自定义配置 + +编辑 `database_config.json` 文件来自定义数据库配置: + +```json +{ + "default_database": "sqlite", + "databases": { + "sqlite": { + "type": "sqlite", + "database": "battlefield_system.db", + "echo": false, + "pool_size": 5, + "max_overflow": 10 + }, + "mysql": { + "type": "mysql", + "host": "localhost", + "port": 3306, + "database": "battlefield_system", + "username": "root", + "password": "your_password", + "charset": "utf8mb4" + } + } +} +``` + +## 配置说明 + +### 数据库配置参数 + +- **host**: 数据库服务器地址 +- **port**: 数据库端口 +- **database**: 数据库名称 +- **username**: 用户名 +- **password**: 密码 +- **charset**: 字符集 +- **pool_size**: 连接池大小 +- **max_overflow**: 最大溢出连接数 +- **pool_timeout**: 连接池超时时间 +- **pool_recycle**: 连接回收时间 +- **echo**: 是否显示SQL语句 + +### 连接池配置 + +系统使用连接池来管理数据库连接,提高性能和稳定性: + +- **pool_size**: 连接池中保持的连接数 +- **max_overflow**: 超过pool_size后最多可以创建的连接数 +- **pool_timeout**: 从连接池获取连接的超时时间 +- **pool_recycle**: 连接在连接池中的回收时间 + +## 性能优化 + +### 索引优化 + +系统自动创建以下索引以提高查询性能: + +- 时间戳索引:用于时间范围查询 +- 类型索引:用于分类查询 +- 置信度索引:用于阈值筛选 +- 坐标索引:用于地理位置查询 + +### 查询优化建议 + +1. **使用参数化查询**:避免SQL注入,提高性能 +2. **限制查询结果**:使用LIMIT子句限制返回记录数 +3. **合理使用索引**:在WHERE子句中使用索引字段 +4. **批量操作**:使用executemany进行批量插入 + +## 错误处理 + +### 常见错误及解决方案 + +1. **连接失败** + - 检查数据库服务是否启动 + - 验证连接参数是否正确 + - 确认网络连接正常 + +2. **权限错误** + - 检查用户权限 + - 确认数据库用户存在 + - 验证密码是否正确 + +3. **表不存在** + - 运行初始化脚本创建表 + - 检查表名是否正确 + - 确认数据库选择正确 + +### 日志记录 + +系统自动记录数据库操作日志: + +```python +from database.db_utils import log_system_event + +# 记录系统事件 +log_system_event( + level="ERROR", + module="database", + message="数据库连接失败", + details="连接超时" +) +``` + +## 安全考虑 + +### 数据安全 + +1. **密码加密**:数据库密码应加密存储 +2. **访问控制**:限制数据库访问权限 +3. **数据备份**:定期备份重要数据 +4. **审计日志**:记录所有数据库操作 + +### SQL注入防护 + +1. **参数化查询**:使用参数化查询避免SQL注入 +2. **输入验证**:验证所有用户输入 +3. **权限最小化**:使用最小权限原则 + +## 扩展开发 + +### 添加新的数据表 + +1. 在 `DatabaseTables` 类中定义表结构 +2. 创建对应的DAO类 +3. 添加索引定义 +4. 更新初始化脚本 + +### 添加新的数据库类型 + +1. 在配置文件中添加新数据库配置 +2. 实现连接逻辑 +3. 更新连接字符串生成方法 +4. 测试连接和操作 + +## 测试 + +### 运行测试 + +```bash +# 测试数据库配置 +python config.py + +# 测试数据库操作 +python db_utils.py + +# 完整初始化测试 +python init_database.py +``` + +### 测试内容 + +- 数据库连接测试 +- 表创建测试 +- 数据插入测试 +- 查询操作测试 +- 性能测试 + +## 维护 + +### 日常维护 + +1. **监控连接池**:检查连接池使用情况 +2. **清理日志**:定期清理系统日志 +3. **优化查询**:分析慢查询并优化 +4. **备份数据**:定期备份数据库 + +### 版本升级 + +1. **备份数据**:升级前备份所有数据 +2. **测试升级**:在测试环境验证升级 +3. **更新配置**:更新配置文件 +4. **验证功能**:验证所有功能正常 + +## 技术支持 + +如有问题,请联系系统开发团队或查看系统日志获取详细信息。 \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/config.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/config.py new file mode 100644 index 0000000..b93cda7 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/config.py @@ -0,0 +1,432 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +数据库配置文件 +基于多模态的战场隐蔽威胁发现和定位系统数据库配置 + +支持多种数据库类型: +- SQLite (默认) +- MySQL +- PostgreSQL +- MongoDB (NoSQL) + +作者: 系统开发团队 +创建时间: 2024 +""" + +import os +import json +import logging +from typing import Dict, Any, Optional +from dataclasses import dataclass +from pathlib import Path + +# 配置日志 +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +@dataclass +class DatabaseConfig: + """数据库配置数据类""" + host: str = "localhost" + port: int = 3306 + database: str = "battlefield_system" + username: str = "root" + password: str = "" + charset: str = "utf8mb4" + pool_size: int = 10 + max_overflow: int = 20 + pool_timeout: int = 30 + pool_recycle: int = 3600 + echo: bool = False + + +class DatabaseManager: + """数据库管理器类""" + + def __init__(self, config_file: str = "database_config.json"): + """ + 初始化数据库管理器 + + Args: + config_file: 配置文件路径 + """ + self.config_file = config_file + self.config = self._load_config() + self.connections = {} + + def _load_config(self) -> Dict[str, Any]: + """ + 加载数据库配置 + + Returns: + 配置字典 + """ + config_path = Path(__file__).parent / self.config_file + + # 如果配置文件不存在,创建默认配置 + if not config_path.exists(): + self._create_default_config(config_path) + + try: + with open(config_path, 'r', encoding='utf-8') as f: + config = json.load(f) + logger.info(f"成功加载数据库配置: {config_path}") + return config + except Exception as e: + logger.error(f"加载配置文件失败: {e}") + return self._get_default_config() + + def _create_default_config(self, config_path: Path): + """ + 创建默认配置文件 + + Args: + config_path: 配置文件路径 + """ + default_config = self._get_default_config() + + try: + with open(config_path, 'w', encoding='utf-8') as f: + json.dump(default_config, f, indent=4, ensure_ascii=False) + logger.info(f"创建默认配置文件: {config_path}") + except Exception as e: + logger.error(f"创建配置文件失败: {e}") + + def _get_default_config(self) -> Dict[str, Any]: + """ + 获取默认配置 + + Returns: + 默认配置字典 + """ + return { + "default_database": "sqlite", + "databases": { + "sqlite": { + "type": "sqlite", + "database": "battlefield_system.db", + "echo": False, + "pool_size": 5, + "max_overflow": 10 + }, + "mysql": { + "type": "mysql", + "host": "localhost", + "port": 3306, + "database": "battlefield_system", + "username": "root", + "password": "", + "charset": "utf8mb4", + "pool_size": 10, + "max_overflow": 20, + "pool_timeout": 30, + "pool_recycle": 3600, + "echo": False + }, + "postgresql": { + "type": "postgresql", + "host": "localhost", + "port": 5432, + "database": "battlefield_system", + "username": "postgres", + "password": "", + "pool_size": 10, + "max_overflow": 20, + "pool_timeout": 30, + "pool_recycle": 3600, + "echo": False + }, + "mongodb": { + "type": "mongodb", + "host": "localhost", + "port": 27017, + "database": "battlefield_system", + "username": "", + "password": "", + "pool_size": 10, + "max_overflow": 20, + "echo": False + } + }, + "logging": { + "level": "INFO", + "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + } + } + + def get_database_config(self, db_name: Optional[str] = None) -> DatabaseConfig: + """ + 获取指定数据库的配置 + + Args: + db_name: 数据库名称,如果为None则使用默认数据库 + + Returns: + 数据库配置对象 + """ + if db_name is None: + db_name = self.config.get("default_database", "sqlite") + + db_config = self.config["databases"].get(db_name) + if not db_config: + raise ValueError(f"未找到数据库配置: {db_name}") + + return DatabaseConfig(**db_config) + + def get_connection_string(self, db_name: Optional[str] = None) -> str: + """ + 获取数据库连接字符串 + + Args: + db_name: 数据库名称 + + Returns: + 连接字符串 + """ + config = self.get_database_config(db_name) + + if config.database == "sqlite": + return f"sqlite:///{config.database}" + elif config.database == "mysql": + return (f"mysql+pymysql://{config.username}:{config.password}" + f"@{config.host}:{config.port}/{config.database}" + f"?charset={config.charset}") + elif config.database == "postgresql": + return (f"postgresql://{config.username}:{config.password}" + f"@{config.host}:{config.port}/{config.database}") + elif config.database == "mongodb": + return f"mongodb://{config.host}:{config.port}/{config.database}" + else: + raise ValueError(f"不支持的数据库类型: {config.database}") + + +class DatabaseTables: + """数据库表结构定义""" + + # 目标检测记录表 + TARGET_DETECTION_TABLE = """ + CREATE TABLE IF NOT EXISTS target_detections ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + target_type VARCHAR(50) NOT NULL, + confidence FLOAT NOT NULL, + distance FLOAT, + latitude DOUBLE, + longitude DOUBLE, + altitude FLOAT, + image_path VARCHAR(255), + threat_level VARCHAR(20), + description TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + """ + + # 无人机飞行记录表 + UAV_FLIGHT_TABLE = """ + CREATE TABLE IF NOT EXISTS uav_flights ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + flight_id VARCHAR(50) UNIQUE NOT NULL, + start_time DATETIME, + end_time DATETIME, + duration INTEGER, + max_altitude FLOAT, + max_distance FLOAT, + flight_mode VARCHAR(20), + status VARCHAR(20), + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + """ + + # 声源定位记录表 + SOUND_LOCATION_TABLE = """ + CREATE TABLE IF NOT EXISTS sound_locations ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + source_x FLOAT NOT NULL, + source_y FLOAT NOT NULL, + strength FLOAT NOT NULL, + angle FLOAT NOT NULL, + frequency FLOAT, + confidence FLOAT, + latitude DOUBLE, + longitude DOUBLE, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + """ + + # 系统日志表 + SYSTEM_LOG_TABLE = """ + CREATE TABLE IF NOT EXISTS system_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + level VARCHAR(10) NOT NULL, + module VARCHAR(50) NOT NULL, + message TEXT NOT NULL, + details TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + """ + + # 用户操作记录表 + USER_ACTIONS_TABLE = """ + CREATE TABLE IF NOT EXISTS user_actions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + user_id VARCHAR(50), + action_type VARCHAR(50) NOT NULL, + action_detail TEXT, + ip_address VARCHAR(45), + user_agent TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + """ + + # 设备状态记录表 + DEVICE_STATUS_TABLE = """ + CREATE TABLE IF NOT EXISTS device_status ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + device_type VARCHAR(50) NOT NULL, + device_id VARCHAR(50) NOT NULL, + status VARCHAR(20) NOT NULL, + battery_level INTEGER, + signal_strength INTEGER, + temperature FLOAT, + humidity FLOAT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + """ + + # 地图标记表 + MAP_MARKERS_TABLE = """ + CREATE TABLE IF NOT EXISTS map_markers ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + marker_type VARCHAR(50) NOT NULL, + latitude DOUBLE NOT NULL, + longitude DOUBLE NOT NULL, + altitude FLOAT, + title VARCHAR(100), + description TEXT, + icon_path VARCHAR(255), + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + """ + + @classmethod + def get_all_tables(cls) -> Dict[str, str]: + """ + 获取所有表结构定义 + + Returns: + 表名和SQL语句的字典 + """ + return { + "target_detections": cls.TARGET_DETECTION_TABLE, + "uav_flights": cls.UAV_FLIGHT_TABLE, + "sound_locations": cls.SOUND_LOCATION_TABLE, + "system_logs": cls.SYSTEM_LOG_TABLE, + "user_actions": cls.USER_ACTIONS_TABLE, + "device_status": cls.DEVICE_STATUS_TABLE, + "map_markers": cls.MAP_MARKERS_TABLE + } + + +class DatabaseInitializer: + """数据库初始化器""" + + def __init__(self, db_manager: DatabaseManager): + """ + 初始化数据库初始化器 + + Args: + db_manager: 数据库管理器 + """ + self.db_manager = db_manager + + def initialize_database(self, db_name: Optional[str] = None): + """ + 初始化数据库 + + Args: + db_name: 数据库名称 + """ + try: + config = self.db_manager.get_database_config(db_name) + logger.info(f"开始初始化数据库: {config.database}") + + # 这里可以添加具体的数据库初始化逻辑 + # 例如创建表、插入初始数据等 + + logger.info(f"数据库初始化完成: {config.database}") + + except Exception as e: + logger.error(f"数据库初始化失败: {e}") + raise + + +# 全局数据库管理器实例 +db_manager = DatabaseManager() + +# 导出常用函数 +def get_db_config(db_name: Optional[str] = None) -> DatabaseConfig: + """ + 获取数据库配置 + + Args: + db_name: 数据库名称 + + Returns: + 数据库配置对象 + """ + return db_manager.get_database_config(db_name) + + +def get_connection_string(db_name: Optional[str] = None) -> str: + """ + 获取数据库连接字符串 + + Args: + db_name: 数据库名称 + + Returns: + 连接字符串 + """ + return db_manager.get_connection_string(db_name) + + +def initialize_database(db_name: Optional[str] = None): + """ + 初始化数据库 + + Args: + db_name: 数据库名称 + """ + initializer = DatabaseInitializer(db_manager) + initializer.initialize_database(db_name) + + +if __name__ == "__main__": + """测试数据库配置""" + try: + # 测试获取配置 + config = get_db_config() + print(f"默认数据库配置: {config}") + + # 测试获取连接字符串 + conn_str = get_connection_string() + print(f"连接字符串: {conn_str}") + + # 显示所有表结构 + tables = DatabaseTables.get_all_tables() + print(f"数据库表数量: {len(tables)}") + for table_name in tables.keys(): + print(f" - {table_name}") + + print("数据库配置测试完成") + + except Exception as e: + print(f"测试失败: {e}") \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/create_tables_simple.sql b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/create_tables_simple.sql new file mode 100644 index 0000000..d8d5b1f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/create_tables_simple.sql @@ -0,0 +1,102 @@ +-- 基于多模态的战场隐蔽威胁发现和定位系统数据库表结构 +-- 简化版本 - 逐个创建表 + +-- 启用外键约束 +PRAGMA foreign_keys = ON; + +-- 1. 目标检测记录表 +CREATE TABLE IF NOT EXISTS target_detections ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT DEFAULT (datetime('now')), + target_type TEXT NOT NULL, + confidence REAL NOT NULL, + distance REAL, + latitude REAL, + longitude REAL, + altitude REAL, + image_path TEXT, + threat_level TEXT, + description TEXT, + created_at TEXT DEFAULT (datetime('now')), + updated_at TEXT DEFAULT (datetime('now')) +); + +-- 2. 无人机飞行记录表 +CREATE TABLE IF NOT EXISTS uav_flights ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + flight_id TEXT UNIQUE NOT NULL, + start_time TEXT, + end_time TEXT, + duration INTEGER, + max_altitude REAL, + max_distance REAL, + flight_mode TEXT, + status TEXT, + created_at TEXT DEFAULT (datetime('now')) +); + +-- 3. 声源定位记录表 +CREATE TABLE IF NOT EXISTS sound_locations ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT DEFAULT (datetime('now')), + source_x REAL NOT NULL, + source_y REAL NOT NULL, + strength REAL NOT NULL, + angle REAL NOT NULL, + frequency REAL, + confidence REAL, + latitude REAL, + longitude REAL, + created_at TEXT DEFAULT (datetime('now')) +); + +-- 4. 系统日志表 +CREATE TABLE IF NOT EXISTS system_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT DEFAULT (datetime('now')), + level TEXT NOT NULL, + module TEXT NOT NULL, + message TEXT NOT NULL, + details TEXT, + created_at TEXT DEFAULT (datetime('now')) +); + +-- 5. 用户操作记录表 +CREATE TABLE IF NOT EXISTS user_actions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT DEFAULT (datetime('now')), + user_id TEXT, + action_type TEXT NOT NULL, + action_detail TEXT, + ip_address TEXT, + user_agent TEXT, + created_at TEXT DEFAULT (datetime('now')) +); + +-- 6. 设备状态记录表 +CREATE TABLE IF NOT EXISTS device_status ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT DEFAULT (datetime('now')), + device_type TEXT NOT NULL, + device_id TEXT NOT NULL, + status TEXT NOT NULL, + battery_level INTEGER, + signal_strength INTEGER, + temperature REAL, + humidity REAL, + created_at TEXT DEFAULT (datetime('now')) +); + +-- 7. 地图标记表 +CREATE TABLE IF NOT EXISTS map_markers ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + marker_type TEXT NOT NULL, + latitude REAL NOT NULL, + longitude REAL NOT NULL, + altitude REAL, + title TEXT, + description TEXT, + icon_path TEXT, + created_at TEXT DEFAULT (datetime('now')), + updated_at TEXT DEFAULT (datetime('now')) +); \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/create_tables_simple_mysql.sql b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/create_tables_simple_mysql.sql new file mode 100644 index 0000000..12b12d7 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/create_tables_simple_mysql.sql @@ -0,0 +1,99 @@ +-- 基于多模态的战场隐蔽威胁发现和定位系统数据库表结构 +-- MySQL版本 - 逐个创建表 + +-- 1. 目标检测记录表 +CREATE TABLE IF NOT EXISTS target_detections ( + id INT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + target_type VARCHAR(255) NOT NULL, + confidence DECIMAL(5,4) NOT NULL, + distance DECIMAL(10,3), + latitude DECIMAL(10,8), + longitude DECIMAL(11,8), + altitude DECIMAL(8,2), + image_path VARCHAR(500), + threat_level VARCHAR(50), + description TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); + +-- 2. 无人机飞行记录表 +CREATE TABLE IF NOT EXISTS uav_flights ( + id INT AUTO_INCREMENT PRIMARY KEY, + flight_id VARCHAR(100) UNIQUE NOT NULL, + start_time TIMESTAMP NULL, + end_time TIMESTAMP NULL, + duration INT, + max_altitude DECIMAL(8,2), + max_distance DECIMAL(10,3), + flight_mode VARCHAR(50), + status VARCHAR(50), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 3. 声源定位记录表 +CREATE TABLE IF NOT EXISTS sound_locations ( + id INT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + source_x DECIMAL(10,3) NOT NULL, + source_y DECIMAL(10,3) NOT NULL, + strength DECIMAL(8,2) NOT NULL, + angle DECIMAL(6,2) NOT NULL, + frequency DECIMAL(10,2), + confidence DECIMAL(5,4), + latitude DECIMAL(10,8), + longitude DECIMAL(11,8), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 4. 系统日志表 +CREATE TABLE IF NOT EXISTS system_logs ( + id INT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + level VARCHAR(20) NOT NULL, + module VARCHAR(100) NOT NULL, + message TEXT NOT NULL, + details TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 5. 用户操作记录表 +CREATE TABLE IF NOT EXISTS user_actions ( + id INT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + user_id VARCHAR(100), + action_type VARCHAR(100) NOT NULL, + action_detail TEXT, + ip_address VARCHAR(45), + user_agent TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 6. 设备状态记录表 +CREATE TABLE IF NOT EXISTS device_status ( + id INT AUTO_INCREMENT PRIMARY KEY, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + device_type VARCHAR(100) NOT NULL, + device_id VARCHAR(100) NOT NULL, + status VARCHAR(50) NOT NULL, + battery_level INT, + signal_strength INT, + temperature DECIMAL(5,2), + humidity DECIMAL(5,2), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- 7. 地图标记表 +CREATE TABLE IF NOT EXISTS map_markers ( + id INT AUTO_INCREMENT PRIMARY KEY, + marker_type VARCHAR(100) NOT NULL, + latitude DECIMAL(10,8) NOT NULL, + longitude DECIMAL(11,8) NOT NULL, + altitude DECIMAL(8,2), + title VARCHAR(255), + description TEXT, + icon_path VARCHAR(500), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/db_utils.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/db_utils.py new file mode 100644 index 0000000..edc1fca --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/db_utils.py @@ -0,0 +1,553 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +数据库操作工具 +基于多模态的战场隐蔽威胁发现和定位系统数据库操作工具 + +提供常用的数据库操作方法: +- 连接管理 +- CRUD操作 +- 批量操作 +- 事务管理 +- 查询构建 + +作者: 系统开发团队 +创建时间: 2024 +""" + +import sqlite3 +import logging +from typing import Dict, List, Any, Optional, Tuple +from datetime import datetime +from contextlib import contextmanager +from config import DatabaseManager, DatabaseConfig, get_db_config + +logger = logging.getLogger(__name__) + + +class DatabaseConnection: + """数据库连接管理类""" + + def __init__(self, config: DatabaseConfig): + """ + 初始化数据库连接 + + Args: + config: 数据库配置 + """ + self.config = config + self.connection = None + + def connect(self): + """建立数据库连接""" + try: + if self.config.database == "sqlite": + self.connection = sqlite3.connect( + self.config.database, + check_same_thread=False + ) + # 启用外键约束 + self.connection.execute("PRAGMA foreign_keys = ON") + else: + # 其他数据库类型的连接逻辑 + pass + + logger.info(f"成功连接到数据库: {self.config.database}") + + except Exception as e: + logger.error(f"数据库连接失败: {e}") + raise + + def disconnect(self): + """断开数据库连接""" + if self.connection: + self.connection.close() + self.connection = None + logger.info("数据库连接已断开") + + def get_cursor(self): + """获取数据库游标""" + if not self.connection: + self.connect() + return self.connection.cursor() + + def commit(self): + """提交事务""" + if self.connection: + self.connection.commit() + + def rollback(self): + """回滚事务""" + if self.connection: + self.connection.rollback() + + +class DatabaseOperations: + """数据库操作类""" + + def __init__(self, db_name: Optional[str] = None): + """ + 初始化数据库操作 + + Args: + db_name: 数据库名称 + """ + self.config = get_db_config(db_name) + self.connection = DatabaseConnection(self.config) + + @contextmanager + def get_connection(self): + """ + 获取数据库连接的上下文管理器 + + Yields: + 数据库连接对象 + """ + try: + self.connection.connect() + yield self.connection + except Exception as e: + self.connection.rollback() + logger.error(f"数据库操作失败: {e}") + raise + finally: + self.connection.disconnect() + + def execute_query(self, query: str, params: Optional[Tuple] = None) -> List[Dict[str, Any]]: + """ + 执行查询语句 + + Args: + query: SQL查询语句 + params: 查询参数 + + Returns: + 查询结果列表 + """ + with self.get_connection() as conn: + cursor = conn.get_cursor() + if params: + cursor.execute(query, params) + else: + cursor.execute(query) + + # 获取列名 + columns = [description[0] for description in cursor.description] + + # 获取结果 + results = [] + for row in cursor.fetchall(): + results.append(dict(zip(columns, row))) + + return results + + def execute_update(self, query: str, params: Optional[Tuple] = None) -> int: + """ + 执行更新语句 + + Args: + query: SQL更新语句 + params: 更新参数 + + Returns: + 影响的行数 + """ + with self.get_connection() as conn: + cursor = conn.get_cursor() + if params: + cursor.execute(query, params) + else: + cursor.execute(query) + + conn.commit() + return cursor.rowcount + + def execute_many(self, query: str, params_list: List[Tuple]) -> int: + """ + 批量执行SQL语句 + + Args: + query: SQL语句 + params_list: 参数列表 + + Returns: + 影响的行数 + """ + with self.get_connection() as conn: + cursor = conn.get_cursor() + cursor.executemany(query, params_list) + conn.commit() + return cursor.rowcount + + def insert_record(self, table: str, data: Dict[str, Any]) -> int: + """ + 插入单条记录 + + Args: + table: 表名 + data: 数据字典 + + Returns: + 插入记录的ID + """ + columns = list(data.keys()) + placeholders = ', '.join(['?' for _ in columns]) + values = tuple(data.values()) + + query = f"INSERT INTO {table} ({', '.join(columns)}) VALUES ({placeholders})" + + with self.get_connection() as conn: + cursor = conn.get_cursor() + cursor.execute(query, values) + conn.commit() + return cursor.lastrowid + + def update_record(self, table: str, data: Dict[str, Any], condition: str, params: Tuple) -> int: + """ + 更新记录 + + Args: + table: 表名 + data: 更新的数据 + condition: 更新条件 + params: 条件参数 + + Returns: + 影响的行数 + """ + set_clause = ', '.join([f"{key} = ?" for key in data.keys()]) + query = f"UPDATE {table} SET {set_clause} WHERE {condition}" + + # 合并参数 + all_params = tuple(data.values()) + params + + return self.execute_update(query, all_params) + + def delete_record(self, table: str, condition: str, params: Tuple) -> int: + """ + 删除记录 + + Args: + table: 表名 + condition: 删除条件 + params: 条件参数 + + Returns: + 影响的行数 + """ + query = f"DELETE FROM {table} WHERE {condition}" + return self.execute_update(query, params) + + def get_record_by_id(self, table: str, record_id: int) -> Optional[Dict[str, Any]]: + """ + 根据ID获取记录 + + Args: + table: 表名 + record_id: 记录ID + + Returns: + 记录字典,如果不存在返回None + """ + query = f"SELECT * FROM {table} WHERE id = ?" + results = self.execute_query(query, (record_id,)) + return results[0] if results else None + + def get_records(self, table: str, condition: Optional[str] = None, + params: Optional[Tuple] = None, limit: Optional[int] = None, + order_by: Optional[str] = None) -> List[Dict[str, Any]]: + """ + 获取多条记录 + + Args: + table: 表名 + condition: 查询条件 + params: 条件参数 + limit: 限制数量 + order_by: 排序条件 + + Returns: + 记录列表 + """ + query = f"SELECT * FROM {table}" + + if condition: + query += f" WHERE {condition}" + + if order_by: + query += f" ORDER BY {order_by}" + + if limit: + query += f" LIMIT {limit}" + + return self.execute_query(query, params) + + +class TargetDetectionDAO: + """目标检测数据访问对象""" + + def __init__(self, db_ops: DatabaseOperations): + """ + 初始化目标检测DAO + + Args: + db_ops: 数据库操作对象 + """ + self.db_ops = db_ops + + def insert_detection(self, target_type: str, confidence: float, + distance: Optional[float] = None, latitude: Optional[float] = None, + longitude: Optional[float] = None, altitude: Optional[float] = None, + image_path: Optional[str] = None, threat_level: Optional[str] = None, + description: Optional[str] = None) -> int: + """ + 插入目标检测记录 + + Args: + target_type: 目标类型 + confidence: 置信度 + distance: 距离 + latitude: 纬度 + longitude: 经度 + altitude: 高度 + image_path: 图像路径 + threat_level: 威胁等级 + description: 描述 + + Returns: + 记录ID + """ + data = { + 'target_type': target_type, + 'confidence': confidence, + 'distance': distance, + 'latitude': latitude, + 'longitude': longitude, + 'altitude': altitude, + 'image_path': image_path, + 'threat_level': threat_level, + 'description': description, + 'timestamp': datetime.now() + } + + return self.db_ops.insert_record('target_detections', data) + + def get_detections_by_type(self, target_type: str, limit: int = 100) -> List[Dict[str, Any]]: + """ + 根据目标类型获取检测记录 + + Args: + target_type: 目标类型 + limit: 限制数量 + + Returns: + 检测记录列表 + """ + return self.db_ops.get_records( + 'target_detections', + condition='target_type = ?', + params=(target_type,), + limit=limit, + order_by='timestamp DESC' + ) + + def get_high_confidence_detections(self, min_confidence: float = 0.8) -> List[Dict[str, Any]]: + """ + 获取高置信度检测记录 + + Args: + min_confidence: 最小置信度 + + Returns: + 检测记录列表 + """ + return self.db_ops.get_records( + 'target_detections', + condition='confidence >= ?', + params=(min_confidence,), + order_by='confidence DESC' + ) + + +class SoundLocationDAO: + """声源定位数据访问对象""" + + def __init__(self, db_ops: DatabaseOperations): + """ + 初始化声源定位DAO + + Args: + db_ops: 数据库操作对象 + """ + self.db_ops = db_ops + + def insert_sound_location(self, source_x: float, source_y: float, strength: float, + angle: float, frequency: Optional[float] = None, + confidence: Optional[float] = None, latitude: Optional[float] = None, + longitude: Optional[float] = None) -> int: + """ + 插入声源定位记录 + + Args: + source_x: 声源X坐标 + source_y: 声源Y坐标 + strength: 强度 + angle: 角度 + frequency: 频率 + confidence: 置信度 + latitude: 纬度 + longitude: 经度 + + Returns: + 记录ID + """ + data = { + 'source_x': source_x, + 'source_y': source_y, + 'strength': strength, + 'angle': angle, + 'frequency': frequency, + 'confidence': confidence, + 'latitude': latitude, + 'longitude': longitude, + 'timestamp': datetime.now() + } + + return self.db_ops.insert_record('sound_locations', data) + + def get_recent_sound_locations(self, hours: int = 24) -> List[Dict[str, Any]]: + """ + 获取最近的声源定位记录 + + Args: + hours: 小时数 + + Returns: + 声源定位记录列表 + """ + query = """ + SELECT * FROM sound_locations + WHERE timestamp >= datetime('now', '-{} hours') + ORDER BY timestamp DESC + """.format(hours) + + return self.db_ops.execute_query(query) + + +class SystemLogDAO: + """系统日志数据访问对象""" + + def __init__(self, db_ops: DatabaseOperations): + """ + 初始化系统日志DAO + + Args: + db_ops: 数据库操作对象 + """ + self.db_ops = db_ops + + def insert_log(self, level: str, module: str, message: str, + details: Optional[str] = None) -> int: + """ + 插入系统日志 + + Args: + level: 日志级别 + module: 模块名称 + message: 日志消息 + details: 详细信息 + + Returns: + 记录ID + """ + data = { + 'level': level, + 'module': module, + 'message': message, + 'details': details, + 'timestamp': datetime.now() + } + + return self.db_ops.insert_record('system_logs', data) + + def get_logs_by_level(self, level: str, limit: int = 100) -> List[Dict[str, Any]]: + """ + 根据日志级别获取日志 + + Args: + level: 日志级别 + limit: 限制数量 + + Returns: + 日志记录列表 + """ + return self.db_ops.get_records( + 'system_logs', + condition='level = ?', + params=(level,), + limit=limit, + order_by='timestamp DESC' + ) + + +# 全局数据库操作实例 +db_operations = DatabaseOperations() + +# 导出DAO实例 +target_detection_dao = TargetDetectionDAO(db_operations) +sound_location_dao = SoundLocationDAO(db_operations) +system_log_dao = SystemLogDAO(db_operations) + + +def log_system_event(level: str, module: str, message: str, details: Optional[str] = None): + """ + 记录系统事件 + + Args: + level: 日志级别 + module: 模块名称 + message: 日志消息 + details: 详细信息 + """ + try: + system_log_dao.insert_log(level, module, message, details) + except Exception as e: + logger.error(f"记录系统日志失败: {e}") + + +if __name__ == "__main__": + """测试数据库操作""" + try: + # 测试插入目标检测记录 + detection_id = target_detection_dao.insert_detection( + target_type="vehicle", + confidence=0.95, + distance=150.5, + latitude=39.9042, + longitude=116.4074, + threat_level="high" + ) + print(f"插入目标检测记录成功,ID: {detection_id}") + + # 测试插入声源定位记录 + sound_id = sound_location_dao.insert_sound_location( + source_x=100.0, + source_y=200.0, + strength=0.8, + angle=45.0, + frequency=1000.0 + ) + print(f"插入声源定位记录成功,ID: {sound_id}") + + # 测试插入系统日志 + log_id = system_log_dao.insert_log( + level="INFO", + module="database_test", + message="数据库操作测试完成" + ) + print(f"插入系统日志成功,ID: {log_id}") + + print("数据库操作测试完成") + + except Exception as e: + print(f"测试失败: {e}") \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/init_database.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/init_database.py new file mode 100644 index 0000000..2c785a1 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/init_database.py @@ -0,0 +1,317 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +数据库初始化脚本 +基于多模态的战场隐蔽威胁发现和定位系统数据库初始化 + +功能: +- 创建数据库表结构 +- 插入初始数据 +- 创建索引 +- 设置约束 + +作者: 系统开发团队 +创建时间: 2024 +""" + +import os +import sys +import logging +from pathlib import Path + +# 添加当前目录到Python路径 +current_dir = Path(__file__).parent +sys.path.insert(0, str(current_dir)) + +from config import DatabaseManager, DatabaseTables, DatabaseInitializer +from db_utils import DatabaseOperations, log_system_event + +# 配置日志 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + + +class DatabaseSetup: + """数据库设置类""" + + def __init__(self): + """初始化数据库设置""" + self.db_manager = DatabaseManager() + self.db_ops = DatabaseOperations() + + def create_tables(self): + """创建数据库表""" + try: + logger.info("开始创建数据库表...") + + tables = DatabaseTables.get_all_tables() + + with self.db_ops.get_connection() as conn: + cursor = conn.get_cursor() + + for table_name, table_sql in tables.items(): + try: + cursor.execute(table_sql) + logger.info(f"成功创建表: {table_name}") + except Exception as e: + logger.error(f"创建表 {table_name} 失败: {e}") + raise + + conn.commit() + + logger.info("所有数据库表创建完成") + + except Exception as e: + logger.error(f"创建数据库表失败: {e}") + raise + + def create_indexes(self): + """创建数据库索引""" + try: + logger.info("开始创建数据库索引...") + + indexes = [ + # 目标检测表索引 + "CREATE INDEX IF NOT EXISTS idx_target_detections_timestamp ON target_detections(timestamp);", + "CREATE INDEX IF NOT EXISTS idx_target_detections_type ON target_detections(target_type);", + "CREATE INDEX IF NOT EXISTS idx_target_detections_confidence ON target_detections(confidence);", + "CREATE INDEX IF NOT EXISTS idx_target_detections_threat_level ON target_detections(threat_level);", + + # 无人机飞行表索引 + "CREATE INDEX IF NOT EXISTS idx_uav_flights_flight_id ON uav_flights(flight_id);", + "CREATE INDEX IF NOT EXISTS idx_uav_flights_start_time ON uav_flights(start_time);", + "CREATE INDEX IF NOT EXISTS idx_uav_flights_status ON uav_flights(status);", + + # 声源定位表索引 + "CREATE INDEX IF NOT EXISTS idx_sound_locations_timestamp ON sound_locations(timestamp);", + "CREATE INDEX IF NOT EXISTS idx_sound_locations_strength ON sound_locations(strength);", + "CREATE INDEX IF NOT EXISTS idx_sound_locations_angle ON sound_locations(angle);", + + # 系统日志表索引 + "CREATE INDEX IF NOT EXISTS idx_system_logs_timestamp ON system_logs(timestamp);", + "CREATE INDEX IF NOT EXISTS idx_system_logs_level ON system_logs(level);", + "CREATE INDEX IF NOT EXISTS idx_system_logs_module ON system_logs(module);", + + # 用户操作表索引 + "CREATE INDEX IF NOT EXISTS idx_user_actions_timestamp ON user_actions(timestamp);", + "CREATE INDEX IF NOT EXISTS idx_user_actions_user_id ON user_actions(user_id);", + "CREATE INDEX IF NOT EXISTS idx_user_actions_action_type ON user_actions(action_type);", + + # 设备状态表索引 + "CREATE INDEX IF NOT EXISTS idx_device_status_timestamp ON device_status(timestamp);", + "CREATE INDEX IF NOT EXISTS idx_device_status_device_type ON device_status(device_type);", + "CREATE INDEX IF NOT EXISTS idx_device_status_device_id ON device_status(device_id);", + + # 地图标记表索引 + "CREATE INDEX IF NOT EXISTS idx_map_markers_type ON map_markers(marker_type);", + "CREATE INDEX IF NOT EXISTS idx_map_markers_coordinates ON map_markers(latitude, longitude);" + ] + + with self.db_ops.get_connection() as conn: + cursor = conn.get_cursor() + + for index_sql in indexes: + try: + cursor.execute(index_sql) + logger.info(f"成功创建索引: {index_sql.split('ON')[1].split('(')[0].strip()}") + except Exception as e: + logger.error(f"创建索引失败: {e}") + raise + + conn.commit() + + logger.info("所有数据库索引创建完成") + + except Exception as e: + logger.error(f"创建数据库索引失败: {e}") + raise + + def insert_initial_data(self): + """插入初始数据""" + try: + logger.info("开始插入初始数据...") + + # 插入系统日志记录 + log_system_event( + level="INFO", + module="database_init", + message="数据库初始化开始", + details="系统启动,开始初始化数据库" + ) + + # 插入示例目标检测记录 + from db_utils import target_detection_dao, sound_location_dao + + # 插入示例目标检测数据 + sample_detections = [ + { + "target_type": "vehicle", + "confidence": 0.95, + "distance": 150.5, + "latitude": 39.9042, + "longitude": 116.4074, + "threat_level": "high", + "description": "检测到可疑车辆" + }, + { + "target_type": "person", + "confidence": 0.87, + "distance": 80.2, + "latitude": 39.9045, + "longitude": 116.4078, + "threat_level": "medium", + "description": "检测到人员活动" + }, + { + "target_type": "equipment", + "confidence": 0.92, + "distance": 200.0, + "latitude": 39.9040, + "longitude": 116.4070, + "threat_level": "high", + "description": "检测到军事装备" + } + ] + + for detection in sample_detections: + target_detection_dao.insert_detection(**detection) + logger.info(f"插入示例目标检测记录: {detection['target_type']}") + + # 插入示例声源定位数据 + sample_sound_locations = [ + { + "source_x": 100.0, + "source_y": 200.0, + "strength": 0.8, + "angle": 45.0, + "frequency": 1000.0, + "confidence": 0.85 + }, + { + "source_x": 150.0, + "source_y": 250.0, + "strength": 0.6, + "angle": 30.0, + "frequency": 800.0, + "confidence": 0.75 + } + ] + + for sound_loc in sample_sound_locations: + sound_location_dao.insert_sound_location(**sound_loc) + logger.info(f"插入示例声源定位记录: 角度{sound_loc['angle']}度") + + # 插入系统日志记录 + log_system_event( + level="INFO", + module="database_init", + message="数据库初始化完成", + details="初始数据插入完成" + ) + + logger.info("初始数据插入完成") + + except Exception as e: + logger.error(f"插入初始数据失败: {e}") + raise + + def setup_database(self): + """完整数据库设置""" + try: + logger.info("开始数据库设置...") + + # 1. 创建表 + self.create_tables() + + # 2. 创建索引 + self.create_indexes() + + # 3. 插入初始数据 + self.insert_initial_data() + + logger.info("数据库设置完成") + + except Exception as e: + logger.error(f"数据库设置失败: {e}") + raise + + def verify_database(self): + """验证数据库设置""" + try: + logger.info("开始验证数据库设置...") + + # 检查表是否存在 + tables = DatabaseTables.get_all_tables() + + with self.db_ops.get_connection() as conn: + cursor = conn.get_cursor() + + for table_name in tables.keys(): + cursor.execute(f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}'") + result = cursor.fetchone() + + if result: + logger.info(f"✓ 表 {table_name} 存在") + else: + logger.error(f"✗ 表 {table_name} 不存在") + return False + + # 检查记录数量 + cursor.execute("SELECT COUNT(*) FROM target_detections") + detection_count = cursor.fetchone()[0] + logger.info(f"目标检测记录数量: {detection_count}") + + cursor.execute("SELECT COUNT(*) FROM sound_locations") + sound_count = cursor.fetchone()[0] + logger.info(f"声源定位记录数量: {sound_count}") + + cursor.execute("SELECT COUNT(*) FROM system_logs") + log_count = cursor.fetchone()[0] + logger.info(f"系统日志记录数量: {log_count}") + + logger.info("数据库验证完成") + return True + + except Exception as e: + logger.error(f"数据库验证失败: {e}") + return False + + +def main(): + """主函数""" + try: + logger.info("=" * 50) + logger.info("基于多模态的战场隐蔽威胁发现和定位系统") + logger.info("数据库初始化工具") + logger.info("=" * 50) + + # 创建数据库设置对象 + db_setup = DatabaseSetup() + + # 执行数据库设置 + db_setup.setup_database() + + # 验证数据库设置 + if db_setup.verify_database(): + logger.info("✓ 数据库初始化成功") + else: + logger.error("✗ 数据库初始化失败") + return 1 + + logger.info("=" * 50) + logger.info("数据库初始化完成") + logger.info("=" * 50) + + return 0 + + except Exception as e: + logger.error(f"数据库初始化过程中发生错误: {e}") + return 1 + + +if __name__ == "__main__": + exit_code = main() + sys.exit(exit_code) \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/requirements.txt b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/requirements.txt new file mode 100644 index 0000000..8faf20e --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/requirements.txt @@ -0,0 +1,34 @@ +# 数据库配置文件依赖包 +# 基于多模态的战场隐蔽威胁发现和定位系统 + +# 核心依赖 +sqlite3>=3.0.0 # Python内置,无需安装 + +# 可选数据库驱动 +pymysql>=1.0.2 # MySQL数据库驱动 +psycopg2-binary>=2.9.5 # PostgreSQL数据库驱动 +pymongo>=4.3.3 # MongoDB数据库驱动 + +# 数据库ORM和工具 +sqlalchemy>=2.0.0 # SQL工具包和ORM +alembic>=1.11.0 # 数据库迁移工具 + +# 数据处理 +pandas>=1.5.0 # 数据处理和分析 +numpy>=1.24.0 # 数值计算 + +# 配置和日志 +pyyaml>=6.0 # YAML配置文件支持 +python-dotenv>=1.0.0 # 环境变量管理 + +# 测试工具 +pytest>=7.3.0 # 测试框架 +pytest-cov>=4.0.0 # 测试覆盖率 + +# 开发工具 +black>=23.0.0 # 代码格式化 +flake8>=6.0.0 # 代码检查 +mypy>=1.3.0 # 类型检查 + +# 性能监控 +memory-profiler>=0.60.0 # 内存使用分析 \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/setup_database.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/setup_database.py new file mode 100644 index 0000000..b099325 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/database/setup_database.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +数据库设置脚本 +基于多模态的战场隐蔽威胁发现和定位系统数据库设置 + +功能: +- 分步创建数据库表 +- 创建索引 +- 插入示例数据 +- 错误处理和回滚 + +作者: 系统开发团队 +创建时间: 2024 +""" + +import sqlite3 +import os +import sys +import logging +from pathlib import Path + +# 配置日志 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + + +class DatabaseSetup: + """数据库设置类""" + + def __init__(self, db_path: str = "battlefield_system.db"): + """ + 初始化数据库设置 + + Args: + db_path: 数据库文件路径 + """ + self.db_path = db_path + self.connection = None + + def connect(self): + """连接数据库""" + try: + self.connection = sqlite3.connect(self.db_path) + self.connection.execute("PRAGMA foreign_keys = ON") + logger.info(f"成功连接到数据库: {self.db_path}") + except Exception as e: + logger.error(f"数据库连接失败: {e}") + raise + + def disconnect(self): + """断开数据库连接""" + if self.connection: + self.connection.close() + logger.info("数据库连接已断开") + + def execute_sql_file(self, file_path: str, description: str): + """ + 执行SQL文件 + + Args: + file_path: SQL文件路径 + description: 操作描述 + """ + try: + logger.info(f"开始执行: {description}") + + if not os.path.exists(file_path): + logger.error(f"SQL文件不存在: {file_path}") + return False + + with open(file_path, 'r', encoding='utf-8') as f: + sql_content = f.read() + + # 分割SQL语句 + statements = [stmt.strip() for stmt in sql_content.split(';') if stmt.strip()] + + cursor = self.connection.cursor() + + for i, statement in enumerate(statements, 1): + if statement and not statement.startswith('--'): + try: + cursor.execute(statement) + logger.debug(f"执行语句 {i}/{len(statements)}: {statement[:50]}...") + except Exception as e: + logger.error(f"执行语句失败: {statement}") + logger.error(f"错误信息: {e}") + raise + + self.connection.commit() + logger.info(f"成功完成: {description}") + return True + + except Exception as e: + logger.error(f"执行失败: {description}") + logger.error(f"错误信息: {e}") + self.connection.rollback() + return False + + def create_tables(self): + """创建数据库表""" + return self.execute_sql_file( + "database/create_tables_fixed.sql", + "创建数据库表" + ) + + def create_indexes(self): + """创建索引""" + return self.execute_sql_file( + "database/create_indexes.sql", + "创建数据库索引" + ) + + def insert_sample_data(self): + """插入示例数据""" + return self.execute_sql_file( + "database/insert_sample_data.sql", + "插入示例数据" + ) + + def verify_database(self): + """验证数据库设置""" + try: + logger.info("开始验证数据库设置...") + + cursor = self.connection.cursor() + + # 检查表是否存在 + tables = [ + 'target_detections', 'uav_flights', 'sound_locations', + 'system_logs', 'user_actions', 'device_status', 'map_markers' + ] + + for table in tables: + cursor.execute(f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table}'") + result = cursor.fetchone() + if result: + logger.info(f"✓ 表 {table} 存在") + else: + logger.error(f"✗ 表 {table} 不存在") + return False + + # 检查记录数量 + for table in tables: + cursor.execute(f"SELECT COUNT(*) FROM {table}") + count = cursor.fetchone()[0] + logger.info(f"表 {table} 记录数量: {count}") + + logger.info("数据库验证完成") + return True + + except Exception as e: + logger.error(f"数据库验证失败: {e}") + return False + + def setup_database(self): + """完整数据库设置""" + try: + logger.info("=" * 50) + logger.info("基于多模态的战场隐蔽威胁发现和定位系统") + logger.info("数据库设置工具") + logger.info("=" * 50) + + # 连接数据库 + self.connect() + + # 1. 创建表 + if not self.create_tables(): + logger.error("创建表失败") + return False + + # 2. 创建索引 + if not self.create_indexes(): + logger.error("创建索引失败") + return False + + # 3. 插入示例数据 + if not self.insert_sample_data(): + logger.error("插入示例数据失败") + return False + + # 4. 验证数据库 + if not self.verify_database(): + logger.error("数据库验证失败") + return False + + logger.info("=" * 50) + logger.info("✓ 数据库设置成功完成") + logger.info("=" * 50) + + return True + + except Exception as e: + logger.error(f"数据库设置过程中发生错误: {e}") + return False + finally: + self.disconnect() + + +def main(): + """主函数""" + try: + # 创建数据库设置对象 + db_setup = DatabaseSetup() + + # 执行数据库设置 + success = db_setup.setup_database() + + if success: + logger.info("数据库设置成功") + return 0 + else: + logger.error("数据库设置失败") + return 1 + + except Exception as e: + logger.error(f"程序执行失败: {e}") + return 1 + + +if __name__ == "__main__": + exit_code = main() + sys.exit(exit_code) \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/FFVideoFormatConvert.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/FFVideoFormatConvert.cpp new file mode 100644 index 0000000..61e4cfc --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/FFVideoFormatConvert.cpp @@ -0,0 +1,165 @@ +// 包含FFmpeg视频格式转换类的头文件 +#include "FFVideoFormatConvert.h" +// 包含视频网络对象头文件 +#include "VideoObjNetwork.h" + +// FFmpeg视频格式转换类构造函数 +CFFVideoFormatConvert::CFFVideoFormatConvert(void) + : m_img_convert_ctx(NULL) // 图像转换上下文,初始化为NULL + , m_pFrame(NULL) // AVFrame指针,初始化为NULL + , m_pBuffer(NULL), m_uBufferSize(0) // 缓冲区指针和大小,初始化为NULL和0 + , m_iWidth(0), m_iHeight(0) // 图像宽度和高度,初始化为0 + , m_pImage(NULL) // QImage指针,初始化为NULL +{ +} + + +// FFmpeg视频格式转换类析构函数 +CFFVideoFormatConvert::~CFFVideoFormatConvert(void) +{ + Close(); // 调用Close函数清理资源 +} + +// 关闭并清理所有FFmpeg相关资源 +void CFFVideoFormatConvert::Close() +{ + // 释放图像转换上下文 + if (m_img_convert_ctx) + { + sws_freeContext(m_img_convert_ctx); // 释放SWS转换上下文 + m_img_convert_ctx = NULL; + } + + // 释放AVFrame + if (m_pFrame) + { + av_frame_free(&m_pFrame); // 释放AVFrame内存 + m_pFrame = NULL; + } + + // 释放缓冲区 + if (m_pBuffer) + { + av_free(m_pBuffer); // 释放FFmpeg分配的内存 + m_pBuffer = NULL; + m_uBufferSize = 0; + } + + // 释放QImage对象 + if (m_pImage != NULL) + { + delete m_pImage; // 删除QImage对象 + m_pImage = NULL; + } + + // 重置图像尺寸 + m_iWidth = 0; + m_iHeight = 0; +} + +// 将RGB32格式的QImage转换为YUV420P格式的AVFrame +bool CFFVideoFormatConvert::RGB32toYUV420P(const QImage* pIn, AVFrame** pOut) +{ + // 如果图像尺寸发生变化,重新初始化对象 + if (pIn->width() != m_iWidth || pIn->height() != m_iHeight) + { + Close(); // 清理旧资源 + } + + // 如果缓冲区未分配,则分配新的缓冲区 + if (m_pBuffer == NULL) + { + m_iWidth = pIn->width(); // 设置图像宽度 + m_iHeight = pIn->height(); // 设置图像高度 + // 计算YUV420P格式所需的缓冲区大小 + m_uBufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pIn->width(), pIn->height(), 1); + m_pBuffer = (uint8_t *) av_malloc(m_uBufferSize); // 分配FFmpeg内存 + } + + // 如果AVFrame未分配,则分配并初始化 + if (m_pFrame == NULL) + { + m_pFrame = av_frame_alloc(); // 分配AVFrame + m_pFrame->width = pIn->width(); // 设置帧宽度 + m_pFrame->height = pIn->height(); // 设置帧高度 + // 将缓冲区与AVFrame关联,设置数据指针和行步长 + av_image_fill_arrays(m_pFrame->data, m_pFrame->linesize, + m_pBuffer, AV_PIX_FMT_YUV420P, pIn->width(), pIn->height(), 1); + } + + // 如果图像转换上下文未创建,则创建转换上下文 + if (m_img_convert_ctx == NULL) + { + // 创建从RGB32到YUV420P的转换上下文,使用双三次插值算法 + m_img_convert_ctx = sws_getContext(pIn->width(), pIn->height(), + AV_PIX_FMT_RGB32, // 源格式:RGB32 + pIn->width(), pIn->height(), + AV_PIX_FMT_YUV420P, // 目标格式:YUV420P + SWS_BICUBIC, NULL, NULL, NULL); // 使用双三次插值 + } + + // 设置源数据指针和步长 + const uint8_t *const srcSlice[] = { pIn->bits() }; // 源数据指针 + const int srcStride[] = { pIn->bytesPerLine()}; // 源数据步长 + // 执行图像格式转换 + sws_scale(m_img_convert_ctx, + srcSlice, // 源数据 + srcStride, 0, pIn->height(), // 源步长和高度 + m_pFrame->data, // 目标数据 + m_pFrame->linesize); // 目标步长 + + *pOut = m_pFrame; // 返回转换后的AVFrame + return true; +} + +// 将YUV420P格式的AVFrame转换为RGB32格式的QImage +bool CFFVideoFormatConvert::YUV420P2RGB32(const AVFrame* pIn, QImage** pOut) +{ + // 如果图像尺寸发生变化,重新初始化对象 + if (pIn->width != m_iWidth || pIn->height != m_iHeight) + { + Close(); // 清理旧资源 + } + + // 如果缓冲区未分配,则分配新的缓冲区 + if (m_pBuffer == NULL) + { + m_iWidth = pIn->width; // 设置图像宽度 + m_iHeight = pIn->height; // 设置图像高度 + // 计算RGB32格式所需的缓冲区大小 + m_uBufferSize = av_image_get_buffer_size(AV_PIX_FMT_RGB32, pIn->width, pIn->height, 1); + m_pBuffer = (uint8_t *)av_malloc(m_uBufferSize); // 分配FFmpeg内存 + } + + // 如果AVFrame未分配,则分配并初始化 + if (m_pFrame == NULL) + { + m_pFrame = av_frame_alloc(); // 分配AVFrame + // 将缓冲区与AVFrame关联,设置数据指针和行步长 + av_image_fill_arrays(m_pFrame->data, m_pFrame->linesize, + m_pBuffer, AV_PIX_FMT_RGB32, pIn->width, pIn->height, 1); + } + + // 如果图像转换上下文未创建,则创建转换上下文 + if (m_img_convert_ctx == NULL) + { + // 创建从YUV420P到RGB32的转换上下文,使用双三次插值算法 + m_img_convert_ctx = sws_getContext(pIn->width, pIn->height, + AV_PIX_FMT_YUV420P, // 源格式:YUV420P + pIn->width, pIn->height, + AV_PIX_FMT_RGB32, // 目标格式:RGB32 + SWS_BICUBIC, NULL, NULL, NULL); // 使用双三次插值 + } + + // 执行图像格式转换 + sws_scale(m_img_convert_ctx, + (uint8_t const * const *)pIn->data, // 源数据 + pIn->linesize, 0, pIn->height, // 源步长和高度 + m_pFrame->data, // 目标数据 + m_pFrame->linesize); // 目标步长 + + // 创建新的QImage对象,使用转换后的RGB32数据 + *pOut = new QImage((uchar *)m_pFrame->data[0], m_iWidth, m_iHeight, QImage::Format_RGB32); + + return true; +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/FFVideoFormatConvert.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/FFVideoFormatConvert.h new file mode 100644 index 0000000..e137282 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/FFVideoFormatConvert.h @@ -0,0 +1,40 @@ +// 防止头文件重复包含 +#pragma once +// 包含Qt图像处理类 +#include + +// FFmpeg视频帧结构体前向声明 +struct AVFrame; +// FFmpeg软件缩放上下文结构体前向声明 +struct SwsContext; + +// FFmpeg视频格式转换类 +// 用于在Qt的QImage和FFmpeg的AVFrame之间进行格式转换 +class CFFVideoFormatConvert +{ +public: + // 构造函数:初始化所有成员变量 + CFFVideoFormatConvert(void); + // 析构函数:清理所有FFmpeg相关资源 + ~CFFVideoFormatConvert(void); + + // 将RGB32格式的QImage转换为YUV420P格式的AVFrame + bool RGB32toYUV420P(const QImage* pIn, AVFrame** pOut); + // 将YUV420P格式的AVFrame转换为RGB32格式的QImage + bool YUV420P2RGB32(const AVFrame* pIn, QImage** pOut); +private: + // 私有方法:关闭并清理所有FFmpeg相关资源 + void Close(); +private: + // 私有成员变量 + SwsContext* m_img_convert_ctx; // FFmpeg图像转换上下文指针 + AVFrame* m_pFrame; // FFmpeg视频帧指针 + + uint8_t* m_pBuffer; // 图像数据缓冲区指针 + uint m_uBufferSize; // 缓冲区大小 + int m_iWidth; // 图像宽度 + int m_iHeight; // 图像高度 + + QImage* m_pImage; // Qt图像对象指针 +}; + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/MapWidget.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/MapWidget.cpp new file mode 100644 index 0000000..2747c4b --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/MapWidget.cpp @@ -0,0 +1,305 @@ +#include "MapWidget.h" +#include +#include +#include +#include + +/** + * @brief MapWidget构造函数 + * @param parent 父窗口指针 + * + * 初始化地图组件,创建QQuickWidget用于显示QML地图, + * 设置默认布局和初始化地图相关属性 + */ +MapWidget::MapWidget(QWidget *parent) + : QWidget(parent), + m_quickWidget(nullptr), + m_mapItem(nullptr), + m_uavMarker(nullptr), + m_rootObject(nullptr), + m_targetCounter(0) +{ + // 创建布局 + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + // 创建QQuickWidget + m_quickWidget = new QQuickWidget(this); + m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + // 初始化地图 + initializeMap(); + + // 添加到布局 + layout->addWidget(m_quickWidget); + setLayout(layout); +} + +/** + * @brief MapWidget析构函数 + * + * 清理资源,清除所有目标标记 + */ +MapWidget::~MapWidget() +{ + // 清除目标标记 + clearTargetMarkers(); +} + +/** + * @brief 初始化地图 + * + * 设置地图的默认位置(长沙),配置QML上下文属性, + * 加载地图QML文件,获取地图和标记对象引用 + */ +void MapWidget::initializeMap() +{ + // 设置默认位置 (默认为长沙) + m_currentPosition = QGeoCoordinate(28.1544, 113.0216); + + // 设置QML上下文属性 + m_quickWidget->rootContext()->setContextProperty("mapWidget", this); + m_quickWidget->rootContext()->setContextProperty("uavPosition", QVariant::fromValue(m_currentPosition)); + m_quickWidget->rootContext()->setContextProperty("uavTrajectory", QVariant::fromValue(m_trajectory)); + + // 加载QML + m_quickWidget->setSource(QUrl("qrc:/qml/Map.qml")); + + // 检查QML是否加载成功 + if (m_quickWidget->status() != QQuickWidget::Ready) { + qWarning() << "地图QML加载失败:" << m_quickWidget->errors(); + return; + } + + // 获取地图和标记对象 + m_rootObject = m_quickWidget->rootObject(); + if (m_rootObject) { + m_mapItem = m_rootObject->findChild("map"); + m_uavMarker = m_rootObject->findChild("uavMarker"); + + if (!m_mapItem) { + qWarning() << "无法找到地图对象"; + } + + if (!m_uavMarker) { + qWarning() << "无法找到无人机标记对象"; + } + } else { + qWarning() << "无法获取QML根对象"; + } +} + +/** + * @brief 设置无人机位置 + * @param position 无人机的地理坐标位置 + * + * 更新当前无人机位置,将位置添加到轨迹中, + * 并更新QML上下文中的位置和轨迹属性 + */ +void MapWidget::setUAVPosition(const QGeoCoordinate &position) +{ + m_currentPosition = position; + + // 更新QML中的位置 + m_quickWidget->rootContext()->setContextProperty("uavPosition", QVariant::fromValue(m_currentPosition)); + + // 将位置添加到轨迹 + m_trajectory.addCoordinate(position); + m_quickWidget->rootContext()->setContextProperty("uavTrajectory", QVariant::fromValue(m_trajectory)); +} + +/** + * @brief 设置无人机轨迹 + * @param trajectory 无人机轨迹坐标点数组 + * + * 清空当前轨迹,设置新的轨迹路径, + * 更新QML上下文中的轨迹属性 + */ +void MapWidget::setUAVTrajectory(const QVector &trajectory) +{ + // 创建一个空的GeoPath,然后添加坐标 + m_trajectory = QGeoPath(); + for (const QGeoCoordinate &coord : trajectory) { + m_trajectory.addCoordinate(coord); + } + m_quickWidget->rootContext()->setContextProperty("uavTrajectory", QVariant::fromValue(m_trajectory)); +} + +/** + * @brief 清除无人机轨迹 + * + * 清空当前轨迹数据,重置轨迹显示 + */ +void MapWidget::clearTrajectory() +{ + m_trajectory = QGeoPath(); + m_quickWidget->rootContext()->setContextProperty("uavTrajectory", QVariant::fromValue(m_trajectory)); +} + +/** + * @brief 设置地图中心位置 + * @param center 地图中心的地理坐标 + * + * 通过QML方法调用将地图中心移动到指定位置, + * 包含异常处理机制 + */ +void MapWidget::setMapCenter(const QGeoCoordinate ¢er) +{ + if (!m_mapItem) { + qWarning() << "setMapCenter: 地图对象为空"; + return; + } + + try { + QMetaObject::invokeMethod(m_mapItem, "centerOn", + Q_ARG(QVariant, QVariant::fromValue(center))); + } catch (const std::exception &e) { + qWarning() << "setMapCenter异常:" << e.what(); + } catch (...) { + qWarning() << "setMapCenter未知异常"; + } +} + +/** + * @brief 设置地图缩放级别 + * @param zoomLevel 缩放级别值 + * + * 通过QML方法调用设置地图的缩放级别, + * 包含异常处理机制 + */ +void MapWidget::setZoomLevel(double zoomLevel) +{ + if (!m_mapItem) { + qWarning() << "setZoomLevel: 地图对象为空"; + return; + } + + try { + QMetaObject::invokeMethod(m_mapItem, "setZoomLevel", + Q_ARG(QVariant, zoomLevel)); + } catch (const std::exception &e) { + qWarning() << "setZoomLevel异常:" << e.what(); + } catch (...) { + qWarning() << "setZoomLevel未知异常"; + } +} + +/** + * @brief 切换地图类型 + * + * 在普通地图和卫星地图之间切换, + * 通过修改QML根对象的属性来实现地图类型切换 + */ +void MapWidget::toggleMapType() +{ + if (m_rootObject) { + // 获取当前地图类型 + QVariant currentType = m_rootObject->property("currentMapType"); + + // 切换地图类型 + QString newType = (currentType.toString() == "normal") ? "satellite" : "normal"; + + // 设置新的地图类型 + m_rootObject->setProperty("currentMapType", newType); + + // 记录信息以便调试 + qDebug() << "地图类型已切换为:" << newType; + } else { + qWarning() << "toggleMapType: m_rootObject为空,无法切换地图类型"; + } +} + +/** + * @brief 获取当前地图类型 + * @return 当前地图类型字符串("normal"或"satellite") + * + * 从QML根对象获取当前地图类型属性 + */ +QString MapWidget::getCurrentMapType() const +{ + if (m_rootObject) { + return m_rootObject->property("currentMapType").toString(); + } + return "normal"; +} + +/** + * @brief 添加目标标记 + * @param position 目标的地理坐标位置 + * @param distance 目标距离(米) + * @param uncertainty 定位不确定性(米) + * + * 在地图上添加新的目标标记,包含位置、距离和不确定性信息, + * 通过QML方法调用创建标记,并维护本地标记列表 + */ +void MapWidget::addTargetMarker(const QGeoCoordinate &position, double distance, double uncertainty) +{ + if (!m_mapItem || !m_rootObject) { + qWarning() << "addTargetMarker: 地图对象为空"; + return; + } + + try { + m_targetCounter++; + + // 调用QML创建目标标记 + QVariant returnedValue; + QMetaObject::invokeMethod(m_rootObject, "createTargetMarker", + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, QVariant::fromValue(position)), + Q_ARG(QVariant, distance), + Q_ARG(QVariant, uncertainty), + Q_ARG(QVariant, m_targetCounter)); + + if (returnedValue.isValid() && returnedValue.canConvert()) { + QQuickItem* targetMarker = qvariant_cast(returnedValue); + if (targetMarker) { + m_targetMarkers.append(targetMarker); + qDebug() << "目标标记已添加 #" << m_targetCounter << " 在位置: " + << position.latitude() << ", " << position.longitude() + << " 距离: " << distance << "m, 不确定性: " << uncertainty << "m"; + } + } + } catch (const std::exception &e) { + qWarning() << "addTargetMarker异常:" << e.what(); + } catch (...) { + qWarning() << "addTargetMarker未知异常"; + } +} + +/** + * @brief 清除所有目标标记 + * + * 通过QML方法调用清除地图上的所有目标标记, + * 同时清空本地标记列表 + */ +void MapWidget::clearTargetMarkers() +{ + if (!m_rootObject) { + return; + } + + try { + // 调用QML清除所有标记 + QMetaObject::invokeMethod(m_rootObject, "clearTargetMarkers"); + + // 清空本地标记列表 + m_targetMarkers.clear(); + qDebug() << "所有目标标记已清除"; + } catch (const std::exception &e) { + qWarning() << "clearTargetMarkers异常:" << e.what(); + } catch (...) { + qWarning() << "clearTargetMarkers未知异常"; + } +} + +/** + * @brief 获取当前无人机位置 + * @return 当前无人机的地理坐标 + * + * 返回当前存储的无人机位置信息 + */ +QGeoCoordinate MapWidget::getCurrentPosition() const +{ + return m_currentPosition; +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/MapWidget.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/MapWidget.h new file mode 100644 index 0000000..4522a09 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/MapWidget.h @@ -0,0 +1,62 @@ +#ifndef MAPWIDGET_H +#define MAPWIDGET_H + +#include +#include +#include +#include +#include + +class MapWidget : public QWidget +{ + Q_OBJECT +public: + explicit MapWidget(QWidget *parent = nullptr); + ~MapWidget(); + + // 设置无人机当前位置 + void setUAVPosition(const QGeoCoordinate &position); + + // 设置无人机轨迹 + void setUAVTrajectory(const QVector &trajectory); + + // 清除轨迹 + void clearTrajectory(); + + // 设置地图中心 + void setMapCenter(const QGeoCoordinate ¢er); + + // 设置地图缩放级别 + void setZoomLevel(double zoomLevel); + + // 切换地图类型 + void toggleMapType(); + + // 获取当前地图类型 + QString getCurrentMapType() const; + + // 添加目标标记 + void addTargetMarker(const QGeoCoordinate &position, double distance, double uncertainty = 20.0); + + // 清除所有目标标记 + void clearTargetMarkers(); + + // 获取当前无人机位置 + QGeoCoordinate getCurrentPosition() const; + +private: + // 初始化地图 + void initializeMap(); + +private: + QQuickWidget *m_quickWidget; + QQuickItem *m_mapItem; + QQuickItem *m_uavMarker; + QGeoPath m_trajectory; + QGeoCoordinate m_currentPosition; + QQuickItem *m_rootObject; + QList m_targetMarkers; // 存储目标标记列表 + int m_targetCounter; // 目标计数器 +}; + +#endif // MAPWIDGET_H \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/QtCameraCapture.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/QtCameraCapture.cpp new file mode 100644 index 0000000..1904751 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/QtCameraCapture.cpp @@ -0,0 +1,99 @@ +#include "QtCameraCapture.h" + +/** + * @brief QtCameraCapture构造函数 + * @param parent 父对象指针 + * + * 初始化摄像头捕获对象,继承自QAbstractVideoSurface, + * 用于处理视频帧数据 + */ +QtCameraCapture::QtCameraCapture(QObject *parent) : QAbstractVideoSurface(parent) +{ + +} + +/** + * @brief 获取支持的像素格式列表 + * @param handleType 视频缓冲区句柄类型(未使用) + * @return 支持的像素格式列表 + * + * 返回该视频表面支持的所有像素格式,包括: + * - ARGB32系列格式(带透明通道) + * - RGB32系列格式(24位和32位) + * - BGR系列格式(OpenCV常用格式) + * - YUV系列格式(视频压缩常用) + * - 灰度格式(Y8、Y16) + * - 压缩格式(JPEG、RAW等) + */ +QList QtCameraCapture::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const +{ + Q_UNUSED(handleType); + return QList() + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_ARGB32_Premultiplied + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_RGB565 + << QVideoFrame::Format_RGB555 + << QVideoFrame::Format_ARGB8565_Premultiplied + << QVideoFrame::Format_BGRA32 + << QVideoFrame::Format_BGRA32_Premultiplied + << QVideoFrame::Format_BGR32 + << QVideoFrame::Format_BGR24 + << QVideoFrame::Format_BGR565 + << QVideoFrame::Format_BGR555 + << QVideoFrame::Format_BGRA5658_Premultiplied + << QVideoFrame::Format_AYUV444 + << QVideoFrame::Format_AYUV444_Premultiplied + << QVideoFrame::Format_YUV444 + << QVideoFrame::Format_YUV420P + << QVideoFrame::Format_YV12 + << QVideoFrame::Format_UYVY + << QVideoFrame::Format_YUYV + << QVideoFrame::Format_NV12 + << QVideoFrame::Format_NV21 + << QVideoFrame::Format_IMC1 + << QVideoFrame::Format_IMC2 + << QVideoFrame::Format_IMC3 + << QVideoFrame::Format_IMC4 + << QVideoFrame::Format_Y8 + << QVideoFrame::Format_Y16 + << QVideoFrame::Format_Jpeg + << QVideoFrame::Format_CameraRaw + << QVideoFrame::Format_AdobeDng; +} + +/** + * @brief 处理视频帧数据 + * @param frame 输入的视频帧 + * @return 处理成功返回true,失败返回false + * + * 当摄像头捕获到新的视频帧时,此函数会被调用。 + * 函数会: + * 1. 检查帧是否有效 + * 2. 克隆帧数据以避免数据竞争 + * 3. 将视频帧映射到内存进行读取 + * 4. 将帧数据转换为QImage格式 + * 5. 发送frameAvailable信号通知其他组件 + * 6. 解除内存映射并返回处理结果 + */ +bool QtCameraCapture::present(const QVideoFrame &frame) +{ + if (frame.isValid()) { + // 克隆帧数据以避免数据竞争问题 + QVideoFrame cloneFrame(frame); + // 将帧数据映射到内存,以只读方式访问 + cloneFrame.map(QAbstractVideoBuffer::ReadOnly); + // 将视频帧转换为QImage格式 + const QImage image(cloneFrame.bits(), + cloneFrame.width(), + cloneFrame.height(), + QVideoFrame::imageFormatFromPixelFormat(cloneFrame.pixelFormat())); + // 发送信号通知其他组件有新帧可用 + emit frameAvailable(image); + // 解除内存映射 + cloneFrame.unmap(); + return true; + } + return false; +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/QtCameraCapture.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/QtCameraCapture.h new file mode 100644 index 0000000..e389b3f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/QtCameraCapture.h @@ -0,0 +1,116 @@ +#ifndef QTCAMERACAPTURE_H +#define QTCAMERACAPTURE_H + +#include +#include +#include + +/** + * @brief QtCameraCapture类 + * + * 摄像头捕获类,继承自QAbstractVideoSurface, + * 用于处理摄像头视频流数据,将视频帧转换为QImage格式 + */ +class QtCameraCapture : public QAbstractVideoSurface +{ + Q_OBJECT +public: + /** + * @brief 像素格式枚举 + * + * 定义了摄像头支持的各种像素格式,包括: + * - RGB系列格式(标准颜色格式) + * - ARGB系列格式(带透明通道) + * - BGR系列格式(OpenCV常用格式) + * - YUV系列格式(视频压缩格式) + * - 灰度格式(单通道) + * - 压缩格式(JPEG、RAW等) + */ + enum PixelFormat { + Format_Invalid, // 无效格式 + Format_ARGB32, // 32位ARGB格式 + Format_ARGB32_Premultiplied, // 32位预乘ARGB格式 + Format_RGB32, // 32位RGB格式 + Format_RGB24, // 24位RGB格式 + Format_RGB565, // 16位RGB565格式 + Format_RGB555, // 16位RGB555格式 + Format_ARGB8565_Premultiplied, // 预乘ARGB8565格式 + Format_BGRA32, // 32位BGRA格式 + Format_BGRA32_Premultiplied, // 32位预乘BGRA格式 + Format_BGR32, // 32位BGR格式 + Format_BGR24, // 24位BGR格式 + Format_BGR565, // 16位BGR565格式 + Format_BGR555, // 16位BGR555格式 + Format_BGRA5658_Premultiplied, // 预乘BGRA5658格式 + + Format_AYUV444, // 4:4:4 AYUV格式 + Format_AYUV444_Premultiplied, // 预乘4:4:4 AYUV格式 + Format_YUV444, // 4:4:4 YUV格式 + Format_YUV420P, // 4:2:0 YUV平面格式 + Format_YV12, // YV12格式 + Format_UYVY, // UYVY交错格式 + Format_YUYV, // YUYV交错格式 + Format_NV12, // NV12格式 + Format_NV21, // NV21格式 + Format_IMC1, // IMC1格式 + Format_IMC2, // IMC2格式 + Format_IMC3, // IMC3格式 + Format_IMC4, // IMC4格式 + Format_Y8, // 8位灰度格式 + Format_Y16, // 16位灰度格式 + + Format_Jpeg, // JPEG压缩格式 + + Format_CameraRaw, // 相机原始格式 + Format_AdobeDng, // Adobe DNG格式 + +#ifndef Q_QDOC + NPixelFormats, // 像素格式数量(仅用于内部计数) +#endif + Format_User = 1000 // 用户自定义格式起始值 + }; + + Q_ENUM(PixelFormat) + + /** + * @brief 构造函数 + * @param parent 父对象指针,默认为nullptr + * + * 创建QtCameraCapture对象,初始化摄像头捕获功能 + */ + explicit QtCameraCapture(QObject *parent = 0); + + /** + * @brief 获取支持的像素格式列表 + * @param handleType 视频缓冲区句柄类型,默认为NoHandle + * @return 支持的像素格式列表 + * + * 返回该视频表面支持的所有像素格式, + * 用于与摄像头协商最佳的像素格式 + */ + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + /** + * @brief 处理视频帧数据 + * @param frame 输入的视频帧 + * @return 处理成功返回true,失败返回false + * + * 当摄像头捕获到新的视频帧时,此函数会被调用。 + * 将视频帧转换为QImage格式并通过信号发送 + */ + bool present(const QVideoFrame &frame) override; + +signals: + /** + * @brief 帧可用信号 + * @param frame 转换后的QImage图像 + * + * 当新的视频帧被成功处理并转换为QImage格式后, + * 此信号会被发射,通知其他组件有新帧可用 + */ + void frameAvailable(QImage frame); + +}; + +#endif // QTCAMERACAPTURE_H diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/README.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/README.md new file mode 100644 index 0000000..e5bbb23 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/README.md @@ -0,0 +1,128 @@ +# 智能无人机红外监控系统 + +## 项目概述 + +本项目基于Viewpro云台控制和视频显示,结合红外图像智能识别和MAVLink无人机控制系统,实现了一套完整的智能红外监控系统。系统可以通过网络连接飞控,控制无人机执行各种飞行任务,并通过红外摄像头获取目标图像,进行智能识别和分析。 + +## 主要功能 + +### 云台和摄像头控制 +- 支持通过网络或串口连接云台 +- 实时视频流显示 +- 云台俯仰、横滚、偏航控制 +- 拍照和录像功能 + +### 红外智能识别 +- 红外图像增强处理 +- 基于智谱AI大模型的目标识别分析 +- 可调节置信度阈值 +- 选择性预处理优化 + +### 无人机控制 +- 通过MAVLink协议连接和控制无人机 +- 支持起飞、降落、返航等基本飞行操作 +- 多种飞行模式切换(手动、稳定、定高、定点、自动等) +- 实时飞行数据监控(高度、速度、姿态、电量等) +- 地图定位跟踪 + +## 依赖项 + +### 系统依赖 +- Qt 5.12+ +- OpenCV 4.x+ +- libcurl +- openssl +- nlohmann/json (header-only library) + +### 地图依赖 +- Qt Location module +- Qt Positioning module + +### MAVLink依赖 +- MAVLink 库 (需要包含在项目中) + +## 安装依赖 + +### Ubuntu/Debian系统 +```bash +# 安装Qt依赖 +sudo apt-get install qt5-default qtdeclarative5-dev qtpositioning5-dev \ + qtlocation5-dev qml-module-qtlocation \ + qml-module-qtpositioning + +# 安装网络和加密依赖 +sudo apt-get install libcurl4-openssl-dev libssl-dev + +# 安装OpenCV +sudo apt-get install libopencv-dev + +# 安装nlohmann/json库 +sudo apt-get install nlohmann-json3-dev + + +# 安装依赖(补充) +sudo apt-get install qtdeclarative5-dev qtquickcontrols2-5-dev +``` + +## 编译和运行 + +### 编译项目 +```bash +cd demo/demo_for_qt +mkdir build && cd build +qmake ../demo_for_qt.pro +make +``` + +### 运行程序 +```bash +./demo_for_qt +``` + +## 使用说明 + +### 摄像头和云台控制 +1. 在连接设置区输入云台IP地址和端口 +2. 点击"连接"按钮建立连接 +3. 连接成功后,可以使用控制按钮调整云台位置 +4. 点击"拍照"按钮可以拍摄静态图片 +5. 点击"开始录像"/"停止录像"按钮可以录制视频 + +### 红外智能识别 +1. 调整识别置信度阈值滑块 +2. 选择是否进行图像预处理 +3. 点击"红外目标识别"按钮对当前画面进行分析 +4. 识别结果将显示在文本框内 +5. 点击"清除识别结果"可以清除历史记录 + +### 无人机控制 +1. 切换到"无人机控制"选项卡 +2. 输入飞控的IP地址和MAVLink端口(默认14550) +3. 点击"连接"按钮与无人机建立连接 +4. 连接成功后,使用控制按钮进行操作: + - "解锁"按钮:解锁电机 + - "起飞"按钮:自动起飞(会提示输入高度) + - "降落"按钮:自动降落 + - "返航"按钮:返回起飞点 + - 使用模式下拉框和"切换模式"按钮切换飞行模式 +5. 实时飞行数据将显示在界面上 +6. 无人机位置将在地图上实时更新 + +## 常见问题 + +### 无法连接到云台 +- 检查IP地址和端口是否正确 +- 确认云台已开机且已连接到同一网络 +- 尝试ping云台IP确认网络连通性 + +### 无法连接到无人机 +- 确认飞控已通过UDP转发MAVLink数据 +- 检查IP地址和端口配置 +- 如果使用本地模拟器(如SITL),确认模拟器已正确配置MAVLink输出 + +### 地图显示问题 +- 确保网络连接正常(地图需要互联网连接获取瓦片) +- 如果使用商业地图服务,可能需要添加API密钥 + +## 许可证 +本项目采用Apache 2.0许可证。详见LICENSE文件。 \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/RecordingFlash_32x32.png b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/RecordingFlash_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..98971a145e9e25aa9745c23f70e17bc639c52f7a GIT binary patch literal 526 zcmV+p0`dKcP)m-J4;JTY*Xk&!+J=E~wQp4U}a+k +#include "ShaderSourceCode.h" +#include +#include +#include +#include "widget.h" + +extern "C" { +#include "libavutil/frame.h" +}; + +#define LOCAL_RECORD_FLASH_ELAPSE 500 + +/** + * @brief OpenGL顶点和纹理坐标数据 + * + * 定义用于渲染YUV视频的顶点坐标和纹理坐标 + * 前4个值为顶点坐标,后4个值为纹理坐标 + */ +static const GLfloat vertices[] = { + // vertex coordinate + -1.0f, -1.0f, + 1.0f, -1.0f, + -1.0f, 1.0f, + 1.0f, 1.0f, + // texture coordinate + 0.0f, 1.0f, + 1.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f +}; + +/** + * @brief VLKVideoWidget构造函数 + * + * 初始化OpenGL视频显示组件,设置着色器、纹理、UI元素等 + * 支持拖拽、鼠标交互、本地录制闪烁等功能 + */ +VLKVideoWidget::VLKVideoWidget(QWidget *parent) + : QOpenGLWidget(parent) + , m_textureUniformY(0), m_textureUniformU(0), m_textureUniformV(0) + , m_vertexInAttr(0), m_textureInAttr(0) + , m_TextureIDY(0), m_TextureIDU(0), m_TextureIDV(0) + , m_pYData(NULL), m_pUData(NULL), m_pVData(NULL) + , m_iPixelW(0), m_iPixelH(0) + , m_bIsMagnified(false) + , m_bLButtonPressed(false) + , m_nStopZoomTimerID(0) + , m_pMainWidget(NULL) + , m_iCheckDragDistanceTimer(0) + , m_bIsRendering(false) + , m_iLocalRecordingFlashTimer(0), m_bFlashFlag(false) + , m_keepAspectRatio(true) + , m_targetAspectRatio(16.0f / 9.0f) // 初始化为1920:1080的比例 +{ + setAcceptDrops(true); + connect(this, SIGNAL(SignalEndOfFile()), this, SLOT(onSlotEndOfFile())); + + if (!m_pixmapBeginPos.load(":/image/circle_empty_48x48.png")) + { + qCritical() << "could not load image :/image/circle_empty_48x48.png"; + } + + if (!m_pixmapEndPos.load(":/image/circle_selected_32x32.png")) + { + qCritical() << "could not load image :/image/circle_selected_32x32.png"; + } + + if (!m_pixmapLocalRecord.load(":/image/RecordingFlash_32x32.png")) + { + qCritical() << "could not load image :/image/RecordingFlash_32x32.png"; + } + + m_fontNoSignal.setFamily("Microsoft YaHei"); + m_fontNoSignal.setPointSize(24); + m_fontNoSignal.setBold(true); + m_fontNoSignal.setLetterSpacing(QFont::AbsoluteSpacing, 0); +} + +/** + * @brief VLKVideoWidget析构函数 + * + * 清理OpenGL资源,删除纹理、缓冲区、定时器等 + */ +VLKVideoWidget::~VLKVideoWidget() +{ + makeCurrent(); + m_vbo.destroy(); + glDeleteTextures(1, &m_TextureIDY); + glDeleteTextures(1, &m_TextureIDU); + glDeleteTextures(1, &m_TextureIDV); + doneCurrent(); + + delete m_pYData; + delete m_pUData; + delete m_pVData; + + if (m_nStopZoomTimerID != 0) + { + killTimer(m_nStopZoomTimerID); + m_nStopZoomTimerID = 0; + } + + if (m_iCheckDragDistanceTimer != 0) + { + killTimer(m_iCheckDragDistanceTimer); + m_iCheckDragDistanceTimer = 0; + } +} + +/** + * @brief 初始化OpenGL + * + * 初始化着色器程序和纹理对象 + */ +void VLKVideoWidget::initializeGL() +{ + m_mutex.lock(); + + InitShader(); + InitTexture(); + + m_mutex.unlock(); +} + +/** + * @brief 初始化着色器程序 + * + * 加载顶点着色器和片段着色器,编译链接程序, + * 设置顶点属性位置和纹理uniform变量 + */ +bool VLKVideoWidget::InitShader() +{ + // intialize openGL (function of QOpenGLFunctions) + initializeOpenGLFunctions(); + + // program load shader(vertex and texture)script + // texture + if (!m_ShaderProgram.addShaderFromSourceCode(QGLShader::Fragment, tString)) + { + qDebug() << "program.addShaderFromSourceCode Fragment failed!"; + } + // vertex + if (!m_ShaderProgram.addShaderFromSourceCode(QGLShader::Vertex, vString)) + { + qDebug() << "program.addShaderFromSourceCode Vertex failed!"; + } + + // bind vertex coordinate + // m_ShaderProgram.bindAttributeLocation("vertexIn", A_VER); + + // bind texture coordinate + // m_ShaderProgram.bindAttributeLocation("textureIn", T_VER); + + // compile shader + if (!m_ShaderProgram.link()) + { + qDebug() << "program.link() failed!"; + } + + // qDebug() << "program.bind() = " << m_ShaderProgram.bind(); + + m_vertexInAttr = m_ShaderProgram.attributeLocation("vertexIn"); + m_textureInAttr = m_ShaderProgram.attributeLocation("textureIn"); + m_textureUniformY = m_ShaderProgram.uniformLocation("tex_y"); + m_textureUniformU = m_ShaderProgram.uniformLocation("tex_u"); + m_textureUniformV = m_ShaderProgram.uniformLocation("tex_v"); + + m_vbo.create(); + m_vbo.bind(); + m_vbo.allocate(vertices, sizeof(vertices)); + m_vbo.release(); + + return true; +} + +/** + * @brief 初始化纹理对象 + * + * 创建Y、U、V三个纹理对象,设置纹理参数 + */ +bool VLKVideoWidget::InitTexture() +{ + if (m_TextureIDY != 0) + { + glDeleteTextures(1, &m_TextureIDY); + glDeleteTextures(1, &m_TextureIDU); + glDeleteTextures(1, &m_TextureIDV); + } + + // generate texture + glGenTextures(1, &m_TextureIDY); + glGenTextures(1, &m_TextureIDU); + glGenTextures(1, &m_TextureIDV); + + // Y + glBindTexture(GL_TEXTURE_2D, m_TextureIDY); + // linear interpolation + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0); + + // U + glBindTexture(GL_TEXTURE_2D, m_TextureIDU); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0); + + // V + glBindTexture(GL_TEXTURE_2D, m_TextureIDV); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0); + + glClearColor(0.0, 0.0, 0.0, 0.0); + + return 0; +} + +/** + * @brief OpenGL绘制函数 + * + * 渲染YUV视频数据,绘制UI覆盖层(方向操作图标、录制闪烁、状态信息等) + */ +void VLKVideoWidget::paintGL() +{ + QPainter painter; + painter.begin(this); + // painter.setRenderHint(QPainter::Antialiasing, true); + + /******************************************************************* + openGL render YUV data + ********************************************************************/ + painter.beginNativePainting(); + //Clear + // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glFrontFace(GL_CW); + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + + m_ShaderProgram.bind(); + RenderYUV(); + m_ShaderProgram.release(); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + painter.endNativePainting(); + + + /***************************************************************** + QPainter overlay text or image on video + ******************************************************************/ + DrawDirectionOperateImg(painter); + DrawLocalRecordFlash(painter); + if (!m_bIsRendering) + { + DrawVideoStatus(painter); + } + + painter.end(); +} + +/** + * @brief 渲染YUV视频数据 + * + * 使用OpenGL着色器渲染YUV420P格式的视频帧, + * 支持宽高比保持和视口调整 + */ +void VLKVideoWidget::RenderYUV() +{ + if (m_iPixelW <= 0 || m_iPixelH <= 0) { + return; + } + + m_mutex.lock(); + + // 计算实际显示区域 + QRect displayRect = m_keepAspectRatio ? m_displayRect : rect(); + + // 设置视口 + glViewport(displayRect.x(), displayRect.y(), displayRect.width(), displayRect.height()); + + // 启用着色器程序 + m_ShaderProgram.bind(); + + // 设置Y纹理 + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_TextureIDY); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_iPixelW, m_iPixelH, 0, GL_RED, GL_UNSIGNED_BYTE, m_pYData); + glUniform1i(m_textureUniformY, 0); + + // 设置U纹理 + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_TextureIDU); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_iPixelW / 2, m_iPixelH / 2, 0, GL_RED, GL_UNSIGNED_BYTE, m_pUData); + glUniform1i(m_textureUniformU, 1); + + // 设置V纹理 + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, m_TextureIDV); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_iPixelW / 2, m_iPixelH / 2, 0, GL_RED, GL_UNSIGNED_BYTE, m_pVData); + glUniform1i(m_textureUniformV, 2); + + // 顶点数据 + m_vbo.bind(); + m_ShaderProgram.enableAttributeArray(m_vertexInAttr); + m_ShaderProgram.setAttributeBuffer(m_vertexInAttr, GL_FLOAT, 0, 2, 2 * sizeof(float)); + + // 纹理坐标 + m_ShaderProgram.enableAttributeArray(m_textureInAttr); + m_ShaderProgram.setAttributeBuffer(m_textureInAttr, GL_FLOAT, 8 * sizeof(float), 2, 2 * sizeof(float)); + + // 绘制 + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // 禁用顶点数组 + m_ShaderProgram.disableAttributeArray(m_vertexInAttr); + m_ShaderProgram.disableAttributeArray(m_textureInAttr); + m_vbo.release(); + + // 禁用着色器程序 + m_ShaderProgram.release(); + + m_mutex.unlock(); +} + +/** + * @brief 绘制方向操作图标 + * + * 在视频上绘制拖拽操作的开始和结束位置图标 + */ +void VLKVideoWidget::DrawDirectionOperateImg(QPainter& painter) +{ + if (!m_bLButtonPressed || m_ptBegin == m_ptEnd) + { + return; + } + painter.save(); + if (m_ptBegin.x() != 0 && m_ptBegin.y() != 0) + { + painter.drawPixmap(m_ptBegin.x() - (m_pixmapBeginPos.width()>>1), + m_ptBegin.y() - (m_pixmapBeginPos.height() >> 1), m_pixmapBeginPos); + } + + if (m_ptEnd.x() != 0 && m_ptEnd.y() != 0) + { + painter.drawPixmap(m_ptEnd.x() - (m_pixmapEndPos.width() >> 1), + m_ptEnd.y() - (m_pixmapEndPos.height() >> 1), m_pixmapEndPos); + } + painter.restore(); +} + +/** + * @brief 绘制本地录制闪烁图标 + * + * 在视频右上角显示录制状态的闪烁图标 + */ +void VLKVideoWidget::DrawLocalRecordFlash(QPainter& painter) +{ + if (m_iLocalRecordingFlashTimer != 0 && m_bFlashFlag) + { + painter.save(); + painter.drawPixmap(this->rect().width() - m_pixmapLocalRecord.width() - 10, 10, m_pixmapLocalRecord); + painter.restore(); + } +} + +/** + * @brief 绘制遥测信息 + * + * 在视频上显示高度、视场角等遥测数据 + */ +void VLKVideoWidget::DrawTelemetryInfo(QPainter& painter) +{ + painter.save(); + + painter.setFont(m_font); + painter.setPen(QPen(QColor(200, 200, 200))); + painter.drawText(20, 20, "ALT -17m FOV 17.5"); + + painter.restore(); +} + +/** + * @brief 绘制视频状态信息 + * + * 当没有视频信号时显示"No signal"提示 + */ +void VLKVideoWidget::DrawVideoStatus(QPainter& painter) +{ + painter.save(); + + painter.setFont(m_fontNoSignal); + painter.setPen(QPen(QColor(100, 100, 100))); + + QFontMetrics fontMetrics(m_fontNoSignal); + int iX = (rect().width() - fontMetrics.width("No signal"))>>1; + int iY = (rect().height() - fontMetrics.height()) >> 1; + painter.drawText(iX, iY, "No signal"); + + painter.restore(); +} + +/** + * @brief 窗口大小改变事件 + * + * 重新计算保持宽高比的显示区域 + */ +void VLKVideoWidget::resizeGL(int width, int height) +{ + Q_UNUSED(width); + Q_UNUSED(height); + + if (m_keepAspectRatio) { + m_displayRect = calculateAspectRatioRect(); + } else { + m_displayRect = rect(); + } +} + +/** + * @brief 初始化函数 + * + * 预留的初始化接口,当前未使用 + */ +void VLKVideoWidget::Init(int width, int height) +{ + Q_UNUSED(width); + Q_UNUSED(height); +} + +/** + * @brief 重绘视频帧 + * + * 接收FFmpeg解码后的AVFrame,更新YUV数据并触发重绘 + */ +void VLKVideoWidget::Repaint(const AVFrame *frame) +{ + if (!frame) + { + return; + } + + m_mutex.lock(); + // video width or height changed, reallocate texture memory + if (frame->width != m_iPixelW || frame->height != m_iPixelH) + { + if (m_pYData == NULL) // receive first video frame + { + m_bIsRendering = true; + emit RecieveFirstFrame(); + } + + delete m_pYData; + delete m_pUData; + delete m_pVData; + + // allocate texture memory + m_pYData = new unsigned char[frame->width * frame->height]; // Y + memset(m_pYData, 0, frame->width * frame->height); + m_pUData = new unsigned char[frame->width * frame->height / 4]; // U + memset(m_pUData, 0, frame->width * frame->height / 4); + m_pVData = new unsigned char[frame->width * frame->height / 4];// V + memset(m_pVData, 0, frame->width * frame->height / 4); + + m_iPixelW = frame->width; + m_iPixelH = frame->height; + } + if (m_iPixelW == frame->linesize[0]) // no need to handle line alignment + { + memcpy(m_pYData, frame->data[0], m_iPixelW * m_iPixelH); + memcpy(m_pUData, frame->data[1], m_iPixelW * m_iPixelH / 4); + memcpy(m_pVData, frame->data[2], m_iPixelW * m_iPixelH / 4); + } + else // handle line alignment + { + for (int i = 0; i < m_iPixelH; ++i) // Y + memcpy(m_pYData + m_iPixelW * i, frame->data[0] + frame->linesize[0] * i, m_iPixelW); + for (int i = 0; i < m_iPixelH / 2; ++i) // U + memcpy(m_pUData + m_iPixelW / 2 * i, frame->data[1] + frame->linesize[1] * i, m_iPixelW); + for (int i = 0; i < m_iPixelH / 2; ++i) // V + memcpy(m_pVData + m_iPixelW / 2 * i, frame->data[2] + frame->linesize[2] * i, m_iPixelW); + } + m_mutex.unlock(); + + update(); +} + +/** + * @brief 文件结束信号 + * + * 发送文件结束信号 + */ +void VLKVideoWidget::EndOfFile() +{ + emit SignalEndOfFile(); +} + +/** + * @brief 文件结束槽函数 + * + * 处理文件结束事件,清空视频数据并停止录制闪烁 + */ +void VLKVideoWidget::onSlotEndOfFile() +{ + Clear(); + m_bIsRendering = false; + ShowLocalRecordFlash(false); +} + +/** + * @brief 清空视频数据 + * + * 释放YUV数据内存,清空OpenGL缓冲区 + */ +void VLKVideoWidget::Clear() +{ + m_mutex.lock(); + if (m_pYData != NULL) + { + delete m_pYData; + m_pYData = NULL; + delete m_pUData; + m_pUData = NULL; + delete m_pVData; + m_pVData = NULL; + } + m_iPixelW = m_iPixelH = 0; + m_mutex.unlock(); + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + update(); +} + +/** + * @brief 拖拽进入事件 + * + * 处理拖拽进入事件,允许外部拖拽 + */ +void VLKVideoWidget::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->source() == this) + event->ignore(); + else + event->accept(); +} + +/** + * @brief 拖拽释放事件 + * + * 处理拖拽释放事件,当前未实现具体功能 + */ +void VLKVideoWidget::dropEvent(QDropEvent *event) +{ + Q_UNUSED(event); +/* const QMimeData* data = event->mimeData(); + + int iDevID = Utils::bytesToInt(data->data("DeviceID")); + QString strName = data->data("DeviceName"); +*/ +} + +/** + * @brief 右键菜单事件 + * + * 处理右键菜单事件,当前未实现 + */ +void VLKVideoWidget::contextMenuEvent(QContextMenuEvent * event) +{ + Q_UNUSED(event); + // m_menu->move(cursor().pos()); + // m_menu->show(); +} + +/** + * @brief 右键菜单槽函数 + * + * 处理右键菜单动作,当前未实现 + */ +void VLKVideoWidget::on_SlotContextMenu(QAction* action) +{ + Q_UNUSED(action); +} + +/** + * @brief 鼠标双击事件 + * + * 处理鼠标双击,发送目标跟踪命令 + */ +void VLKVideoWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + // check if the device has track capability + //... + + // send track command + VLK_TRACK_MODE_PARAM param; + param.emTrackTempSize = VLK_TRACK_TEMPLATE_SIZE_AUTO; + param.emTrackSensor = VLK_SENSOR_VISIBLE1; + + QRect rc = this->rect(); + int iImgPosX = ((float)event->pos().x() / (float)rc.width()) * m_iPixelW; + int iImgPosY = ((float)event->pos().y() / (float)rc.height()) * m_iPixelH; + + VLK_TrackTargetPositionEx(¶m, iImgPosX, iImgPosY, m_iPixelW, m_iPixelH); +} + +/** + * @brief 鼠标滚轮事件 + * + * 处理鼠标滚轮,控制缩放功能 + */ +void VLKVideoWidget::wheelEvent(QWheelEvent* event) +{ + if (event->delta() > 0) // wheel is moving forward + { + if (m_nStopZoomTimerID != 0) + { + killTimer(m_nStopZoomTimerID); + m_nStopZoomTimerID = 0; + } + VLK_ZoomIn(4); + + m_nStopZoomTimerID = startTimer(500); + } + else // wheel is moving backward + { + if (m_nStopZoomTimerID != 0) + { + killTimer(m_nStopZoomTimerID); + m_nStopZoomTimerID = 0; + } + VLK_ZoomOut(4); + + m_nStopZoomTimerID = startTimer(500); + } +} + +/** + * @brief 鼠标按下事件 + * + * 处理鼠标按下,开始拖拽操作或停止跟踪 + */ +void VLKVideoWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + { + m_bLButtonPressed = true; + m_ptBegin = event->pos(); + m_ptEnd = event->pos(); + m_iCheckDragDistanceTimer = startTimer(100); + update(); + } + else if (event->button() == Qt::RightButton) + { + // check if the device has track capability + //... + + // send stop tracking command + VLK_DisableTrackMode(); + } +} + +/** + * @brief 鼠标移动事件 + * + * 处理鼠标移动,更新拖拽结束位置 + */ +void VLKVideoWidget::mouseMoveEvent(QMouseEvent *event) +{ + if (m_bLButtonPressed) + { + m_ptEnd = event->pos(); + update(); + } +} + +/** + * @brief 鼠标释放事件 + * + * 处理鼠标释放,结束拖拽操作并发送停止移动命令 + */ +void VLKVideoWidget::mouseReleaseEvent(QMouseEvent *event) +{ + Q_UNUSED(event); + if (m_ptBegin != m_ptEnd) + { + if (m_iCheckDragDistanceTimer != 0) + { + killTimer(m_iCheckDragDistanceTimer); + m_iCheckDragDistanceTimer = 0; + } + + // send stop moving command + VLK_Stop(); + } + + m_ptBegin.setX(0); + m_ptBegin.setY(0); + m_ptEnd.setX(0); + m_ptEnd.setY(0); + + m_bLButtonPressed = false; + update(); +} + +/** + * @brief 定时器事件 + * + * 处理各种定时器事件:停止缩放、拖拽距离检查、录制闪烁 + */ +void VLKVideoWidget::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == m_nStopZoomTimerID) + { + // send stop zooming commmand + VLK_StopZoom(); + + killTimer(m_nStopZoomTimerID); + m_nStopZoomTimerID = 0; + } + else if (event->timerId() == m_iCheckDragDistanceTimer) + { + static short sPrevHorizontalSpeed = 0; + static short sPrevVerticalSpeed = 0; + + // calculate move speed by drag distance + short sHorizontalDist = m_ptEnd.x() - m_ptBegin.x(); + short sVerticalDist = m_ptBegin.y() - m_ptEnd.y(); + if (sHorizontalDist == 0 && sVerticalDist == 0) + { + return; + } + + QRect rc = this->rect(); + short sHorizontalSpeed = ((float)sHorizontalDist / (float)rc.width()) * VLK_MAX_YAW_SPEED; + short sVerticalSpeed = ((float)sVerticalDist / (float)rc.height()) * VLK_MAX_PITCH_SPEED; + if (sHorizontalSpeed != sPrevHorizontalSpeed || sVerticalSpeed != sPrevVerticalSpeed) + { + VLK_Move(sHorizontalSpeed, sVerticalSpeed); + } + + sPrevHorizontalSpeed = sHorizontalSpeed; + sPrevVerticalSpeed = sVerticalSpeed; + } + else if (event->timerId() == m_iLocalRecordingFlashTimer) + { + m_bFlashFlag = !m_bFlashFlag; + } +} + +/** + * @brief 显示本地录制闪烁 + * + * 控制录制状态闪烁图标的显示和隐藏 + */ +void VLKVideoWidget::ShowLocalRecordFlash(bool bShow) +{ + if (bShow) + { + m_bFlashFlag = true; + m_iLocalRecordingFlashTimer = startTimer(LOCAL_RECORD_FLASH_ELAPSE); + } + else + { + m_bFlashFlag = false; + if (m_iLocalRecordingFlashTimer !=0) + { + killTimer(m_iLocalRecordingFlashTimer); + m_iLocalRecordingFlashTimer = 0; + } + } +} + +/** + * @brief 设置标准尺寸 + * + * 设置目标宽高比,用于保持视频显示比例 + */ +void VLKVideoWidget::setStandardSize(int width, int height) +{ + if (width > 0 && height > 0) { + m_targetAspectRatio = static_cast(width) / static_cast(height); + update(); + } +} + +/** + * @brief 计算宽高比矩形 + * + * 根据目标宽高比计算实际显示区域,保持视频比例不变形 + */ +QRect VLKVideoWidget::calculateAspectRatioRect() const +{ + QRect result = rect(); + + if (m_targetAspectRatio <= 0) { + return result; + } + + float currentRatio = static_cast(result.width()) / static_cast(result.height()); + + if (qAbs(currentRatio - m_targetAspectRatio) < 0.001f) { + // 比例已经正确,不需要调整 + return result; + } + + if (currentRatio > m_targetAspectRatio) { + // 当前区域太宽,需要减小宽度 + int newWidth = qRound(result.height() * m_targetAspectRatio); + int offsetX = (result.width() - newWidth) / 2; + result.setLeft(result.left() + offsetX); + result.setRight(result.right() - offsetX); + } else { + // 当前区域太高,需要减小高度 + int newHeight = qRound(result.width() / m_targetAspectRatio); + int offsetY = (result.height() - newHeight) / 2; + result.setTop(result.top() + offsetY); + result.setBottom(result.bottom() - offsetY); + } + + return result; +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VLKVideoWidget.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VLKVideoWidget.h new file mode 100644 index 0000000..5bd9b9a --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VLKVideoWidget.h @@ -0,0 +1,137 @@ +#ifndef VLKVIDEOWIDGET_H +#define VLKVIDEOWIDGET_H + +#include +#include +#include +#include +#include +#include +#include + +struct AVFrame; +class Widget; + +/** + * @brief VLK视频显示组件类 + * + * 基于OpenGL的高性能视频显示组件,专门用于显示YUV420P格式的视频流。 + * 继承自QOpenGLWidget和QOpenGLFunctions,提供硬件加速的视频渲染功能。 + * + * 主要功能包括: + * - 使用OpenGL着色器渲染YUV420P视频数据 + * - 支持鼠标交互(拖拽、缩放、双击跟踪) + * - 保持视频宽高比,避免画面变形 + * - 显示UI覆盖层(操作图标、录制状态、遥测信息等) + * - 支持拖拽操作和右键菜单 + * - 本地录制状态闪烁提示 + * - 线程安全的视频数据更新 + * + * 适用于需要高性能视频显示和丰富交互功能的监控、无人机控制等应用场景。 + */ +class VLKVideoWidget : public QOpenGLWidget, protected QOpenGLFunctions +{ + Q_OBJECT +public: + virtual void Init(int width, int height); + virtual void Repaint(const AVFrame *frame); + virtual void EndOfFile(); + void Clear(); + void SetMainDialog(Widget* pMainWidget) { m_pMainWidget = pMainWidget; } + VLKVideoWidget(QWidget *parent); + ~VLKVideoWidget(); + void ShowLocalRecordFlash(bool bShow); + + // 设置是否保持宽高比 + void setKeepAspectRatio(bool keep) { m_keepAspectRatio = keep; update(); } + // 设置目标宽高比 + void setTargetAspectRatio(float ratio) { m_targetAspectRatio = ratio; update(); } + // 设置标准尺寸 + void setStandardSize(int width, int height); + +signals: + void RecieveFirstFrame(); + void SignalEndOfFile(); +protected: + virtual void initializeGL() override; + virtual void paintGL() override; + virtual void resizeGL(int width, int height) override; + virtual void dragEnterEvent(QDragEnterEvent *event) override; + virtual void dropEvent(QDropEvent * event) override; + virtual void contextMenuEvent(QContextMenuEvent * event) override; + virtual void mouseDoubleClickEvent(QMouseEvent *event) override; + virtual void wheelEvent(QWheelEvent* event) override; + virtual void mousePressEvent(QMouseEvent *event) override; + virtual void mouseMoveEvent(QMouseEvent *event) override; + virtual void mouseReleaseEvent(QMouseEvent *event) override; + virtual void timerEvent(QTimerEvent *event) override; +private slots: + void on_SlotContextMenu(QAction* action); + void onSlotEndOfFile(); +private: + bool InitShader(); + bool InitTexture(); + + void RenderYUV(); + void DrawDirectionOperateImg(QPainter& painter); + void DrawTelemetryInfo(QPainter& painter); + void DrawVideoStatus(QPainter& painter); + void DrawLocalRecordFlash(QPainter& painter); + + // 计算保持宽高比的实际显示区域 + QRect calculateAspectRatioRect() const; + +private: + QGLShaderProgram m_ShaderProgram; + QOpenGLBuffer m_vbo; + + GLuint m_textureUniformY; + GLuint m_textureUniformU; + GLuint m_textureUniformV; + + GLuint m_vertexInAttr; + GLuint m_textureInAttr; + + GLuint m_TextureIDY; + GLuint m_TextureIDU; + GLuint m_TextureIDV; + + unsigned char* m_pYData; + unsigned char* m_pUData; + unsigned char* m_pVData; + + int m_iPixelW; + int m_iPixelH; + + QMutex m_mutex; + + bool m_bIsMagnified; + + bool m_bLButtonPressed; + QPoint m_ptBegin; + QPoint m_ptEnd; + QPixmap m_pixmapBeginPos; + QPixmap m_pixmapEndPos; + QFont m_font; + QFont m_fontNoSignal; + + int m_nStopZoomTimerID; + + Widget* m_pMainWidget; + + int m_iCheckDragDistanceTimer; + bool m_bIsRendering; + + QPixmap m_pixmapLocalRecord; + int m_iLocalRecordingFlashTimer; + bool m_bFlashFlag; + + // 是否保持宽高比 + bool m_keepAspectRatio; + // 目标宽高比 (宽/高) + float m_targetAspectRatio; + // 实际显示区域 + QRect m_displayRect; +}; + +#endif // VLKVIDEOWIDGET_H diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjNetwork.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjNetwork.cpp new file mode 100644 index 0000000..677d261 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjNetwork.cpp @@ -0,0 +1,519 @@ +#include "VideoObjNetwork.h" +#include "VLKVideoWidget.h" +#include + +/** + * @brief 静态初始化标志 + * + * 用于标记FFmpeg库是否已经初始化,避免重复初始化 + */ +bool CVideoObjNetwork::m_bInit = false; + +/** + * @brief 有理数转浮点数工具函数 + * @param r AVRational有理数结构 + * @return 转换后的浮点数值 + * + * 将FFmpeg中的有理数格式转换为浮点数,用于时间基准转换 + */ +static double r2d(AVRational r) +{ + return r.den == 0 ? 0 : (double)r.num / (double)r.den; +} + +/** + * @brief CVideoObjNetwork构造函数 + * + * 初始化网络视频对象,设置所有成员变量为默认值 + */ +CVideoObjNetwork::CVideoObjNetwork() + : m_pAVFmtContext(NULL) // FFmpeg格式上下文 + , m_iVideoStreamIndex(-1) // 视频流索引 + , m_iAudioStreamIndex(-1) // 音频流索引 + , m_iWidth(0), m_iHeight(0) // 视频宽度和高度 + , m_pThread(NULL) // 解码线程指针 + , m_cbFunc(NULL) // 回调函数指针 + , m_lUserParam(0) // 用户参数 + , m_bExit(false) // 退出标志 + , m_pCodecContext(NULL) // 解码器上下文 + , m_pVideoWidget(NULL) // 视频显示组件 +{ +} + + +/** + * @brief CVideoObjNetwork析构函数 + * + * 清理资源,关闭所有连接和释放内存 + */ +CVideoObjNetwork::~CVideoObjNetwork() +{ + Close(); +} + +/** + * @brief FFmpeg日志回调函数 + * @param ptr 日志上下文指针 + * @param level 日志级别 + * @param fmt 格式化字符串 + * @param vl 可变参数列表 + * + * 将FFmpeg的日志输出重定向到Qt的调试输出 + */ +void ffmpeg_log_callback(void* ptr, int level, const char* fmt, va_list vl) +{ + // va_start(vl, fmt); + QString strResult = QString::vasprintf(fmt, vl); + // va_end(vl); + + qDebug() << strResult; +} + +/** + * @brief 打开网络视频流 + * @param strURL 视频流URL地址 + * @param pVideoWidget 视频显示组件指针 + * @return 成功返回true,失败返回false + * + * 初始化FFmpeg库,创建解码线程,开始接收和处理视频流 + */ +bool CVideoObjNetwork::Open(const std::string& strURL, VLKVideoWidget* pVideoWidget) +{ + if (!m_bInit) + { + // av_log_set_callback(ffmpeg_log_callback); + + // initialize ffmpeg + av_register_all(); + avformat_network_init(); + + m_bInit = true; + } + + Close(); + + m_strURL = strURL; + m_pVideoWidget = pVideoWidget; + + m_bExit = false; + m_pThread = new std::thread(ThreadFunc, this); + + return true; +} + +/** + * @brief 检查是否已打开视频流 + * @return 已打开返回true,否则返回false + * + * 通过检查解码线程是否存在来判断视频流是否已打开 + */ +bool CVideoObjNetwork::IsOpen() +{ + return m_pThread != NULL; +} + +/** + * @brief 设置视频数据回调函数 + * @param pVideoDataCB 回调函数指针 + * @param lUserParam 用户参数 + * + * 设置当接收到视频帧数据时的回调函数 + */ +void CVideoObjNetwork::SetDataCallback(VideoDataCallback pVideoDataCB, long lUserParam) +{ + m_cbFunc = pVideoDataCB; + m_lUserParam = lUserParam; +} + +/** + * @brief 关闭视频流连接 + * + * 停止解码线程,关闭解复用器和解码器,清理所有资源 + */ +void CVideoObjNetwork::Close() +{ + if (m_pThread != NULL) + { + m_bExit = true; + m_pThread->join(); + delete m_pThread; + m_pThread = NULL; + } + + CloseDemux(); + + CloseDecoder(); +} + +/** + * @brief 打开视频流解复用器 + * @param strURL 视频流URL地址 + * @return 成功返回true,失败返回false + * + * 使用FFmpeg打开网络视频流,获取视频和音频流信息, + * 设置中断回调函数以支持优雅退出 + */ +bool CVideoObjNetwork::OpenDemux(const std::string& strURL) +{ + AVDictionary *opts = NULL; + // av_dict_set(&opts, "rtsp_transport", "tcp", 0); + // av_dict_set(&opts, "max_delay", "500", 0); + // av_dict_set(&opts, "stimeout", "5000", 0); + + m_pAVFmtContext = avformat_alloc_context(); + AVIOInterruptCB cb = { interrupt_callback, this }; + m_pAVFmtContext->interrupt_callback = cb; + m_pAVFmtContext->flags |= AVFMT_FLAG_NONBLOCK; + AVInputFormat* inputformat = /*av_find_input_format("rtsp")*/NULL; + int re = avformat_open_input( + &m_pAVFmtContext, + strURL.c_str(), + inputformat, + &opts); + if (re != 0) + { + char buf[1024] = { 0 }; + av_strerror(re, buf, sizeof(buf) - 1); + qCritical("open url %s failed! %s\n", strURL.c_str(), buf); + + if (re != AVERROR_EXIT) + { + + } + + return false; + } + qDebug("open %s success !\n", strURL.c_str()); + + re = avformat_find_stream_info(m_pAVFmtContext, 0); + + // std::string stdstrURL = strURL.toStdString(); + // av_dump_format(m_pAVFmtContext, 0, stdstrURL.c_str(), 0); + + // find video stream + m_iVideoStreamIndex = av_find_best_stream(m_pAVFmtContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); + if (m_iVideoStreamIndex < 0) + { + qCritical("could not find video stream !!!!!!!!!\n"); + return false; + } + AVStream *as = m_pAVFmtContext->streams[m_iVideoStreamIndex]; + m_iWidth = as->codecpar->width; + m_iHeight = as->codecpar->height; + qDebug("video info codec_id: %d, pixel format: %d, width: %d, height: %d, video fps: %lf\n", + as->codecpar->codec_id, as->codecpar->format, + as->codecpar->width, as->codecpar->height, + r2d(as->avg_frame_rate)); + + // find audio stream + /*m_iAudioStreamIndex = av_find_best_stream(m_pAVFmtContext, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); + as = m_pAVFmtContext->streams[m_iAudioStreamIndex]; + m_iSampleRate = as->codecpar->sample_rate; + m_iChannels = as->codecpar->channels; + qDebug("audio info codec_id: %d, format: %d, sample_rate: %d, channels: %d, frame_size: %d", + as->codecpar->codec_id, as->codecpar->format, + as->codecpar->sample_rate, as->codecpar->channels, + as->codecpar->frame_size);*/ + + return true; +} + +/** + * @brief 关闭解复用器 + * + * 停止本地录制,关闭FFmpeg格式上下文,重置流索引 + */ +void CVideoObjNetwork::CloseDemux() +{ + StopLocalRecord(); + + if (m_pAVFmtContext != NULL) + { + avformat_close_input(&m_pAVFmtContext); + } + m_iVideoStreamIndex = -1; + m_iAudioStreamIndex = -1; +} + +/** + * @brief FFmpeg中断回调函数 + * @param para 用户参数指针(指向CVideoObjNetwork对象) + * @return 需要中断返回1,否则返回0 + * + * 用于FFmpeg网络操作的超时和中断控制, + * 当m_bExit为true时返回1表示需要中断操作 + */ +int CVideoObjNetwork::interrupt_callback(void* para) +{ + // qDebug() << __FUNCTION__; + CVideoObjNetwork* pThis = (CVideoObjNetwork*)para; + if (NULL == pThis) + { + return 0; + } + + if (pThis->m_bExit) + { + return 1; + } + + return 0; +} + +/** + * @brief 线程函数入口 + * @param pThis CVideoObjNetwork对象指针 + * + * 静态线程函数,调用对象的OnThreadFunc方法 + */ +void CVideoObjNetwork::ThreadFunc(CVideoObjNetwork* pThis) +{ + if (pThis != NULL) + { + pThis->OnThreadFunc(); + } +} + +/** + * @brief 主线程处理函数 + * + * 视频解码的主循环,负责: + * 1. 打开解复用器 + * 2. 打开解码器 + * 3. 读取数据包循环 + * 4. 出错时重连 + */ +void CVideoObjNetwork::OnThreadFunc() +{ + while (!m_bExit) + { + if (!OpenDemux(m_strURL)) + { + CloseDemux(); + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + continue; + } + + AVStream *as = m_pAVFmtContext->streams[m_iVideoStreamIndex]; + if (!OpenDecoder(as->codecpar)) + { + CloseDecoder(); + CloseDemux(); + continue; + } + + ReadPacketLoop(); + + CloseDecoder(); + CloseDemux(); + } +} + +/** + * @brief 数据包读取循环 + * + * 持续从视频流中读取数据包,进行时间戳转换, + * 并将视频数据包发送给解码器处理 + */ +void CVideoObjNetwork::ReadPacketLoop() +{ + while (!m_bExit) + { + AVPacket *pkt = av_packet_alloc(); + int re = av_read_frame(m_pAVFmtContext, pkt); + if (re != 0) + { + av_packet_free(&pkt); + char buf[1024] = { 0 }; + av_strerror(re, buf, sizeof(buf) - 1); + qCritical("av_read_frame error: %s\n", buf); + break; + } + + // convert pts timebase and dts timebase to millisecond timebase + pkt->pts = pkt->pts*(1000 * (r2d(m_pAVFmtContext->streams[pkt->stream_index]->time_base))); + pkt->dts = pkt->dts*(1000 * (r2d(m_pAVFmtContext->streams[pkt->stream_index]->time_base))); + if (pkt->pts < 0) + { + qCritical("bad pts %ld, throw this packet away\n", pkt->pts); + av_packet_free(&pkt); + continue; + } + + // send video package to decoder + if (pkt->stream_index == m_iVideoStreamIndex) + { + Send2Decode(pkt); + } + else + { + } + + av_packet_free(&pkt); + } +} + +/** + * @brief 写入本地录制文件 + * @param pkt 数据包指针 + * + * 将视频数据包写入本地文件进行录制(当前未实现) + */ +void CVideoObjNetwork::WriteLocalRecord(const AVPacket* pkt) +{ + Q_UNUSED(pkt); +} + +/** + * @brief 清空缓冲区 + * + * 清空FFmpeg格式上下文的缓冲区,丢弃所有待处理的数据 + */ +void CVideoObjNetwork::Clear() +{ + m_mutex.lock(); + if (m_pAVFmtContext != NULL) + { + avformat_flush(m_pAVFmtContext); + } + m_mutex.unlock(); +} + +/** + * @brief 开始本地录制 + * @return 成功返回true + * + * 开始将视频流录制到本地文件(当前未实现) + */ +bool CVideoObjNetwork::StartLocalRecord() +{ + return true; +} + +/** + * @brief 停止本地录制 + * + * 停止本地录制功能(当前未实现) + */ +void CVideoObjNetwork::StopLocalRecord() +{ + +} + +/** + * @brief 截图功能 + * + * 捕获当前视频帧并保存为图片(当前未实现) + */ +void CVideoObjNetwork::Capture() +{ + +} + +/** + * @brief 打开视频解码器 + * @param para 编解码器参数 + * @return 成功返回true,失败返回false + * + * 根据视频流的编解码器参数创建和配置解码器, + * 设置单线程解码以提高稳定性 + */ +bool CVideoObjNetwork::OpenDecoder(const AVCodecParameters *para) +{ + AVCodec *vcodec = avcodec_find_decoder(para->codec_id); + if (!vcodec) + { + qCritical("can't find the codec id = %d\n", para->codec_id); + return false; + } + + m_pCodecContext = avcodec_alloc_context3(vcodec); + avcodec_parameters_to_context(m_pCodecContext, para); + m_pCodecContext->thread_count = 1/*QThread::idealThreadCount()*/; + + int re = avcodec_open2(m_pCodecContext, 0, 0); + if (re != 0) + { + avcodec_free_context(&m_pCodecContext); + char buf[1024] = { 0 }; + av_strerror(re, buf, sizeof(buf) - 1); + qCritical("avcodec_open2 failed! : %s\n", buf); + return false; + } + + return true; +} + +/** + * @brief 关闭解码器 + * + * 关闭并释放解码器上下文,清理解码器资源 + */ +void CVideoObjNetwork::CloseDecoder() +{ + if (m_pCodecContext) + { + avcodec_close(m_pCodecContext); + avcodec_free_context(&m_pCodecContext); + } +} + +/** + * @brief 发送数据包到解码器 + * @param pkt 视频数据包指针 + * + * 将视频数据包发送给解码器进行解码, + * 然后循环接收解码后的视频帧并发送给显示组件 + */ +void CVideoObjNetwork::Send2Decode(const AVPacket *pkt) +{ + if (!pkt || pkt->size <= 0 || !pkt->data || !m_pCodecContext) + { + return; + } + + int re = avcodec_send_packet(m_pCodecContext, pkt); + if (re != 0) + { + char buf[1024] = { 0 }; + av_strerror(re, buf, sizeof(buf) - 1); + qCritical("avcodec_send_packet failed! : %s\n", buf); + } + + while (!m_bExit) + { + AVFrame *frame = av_frame_alloc(); + int re = avcodec_receive_frame(m_pCodecContext, frame); + if (re != 0) + { + av_frame_free(&frame); + break; + } + + // display video + Send2Display(frame); + + av_frame_free(&frame); + } +} + +/** + * @brief 发送视频帧到显示组件 + * @param frame 解码后的视频帧指针 + * + * 将解码后的视频帧发送给视频显示组件进行渲染显示 + */ +void CVideoObjNetwork::Send2Display(const AVFrame* frame) +{ + if (!frame || frame->data[0] == NULL || frame->linesize[0] == 0) + { + return; + } + + if (m_pVideoWidget != NULL) + { + m_pVideoWidget->Repaint(frame); + } +} + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjNetwork.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjNetwork.h new file mode 100644 index 0000000..5471a38 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjNetwork.h @@ -0,0 +1,318 @@ +#pragma once + +/** + * @brief 标准库包含文件 + */ +#include +#include +#include + +/** + * @brief FFmpeg库包含文件 + * + * 使用extern "C"包装以兼容C++编译器 + */ +extern "C" +{ +#include "libavcodec/avcodec.h" // 编解码器库 +#include "libavformat/avformat.h" // 格式处理库 +#include "libavutil/avutil.h" // 工具库 +#include "libswscale/swscale.h" // 图像缩放库 +#include "libavutil/imgutils.h" // 图像工具库 +}; + +/** + * @brief 视频数据回调函数类型定义 + * @param iEncode 编码格式 + * @param iWidth 视频宽度 + * @param iHeight 视频高度 + * @param pData 视频数据指针 + * @param lLen 数据长度 + * @param lPTS 显示时间戳 + * @param pUserParam 用户参数 + * + * 当接收到解码后的视频帧数据时,此回调函数会被调用 + */ +typedef void (*VideoDataCallback)(int iEncode, int iWidth, int iHeight, const char* pData, long lLen, long lPTS, void* pUserParam); + +/** + * @brief 前向声明 + * + * VLKVideoWidget类的前向声明,避免循环包含 + */ +class VLKVideoWidget; + +/** + * @brief 网络视频对象类 + * + * 负责处理网络视频流的接收、解码和显示 + * 使用FFmpeg库实现RTSP、HTTP等网络视频协议的支持 + */ +class CVideoObjNetwork +{ +public: + /** + * @brief 构造函数 + * + * 初始化网络视频对象 + */ + CVideoObjNetwork(); + + /** + * @brief 虚析构函数 + * + * 清理资源,确保正确释放FFmpeg相关资源 + */ + virtual ~CVideoObjNetwork(); + + /** + * @brief 打开网络视频流 + * @param strURL 视频流URL地址 + * @param pVideoWidget 视频显示组件指针 + * @return 成功返回true,失败返回false + * + * 连接到指定的网络视频流并开始解码 + */ + virtual bool Open(const std::string& strURL, VLKVideoWidget* pVideoWidget); + + /** + * @brief 检查是否已打开视频流 + * @return 已打开返回true,否则返回false + * + * 检查当前是否有活跃的视频流连接 + */ + virtual bool IsOpen(); + + /** + * @brief 设置视频数据回调函数 + * @param pVideoDataCB 回调函数指针 + * @param lUserParam 用户参数 + * + * 设置当接收到视频帧数据时的回调函数 + */ + void SetDataCallback(VideoDataCallback pVideoDataCB, long lUserParam); + + /** + * @brief 清空缓冲区 + * + * 清空所有待处理的视频数据 + */ + virtual void Clear(); + + /** + * @brief 关闭视频流连接 + * + * 停止解码线程,关闭所有连接 + */ + virtual void Close(); + + /** + * @brief 开始本地录制 + * @return 成功返回true + * + * 开始将视频流录制到本地文件 + */ + virtual bool StartLocalRecord(); + + /** + * @brief 停止本地录制 + * + * 停止本地录制功能 + */ + virtual void StopLocalRecord(); + + /** + * @brief 截图功能 + * + * 捕获当前视频帧并保存为图片 + */ + virtual void Capture(); + +private: + /** + * @brief 静态线程函数 + * @param pThis CVideoObjNetwork对象指针 + * + * 线程入口函数,调用对象的OnThreadFunc方法 + */ + static void ThreadFunc(CVideoObjNetwork* pThis); + + /** + * @brief 主线程处理函数 + * + * 视频解码的主循环,负责连接管理和错误重连 + */ + virtual void OnThreadFunc(); + + /** + * @brief 打开视频流解复用器 + * @param strURL 视频流URL地址 + * @return 成功返回true,失败返回false + * + * 使用FFmpeg打开网络视频流,获取流信息 + */ + bool OpenDemux(const std::string& strURL); + + /** + * @brief 关闭解复用器 + * + * 关闭FFmpeg格式上下文,清理解复用器资源 + */ + void CloseDemux(); + + /** + * @brief 写入本地录制文件 + * @param pkt 数据包指针 + * + * 将视频数据包写入本地文件进行录制 + */ + void WriteLocalRecord(const AVPacket* pkt); + + /** + * @brief FFmpeg中断回调函数 + * @param para 用户参数指针 + * @return 需要中断返回1,否则返回0 + * + * 用于FFmpeg网络操作的超时和中断控制 + */ + static int interrupt_callback(void* para); + + /** + * @brief 数据包读取循环 + * + * 持续从视频流中读取数据包并发送给解码器 + */ + void ReadPacketLoop(); + + /** + * @brief 打开视频解码器 + * @param para 编解码器参数 + * @return 成功返回true,失败返回false + * + * 根据视频流的编解码器参数创建和配置解码器 + */ + bool OpenDecoder(const AVCodecParameters *para); + + /** + * @brief 发送数据包到解码器 + * @param pkt 视频数据包指针 + * + * 将视频数据包发送给解码器进行解码 + */ + void Send2Decode(const AVPacket* pkt); + + /** + * @brief 发送视频帧到显示组件 + * @param frame 解码后的视频帧指针 + * + * 将解码后的视频帧发送给视频显示组件进行渲染 + */ + void Send2Display(const AVFrame* frame); + + /** + * @brief 关闭解码器 + * + * 关闭并释放解码器上下文 + */ + void CloseDecoder(); + +private: + /** + * @brief 静态初始化标志 + * + * 用于标记FFmpeg库是否已经初始化 + */ + static bool m_bInit; + + /** + * @brief 互斥锁 + * + * 用于保护共享资源的线程安全访问 + */ + std::mutex m_mutex; + + /** + * @brief 视频流URL地址 + * + * 存储当前连接的视频流地址 + */ + std::string m_strURL; + + /** + * @brief 视频显示组件指针 + * + * 指向用于显示视频的VLKVideoWidget组件 + */ + VLKVideoWidget* m_pVideoWidget; + + /** + * @brief FFmpeg格式上下文 + * + * 存储视频流的格式信息和元数据 + */ + AVFormatContext* m_pAVFmtContext; + + /** + * @brief 视频流索引 + * + * 在视频流数组中的索引位置 + */ + int m_iVideoStreamIndex; + + /** + * @brief 音频流索引 + * + * 在音频流数组中的索引位置 + */ + int m_iAudioStreamIndex; + + /** + * @brief 视频宽度 + * + * 视频帧的像素宽度 + */ + int m_iWidth; + + /** + * @brief 视频高度 + * + * 视频帧的像素高度 + */ + int m_iHeight; + + /** + * @brief 解码线程指针 + * + * 指向负责视频解码的工作线程 + */ + std::thread* m_pThread; + + /** + * @brief 退出标志 + * + * 用于通知线程安全退出的标志位 + */ + bool m_bExit; + + /** + * @brief 视频数据回调函数指针 + * + * 当接收到视频帧数据时调用的回调函数 + */ + VideoDataCallback m_cbFunc; + + /** + * @brief 用户参数 + * + * 传递给回调函数的用户自定义参数 + */ + long m_lUserParam; + + /** + * @brief FFmpeg解码器上下文 + * + * 存储解码器的配置和状态信息 + */ + AVCodecContext* m_pCodecContext; +}; + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjUSBCamera.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjUSBCamera.cpp new file mode 100644 index 0000000..1cd67bc --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjUSBCamera.cpp @@ -0,0 +1,294 @@ +#include "VideoObjUSBCamera.h" +#include "VLKVideoWidget.h" +#include "VideoObjNetwork.h" + +/** + * @brief CVideoObjUSBCamera构造函数 + * + * 初始化USB摄像头对象,创建摄像头捕获组件, + * 连接信号槽以处理摄像头帧数据 + */ +CVideoObjUSBCamera::CVideoObjUSBCamera() + : m_pWidget(NULL) // 视频显示组件指针 + , m_camera(NULL) // 摄像头对象指针 +{ + /** + * 创建摄像头捕获组件 + * 用于从摄像头获取视频帧数据 + */ + m_cameraCapture = new QtCameraCapture; + + /** + * 连接信号槽 + * 当摄像头有新帧可用时,调用grabImage函数处理 + */ + connect(m_cameraCapture, SIGNAL(frameAvailable(QImage)), this, SLOT(grabImage(QImage))); +} + + +/** + * @brief CVideoObjUSBCamera析构函数 + * + * 清理资源,关闭摄像头连接,释放摄像头捕获组件 + */ +CVideoObjUSBCamera::~CVideoObjUSBCamera() +{ + /** + * 关闭摄像头连接 + */ + Close(); + + /** + * 释放摄像头捕获组件 + */ + if (m_cameraCapture != NULL) + { + delete m_cameraCapture; + m_cameraCapture = NULL; + } +} + +/** + * @brief 打开USB摄像头 + * @param strCameraDescription 摄像头描述信息 + * @param pVideoWidget 视频显示组件指针 + * @return 成功返回true,失败返回false + * + * 根据摄像头描述信息查找并打开对应的USB摄像头, + * 设置摄像头参数并开始视频流 + */ +bool CVideoObjUSBCamera::Open(const QString& strCameraDescription, VLKVideoWidget* pVideoWidget) +{ + /** + * 先关闭之前的连接 + */ + Close(); + + /** + * 保存摄像头描述和显示组件指针 + */ + m_strCameraDescription = strCameraDescription; + m_pWidget = pVideoWidget; + + /** + * 根据描述信息查找摄像头设备 + * 遍历所有可用的摄像头设备 + */ + QByteArray byteCameraName; + QList listAvailableCamera = QCamera::availableDevices(); + for (QList::const_iterator it = listAvailableCamera.begin(); + it != listAvailableCamera.end(); ++it) + { + /** + * 比较摄像头描述信息,找到匹配的设备 + */ + if (0 == m_strCameraDescription.compare(QCamera::deviceDescription(*it))) + { + byteCameraName = *it; + break; + } + } + + /** + * 检查是否找到匹配的摄像头 + */ + if (byteCameraName.isEmpty()) + { + qCritical() << "could not find camera which description is " << m_strCameraDescription; + return false; + } + + /** + * 创建摄像头对象并开始视频流 + */ + m_camera = new QCamera(byteCameraName); + m_camera->setViewfinder(m_cameraCapture); + m_camera->start(); + + /** + * 输出摄像头能力信息用于调试 + */ + DumpCameraCapability(m_camera); + return true; +} + +/** + * @brief 检查摄像头是否已打开 + * @return 已打开返回true,否则返回false + * + * 通过检查摄像头对象是否存在来判断摄像头状态 + */ +bool CVideoObjUSBCamera::IsOpen() +{ + return m_camera != NULL; +} + +/** + * @brief 清空缓冲区 + * + * 清空摄像头相关的缓冲区数据(当前未实现) + */ +void CVideoObjUSBCamera::Clear() +{ + +} + +/** + * @brief 关闭摄像头连接 + * + * 停止本地录制,停止摄像头视频流,释放摄像头对象 + */ +void CVideoObjUSBCamera::Close() +{ + /** + * 停止本地录制功能 + */ + StopLocalRecord(); + + /** + * 停止摄像头并释放资源 + */ + if (m_camera != NULL) + { + m_camera->stop(); + delete m_camera; + m_camera = NULL; + } +} + +/** + * @brief 处理摄像头帧数据 + * @param image 摄像头捕获的QImage图像 + * + * 当摄像头有新帧可用时,此函数会被调用。 + * 函数会: + * 1. 修正图像方向(默认配置使图像上下颠倒) + * 2. 将RGB32格式转换为YUV420P格式 + * 3. 设置时间戳 + * 4. 发送给显示组件进行渲染 + */ +void CVideoObjUSBCamera::grabImage(QImage image) +{ + /** + * 静态时间戳计数器 + * 用于为每一帧分配递增的时间戳 + */ + static ulong ulPTS = 0; + // static QTime time = QTime::currentTime(); + // qDebug () << "=============== frame duration: " << time.msecsTo(QTime::currentTime()); + // time = QTime::currentTime(); +// qDebug() << " width: " << image.width() << ", height: " << image.height() << ", byteCount: " << image.byteCount() +// << ", depth: " << image.depth() << ", format: " << image.format(); + + /** + * 修正图像方向 + * 默认配置使图像上下颠倒,需要手动翻转 + * 通过交换上下半部分的像素数据来实现 + */ + int* pRGBData = (int*)image.bits(); + for (int i = 0; i < image.height()>>1; ++i) + { + for (int j = 0; j < image.width(); ++j) + { + /** + * 交换上下对称位置的像素值 + */ + int uVal = pRGBData[i * image.width() + j]; + pRGBData[i * image.width() + j] = pRGBData[(image.height() - 1 - i) * image.width() + j]; + pRGBData[(image.height() - 1 - i) * image.width() + j] = uVal; + } + } + + /** + * 格式转换和显示 + * 将RGB32格式转换为YUV420P格式,设置时间戳,发送给显示组件 + */ + AVFrame *frame = NULL; + m_Converter.RGB32toYUV420P(&image, &frame); + frame->pts = ulPTS; + ulPTS += 40; + if (m_pWidget != NULL && frame != NULL) + { + m_pWidget->Repaint(frame); + } +} + +/** + * @brief 输出摄像头能力信息 + * @param pCamera 摄像头对象指针 + * + * 调试函数,输出摄像头的支持分辨率、像素格式、 + * 当前设置等信息,用于开发和调试 + */ +void CVideoObjUSBCamera::DumpCameraCapability(const QCamera* pCamera) +{ + /** + * 检查摄像头对象是否有效 + */ + if (NULL == pCamera) + { + return; + } + + /** + * 输出支持的分辨率列表 + */ + QList listResolutions = pCamera->supportedViewfinderResolutions(); + qDebug() << "################ supported resulution: ################"; + for (QList::iterator it = listResolutions.begin(); it != listResolutions.end(); ++it) + { + qDebug() << " width: " << it->width() << ", height: " << it->height(); + } + + /** + * 输出支持的像素格式列表 + */ + QList listPixelFormat = pCamera->supportedViewfinderPixelFormats(); + qDebug() << "################ supported pixel format: ################"; + for (QList::iterator it = listPixelFormat.begin(); it != listPixelFormat.end(); ++it) + { + qDebug() << "pixel format: " << *it; + } + + /** + * 输出当前摄像头设置信息 + */ + QCameraViewfinderSettings settings = pCamera->viewfinderSettings(); + qDebug() << "################ current camera video width:" << settings.resolution().width() << ", height: " << settings.resolution().height(); + qDebug() << "################ current camera video pixelFormat:" << settings.pixelFormat() << ", minimum frame rate: " << settings.minimumFrameRate(); + // m_sFrameDuration = 1000 / m_CameraSettings.minimumFrameRate(); + // m_sFrameRate = 10; + // m_sFrameDuration = 100; +} + +/** + * @brief 开始本地录制 + * @return 成功返回true + * + * 开始将摄像头视频流录制到本地文件(当前未实现) + */ +bool CVideoObjUSBCamera::StartLocalRecord() +{ + return true; +} + +/** + * @brief 停止本地录制 + * + * 停止本地录制功能(当前未实现) + */ +void CVideoObjUSBCamera::StopLocalRecord() +{ +} + +/** + * @brief 截图功能 + * + * 捕获当前摄像头帧并保存为图片(当前未实现) + */ +void CVideoObjUSBCamera::Capture() +{ +} + + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjUSBCamera.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjUSBCamera.h new file mode 100644 index 0000000..1178e39 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/VideoObjUSBCamera.h @@ -0,0 +1,48 @@ +#pragma once +#include +#include +#include "QtCameraCapture.h" +#include "FFVideoFormatConvert.h" + +class VLKVideoWidget; + +/** + * @brief USB摄像头对象类 + * + * 该类负责USB摄像头的连接、视频流获取和格式转换。 + * 继承自QObject以支持信号槽机制,使用Qt的多媒体框架实现摄像头的连接、 + * 视频流处理和格式转换功能。主要功能包括: + * - 根据描述信息查找并打开USB摄像头 + * - 处理摄像头视频帧数据并进行格式转换 + * - 支持图像方向修正(上下翻转) + * - 提供本地录制和截图功能(待实现) + * - 输出摄像头能力信息用于调试 + */ +class CVideoObjUSBCamera : public QObject +{ + Q_OBJECT +public: + CVideoObjUSBCamera(); + virtual ~CVideoObjUSBCamera(); + + virtual bool Open(const QString& strCameraDescription, VLKVideoWidget* pVideoWidget); + virtual bool IsOpen(); + virtual void Clear(); + virtual void Close(); + virtual bool StartLocalRecord(); + virtual void StopLocalRecord(); + virtual void Capture(); +private slots: + void grabImage(QImage image); +private: + void DumpCameraCapability(const QCamera* pCamera); +private: + QString m_strCameraDescription; + VLKVideoWidget* m_pWidget; + + QtCameraCapture* m_cameraCapture; + QCamera* m_camera; + + CFFVideoFormatConvert m_Converter; +}; + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/circle_empty_48x48.png b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/circle_empty_48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..d396fc276cd6ebe43496bc99818b7e38a8871e8c GIT binary patch literal 1164 zcmV;71atd|P)A?mSNuWrJMXC*G+QuYplKworJM3hW zne4~xhCmbL5w%duGbeNz2folzH7s5h_vs1B*+W@2gP4fFwT0j~r1r+&W$ zTmsGkKLLLN{{V}`RO$zw01g1Vfd^7;XMxXv_ke5dd;<@wr)!?#lzLKqUhS)+k8SGH z>WAuIHGO@j4mJ`~qrrbuGvHbE1$9FcufI!uRy}1*xda#0eMJ-KbLo@6qmHQCn+UwN zY*mNV=~Vwer~^e2D5>w)1pltuQ$X#PbL!Dn z32ZjD$^>UEX4>S9_eE;Fi>r;dT8Brh?(r0!egQtOT$g|$pf{^>9)VqiJb*Z)J_QyE2(TWUqI zuZ4tGA1)Jb0z%Oq%&M42U@&!kj*tbN!W?iWb-$C0ShEO}D~$l|656KI_?gg10DB2} zz6@CeHl`ZfA%t0{ah)(i5Mpr4N|mw*Y^^i`n5MJSC&7PI4Nr*-^OZ%Ql=|;3A&J)# zU6ry7Sp;qpt_haDjZUJ6Sc?!3aDJsqSp?>Zy`M@a{e^~BANr{prW;fj^b%wdxJ~TE z0QV72s?&HB*i^ZmAY&coodXl8>jPwLV{Jk=kt|4Xg^YEWN8miwb+EfqI)xp;QTfpH@B0b#&jBV#9M1BR%|m~r4jR>eF5b41=I5pYLZ zqRqD%d7A{M3=i8bFR)SlC^g==x}z0CgOPNaNg0e`!~V5{z%i=^YF<6QTAO-0Evp}= zp31agz>6mFqLIZ*@RizI1Oe2CjHFYV#0kU07BOv()dWALK2}frMg|%*Om>0=!+_VF zgj%8OG3IhCpujWrUyHkaHT0EU5A zh!ZoxHNpm-AIaVPz)Qr*IY>zFdN4zru%krae>59Fs{|7C5~+`a zgqPk+_485}A;fMFPx}g?Z7z^^!q$nR2&7RWl`*rJtCgmxi_A{G*nsPC z4K7J@$8i(~u@4h<$v#26mM9e79N%3HliR1w&k zj1S-qY{#D!>tQYt{6XZwQ)yod@0D%nRfemD+lR0NPnQ@U5V0S|1%&}W0T#IdZSS01#Vg%NRY;TE}=TCm6 z2*(!P-W$ax5%x|>DFhI8+}7gf_t zM7mJ?p?=Y1q)qv3zYDkZFr3E?xGy(uV|V(#9)nc`nxey<5p|wnz(TiI;Z|In8y^vg zd6iE0EG4iaEtnBaCc`RRUDG&Rft9)OF`N+9(v^3;PBbsFI745>+B%p|kKAV|flSqg z#Hlk(i&CqLV>p=`Un;^or~61h{}{uwS4>hLo}JM7BT)He$BmGE1J}dPB~T*m=Jot zQmEQcZtgJd#S@}Q{gR%8cn0?fA<8g_$8kCK;y}?@Su1Xf%fv>}^(KU{WXbb8UK8q; zm0C;WPZ19Y9hekt{jcJJUZr(NTqaHlNqrI*7S^29@j%h|pa|FVY5a=rw!SC<;wJN~ zNTL_u%Q3| literal 0 HcmV?d00001 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/demo_for_qt.pro b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/demo_for_qt.pro new file mode 100644 index 0000000..b208a15 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/demo_for_qt.pro @@ -0,0 +1,142 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2020-06-25T15:33:07 +# +#------------------------------------------------- + +QT += core gui opengl multimedia multimediawidgets serialport network + +# 添加QtLocation支持 +QT += core gui opengl multimedia multimediawidgets serialport network positioning location + +# 添加Qt Quick支持 +QT += quickwidgets quick + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = demo_for_qt +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +# 使用workproject目录下的MAVLink库 +MAVLINK_INCLUDE_PATH = $$PWD/../workproject/c_library_v2 + +INCLUDEPATH += \ + $$PWD/../demo_for_windows/ffmpeg/include \ + $$PWD/../../inc \ + "$$PWD/../identification system/src" \ + $$PWD/../workproject/include \ + $$MAVLINK_INCLUDE_PATH \ + /usr/include # 添加系统头文件目录,确保能找到nlohmann/json.hpp + +# 添加红外识别系统相关配置 +CONFIG += c++17 + +# 添加OpenCV配置 +linux { + CONFIG += link_pkgconfig + PKGCONFIG += opencv4 +} + +# 添加其他识别系统需要的库 +linux { + LIBS += -lcurl -lssl -lcrypto + # nlohmann_json是header-only库,不需要链接库文件 +} + +win32{ +contains(QT_ARCH, x86_64){ + LIBS += -L$$PWD/../../lib/win64 -lViewLink \ + -L$$PWD/../demo_for_windows/ffmpeg/lib/win64 -lavformat -lavutil -lavcodec -lswresample -lswscale + DESTDIR = $$PWD/bin/win64 + + SDKDll = $$PWD/../../bin/win64/*.dll + SDKDll = $$replace(SDKDll, /, \\) + FfmpegDll = $$PWD/../demo_for_windows/ffmpeg/bin/win64/*.dll + FfmpegDll = $$replace(FfmpegDll, /, \\) + DllDst = $$replace(DESTDIR, /, \\) + + QMAKE_PRE_LINK += $$QMAKE_COPY $$SDKDll $$DllDst && \ + $$QMAKE_COPY $$FfmpegDll $$DllDst +}else{ + LIBS += -L$$PWD/../../lib/win32 -lViewLink \ + -L$$PWD/../demo_for_windows/ffmpeg/lib/win32 -lavformat -lavutil -lavcodec -lswresample -lswscale + DESTDIR =$$PWD/bin/win32 + + SDKDll = $$PWD/../../bin/win32/*.dll + SDKDll = $$replace(SDKDll, /, \\) + FfmpegDll = $$PWD/../demo_for_windows/ffmpeg/bin/win32/*.dll + FfmpegDll = $$replace(FfmpegDll, /, \\) + DllDst = $$replace(DESTDIR, /, \\) + + QMAKE_PRE_LINK += $$QMAKE_COPY $$SDKDll $$DllDst && \ + $$QMAKE_COPY $$FfmpegDll $$DllDst +} +} +linux{ +contains(QT_ARCH, x86_64){ + DESTDIR =$$PWD/bin/linux-x86_64 + LIBS += -L$$DESTDIR -lViewLink \ + -L/usr/local/lib -lavformat -lavcodec -lavutil -lswscale -lswresample + INCLUDEPATH += /usr/local/include + QMAKE_LFLAGS += -Wl,-rpath,/usr/local/lib + QMAKE_PRE_LINK += $$QMAKE_COPY $$PWD/../../bin/linux-x86_64/*.so $$DESTDIR +} +contains(QT_ARCH, aarch64){ + DESTDIR = $$PWD/bin/linux-aarch64 + LIBS += -L$$DESTDIR -lViewLink + QMAKE_PRE_LINK += $$QMAKE_COPY $$PWD/../../bin/linux-aarch64/*.so $$DESTDIR +} +} + +SOURCES += \ + main.cpp \ + widget.cpp \ + VideoObjNetwork.cpp \ + VLKVideoWidget.cpp \ + VideoObjUSBCamera.cpp \ + QtCameraCapture.cpp \ + FFVideoFormatConvert.cpp \ + # 添加红外识别系统源文件 + "../identification system/src/image_processor.cpp" \ + "../identification system/src/zhipu_api.cpp" \ + # 添加无人机控制和地图源文件 + MapWidget.cpp \ + # 添加workproject的MAVLink客户端源文件 + ../workproject/src/mavlink_client.cpp \ + # 添加图片预览对话框 + imagepreviewdialog.cpp + +HEADERS += \ + widget.h \ + VideoObjNetwork.h \ + ShaderSourceCode.h \ + VLKVideoWidget.h \ + VideoObjUSBCamera.h \ + QtCameraCapture.h \ + FFVideoFormatConvert.h \ + # 添加红外识别系统头文件 + "../identification system/src/image_processor.h" \ + "../identification system/src/zhipu_api.h" \ + # 添加无人机控制和地图头文件 + MapWidget.h \ + # 添加workproject的MAVLink客户端头文件 + ../workproject/include/mavlink_client.h \ + # 添加图片预览对话框 + imagepreviewdialog.h + +FORMS += \ + widget.ui + +RESOURCES += \ + res.qrc diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/demo_for_qt.pro.user b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/demo_for_qt.pro.user new file mode 100644 index 0000000..4fac211 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/demo_for_qt.pro.user @@ -0,0 +1,189 @@ + + + + + + EnvironmentId + {58c578ba-f805-46de-b4c0-7979ab18f2fe} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + true + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 0 + 80 + true + true + 1 + 0 + false + true + false + 2 + true + true + 0 + 8 + true + false + 1 + true + true + true + *.md, *.MD, Makefile + false + true + true + + + + ProjectExplorer.Project.PluginSettings + + + true + false + true + true + true + true + + false + + + 0 + true + + true + true + Builtin.DefaultTidyAndClazy + 11 + true + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 5.15.2 GCC 64bit + Desktop Qt 5.15.2 GCC 64bit + qt.qt5.5152.gcc_64_kit + 0 + 0 + 0 + + 0 + /home/zwt/下载/Linux_SDK/Linux_SDK/Linux_SDK/demo/demo_for_qt/build/Desktop_Qt_5_15_2_GCC_64bit-Debug + /home/zwt/下载/Linux_SDK/Linux_SDK/Linux_SDK/demo/demo_for_qt/build/Desktop_Qt_5_15_2_GCC_64bit-Debug + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Debug (imported) + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + 1 + + + 0 + 部署 + 部署 + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + 0 + true + + 2 + + false + -e cpu-cycles --call-graph dwarf,4096 -F 250 + demo_for_qt2 + Qt4ProjectManager.Qt4RunConfiguration: + /home/zwt/software/gold_eyes/src/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/demo_for_qt.pro + true + true + true + true + /home/zwt/software/gold_eyes/src/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/bin/linux-x86_64 + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/image/RecordingFlash_32x32.png b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/image/RecordingFlash_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..e3793c669c448c95d9b36ffd08b9d2fd3b5e01d4 GIT binary patch literal 1755 zcmZ{kdo&w(7RP_Yqh1kjt(IUC%2**@jYSc!dX((gqSXo$LXk*=P)$-BD%CAo^{Cf~ zX)z2*yV|s>C8M6jIPKC?4UJbUHL9prurdGbAA3LN-tRg0p6_4xp34pn@=;ShrVId3 z^Yg{xqzXSwn1ZyLEs)jf~#9 zmO)t-?q01H(>Gsk?n7zX1<@xxNLiX7(dt_-=rkB;R{Aw(P*Wa@!1)L?E~w%wchWVTLSHn zBw5g1IA;mSOQqpy$?qhVK+f7GdpT6Ihh7xS+5e)i(m&%?O3d5#0s7qjto=wz|3_yK zwU@2YFbT&~&n3t=;i-37EqB?u8-+_l2HLH)+2W>Uq z)Q74n=HAO1js4sSO|4FZK5kV2D>NKL)j+!JnfAIN<{0v2#R`&goGRr4Mue`r**e`s z<2*6i`rg&Qs-EorBgtwllo*=WXF)Iu0`J zX8nfwo|tIoaNiX&t#?SVBt@rsb>V`-EP^4&A*i6?IITwZyPtWo1Ha9QD2Ri-%N9D^ zq+w-#qkn8yM}6%{s!=mBVpL9bUR}!NcBD>9$7bfr#>F{Ws7NB7x-z`6G<*IreZW8w z*vzgCt(gC|dG-q;ODQC$Nf0VJb4lLGtWs-OiE}M(JN9LGRs9Nwm1_^+)d7peE_&d_ zRJ-7VYMui}M(s?zJc|i~l?2fko(#_e$hP;9cHa4_xYQQbw>I!eSo#jsX@JC5o*d6O z$vbPu!m;O{C%Xk+A`UrZk)`6CQzZx@NIaWv4SB1jyQcYjq*a9|f+ymC8`^Y;!U4=+ z!m{n?X@)O<5N~0pW1+OGzHYSO#-)k6Vh$Ogk-`Ep?^fq||9LgB0OnS*(YUE?bq;iP z+(5*-IER{=Xc{ihMeucVXc_0E=!FzC_P&cT(OhI|ef=;|*n*pN1BDA6(b{AahJ(G+USB zP+O?XHa9prVf$q0t-4cr7lDjTx=hm|nH&qh0i_a0dbgg*DGiMSxDzi*#4d8~I+AJE z0v#OFz_^w2n(H=TU2U?=jiq?gmVw*WT+iaK)jwtRx=bOI#or*zHgRpvi0!l~;8w@5 z!=`FF;ve`sO*HZMtBoa*fJ?8Sh_3h;zJUN#VgHc;h93W3M3+qlNf4V_GLoeQva_j` zyJzpSMxg%cfbTd+iZIi6|0e8oG{-kYdN}y^&b@>zoywgo9w|*vN3U>eRYA8)Nj~^A z$xF-*jYe#mf%g`lj{{nT=D29KsqNS%G|oWRD45dJguM!v-tY$DUh!@P+6=(yLU`q0KcVYP7-hXC4kjGx) z>Fdh=l2w9VkwIP1$pk2$=jq}Y5^;FzjlFrofdZ@#&WlC-abe3MM|K{%8UH<&c z8KcxGT<2yRE`Qhd`rOaAyY=m|Ej>22TAtr>v@_h>x%88|#?I$Ut@nQOf4@b>YJJwt zr*Z$6Ex*@QSiUbs`+oZIRkMtlAB&o<-kW}VlL=qt(Wrd|vAIX2S7bjcp1)dT@%*cT zhq6Djnw#W1bL4Jbtgip;cckR&)@f^=yw2mDU!greOupOBxpqruq~e?1MvS&GADuh? z?_JR~O<kI%@!YbY}Q|HruUp7%c-KU=D{`rxw(_%eirioa6P$gLtw=0wuLFq zH~vk3y-%QZ|L?#V;)nMBTi1W6N~tP?OTKT`Rh8qn`_HIXdHwczp|WK85?zyBXJa3F z1~ISUTKlFfEvZnV?TozMrK#JSf}$m+`b<9+abTZ)C-0w)?X5<6k7ARmD*B~UV-{D- zcwRjA)#%*A0xmYbf`vWzE$msD#S0>inY*Q$3oqc3w09Imr1Y_krf)w_#LelBz| z-SB5!efY_~4_bj?AH8l!K8f<0CT?q`so(UR(|GsR$!(XOE?fKmrPH+7_j8qY-;>J&K0h b{FKbJO57TLS$!7bP0l+XkKP26gE literal 0 HcmV?d00001 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/image/circle_selected_32x32.png b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/image/circle_selected_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..829bfd901ebf492b058a4a3ed960789459cb11d5 GIT binary patch literal 1144 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq@N1|*eVE!z&HSkfJR9T^xl_H+M9WCckkdj$D1 zFjT2AFf_COVhm6_Lx^vvO+5WEZEhz$Gm~|7;>kr{Cy(s~6UFx3+Mmwpr`h zIR58z*6ysIRa*Wg@>A{4vb1H!`_F%$^X$x=#{a+8+b{fdfQO;Fyh6!ADfBAu1B*u` zX0M;R**0vpwc%CRc;F4|hV)baPM0u0)BGW$FwH=UVGbLsP^S335~qr+$sfMxJe+?k zrFynay<^<}$cmD+)-zVwF{q2?uyst$KDN#$I-g;Z?y3XFR1X=iZ|T0&{(k0^H}x~E z1zyWJtk!+~^8e!#&*~a3RE9c~Ec@_9ufB1wjct6zlS$SBpG6#AbpC&EoY9H@YVRZU zR{lNmkso5@Jx*8Md(N^^TA}2Y`kzw=`yR(u0rk`!k!@M?KlkK|Fm8v{k~<&!#h7PY zlvGT2+7hDTV; z0V~(NGB;zi=vImU`1JB0j)e1}Cs#goH}^PsI(>Sz8cQ1U4fbv}fq6_5B4q!bUbbiY z>hy>mObQ=eKlYvFT~Mxdpv`jj?4QfGJYD%=p2~q^C*`K6Z`SgO<5V@}cQzIOh0CF7MV3?|>_t-TJEu-fkR z3(NVbUxgHI3eHury0n+s z}WHwGy9%m zkh0wVcWmbT%q@Am(l+`Xiy0Q~e&v>R-+pgR%E8O8pZ?wdyg{CcBlffGo(-!uL@`Dk zU(Lk!pS$E2_nb<_-|LH+qh%RR%3WOd$I$7)Pp*4R9l8SfQRiGk7yQb<@WrQMRp5>) zulg$W+eOT3TixU8oh#mPNPlLS!+emPVdL6c4Yna^b*vl2+kG33_Kd7Z7@Arc8(SHeXd4(<85q=SWbZ-Ikei>9nO2Eg17GQ7pn3)dPgg&ebxsLQ0J=B* AApigX literal 0 HcmV?d00001 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/imagepreviewdialog.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/imagepreviewdialog.cpp new file mode 100644 index 0000000..6bebe6d --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/imagepreviewdialog.cpp @@ -0,0 +1,71 @@ +#include "imagepreviewdialog.h" +#include +#include + +ImagePreviewDialog::ImagePreviewDialog(const QString &imagePath, QWidget *parent) + : QDialog(parent) + , m_imageLabel(new QLabel) + , m_scrollArea(new QScrollArea) + , m_closeButton(new QPushButton(tr("关闭"))) +{ + setupUi(); + loadImage(imagePath); + + // 设置窗口标题为图片名称 + QFileInfo fileInfo(imagePath); + setWindowTitle(tr("图片预览 - %1").arg(fileInfo.fileName())); + + // 调整窗口大小 + resize(800, 600); +} + +ImagePreviewDialog::~ImagePreviewDialog() +{ +} + +void ImagePreviewDialog::setupUi() +{ + // 设置滚动区域 + m_scrollArea->setWidgetResizable(true); + m_scrollArea->setWidget(m_imageLabel); + + // 设置图像标签 + m_imageLabel->setAlignment(Qt::AlignCenter); + m_imageLabel->setScaledContents(false); + + // 设置关闭按钮 + connect(m_closeButton, &QPushButton::clicked, this, &QDialog::accept); + + // 创建布局 + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(m_scrollArea); + mainLayout->addWidget(m_closeButton); + + setLayout(mainLayout); +} + +void ImagePreviewDialog::loadImage(const QString &imagePath) +{ + QPixmap pixmap(imagePath); + if (pixmap.isNull()) { + m_imageLabel->setText(tr("无法加载图片: %1").arg(imagePath)); + return; + } + + // 计算适合的显示大小 + QSize screenSize = parentWidget() ? parentWidget()->size() : QSize(800, 600); + QSize scaledSize = pixmap.size(); + + // 如果图片太大,等比例缩小 + if (scaledSize.width() > screenSize.width() * 0.8 || + scaledSize.height() > screenSize.height() * 0.8) { + scaledSize.scale(screenSize.width() * 0.8, screenSize.height() * 0.8, Qt::KeepAspectRatio); + } + + // 设置图片并调整大小 + m_imageLabel->setPixmap(pixmap.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + // 显示图片信息 + QString infoText = tr("图片尺寸: %1 x %2").arg(pixmap.width()).arg(pixmap.height()); + m_closeButton->setText(tr("关闭 (%1)").arg(infoText)); +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/imagepreviewdialog.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/imagepreviewdialog.h new file mode 100644 index 0000000..9719bc7 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/imagepreviewdialog.h @@ -0,0 +1,38 @@ +// 图像预览对话框头文件 +// 防止头文件重复包含的宏定义 +#ifndef IMAGEPREVIEWDIALOG_H +#define IMAGEPREVIEWDIALOG_H + +// 包含Qt框架相关头文件 +#include // Qt对话框基类 +#include // Qt标签控件 +#include // Qt垂直布局管理器 +#include // Qt按钮控件 +#include // Qt滚动区域控件 + +// 图像预览对话框类 +// 继承自QDialog,用于显示图像预览功能 +class ImagePreviewDialog : public QDialog +{ + Q_OBJECT // Qt元对象宏,支持信号槽机制 + +public: + // 构造函数:创建图像预览对话框 + // @param imagePath: 要预览的图像文件路径 + // @param parent: 父窗口指针,默认为nullptr + explicit ImagePreviewDialog(const QString &imagePath, QWidget *parent = nullptr); + // 析构函数:清理资源 + ~ImagePreviewDialog(); + +private: + // 私有成员变量 + QLabel *m_imageLabel; // 图像显示标签控件 + QScrollArea *m_scrollArea; // 滚动区域控件,支持图像缩放和滚动 + QPushButton *m_closeButton; // 关闭按钮控件 + + // 私有成员函数 + void setupUi(); // 设置用户界面布局 + void loadImage(const QString &imagePath); // 加载并显示图像 +}; + +#endif // IMAGEPREVIEWDIALOG_H // 头文件保护宏结束 \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/main.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/main.cpp new file mode 100644 index 0000000..20832af --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/main.cpp @@ -0,0 +1,39 @@ +// 包含主窗口类头文件 +#include "widget.h" +// 包含Qt应用程序类 +#include +// 包含Qt调试输出类 +#include + +// Qt应用程序主函数 +// @param argc: 命令行参数个数 +// @param argv: 命令行参数数组 +int main(int argc, char *argv[]) +{ + // 创建Qt应用程序对象,传入命令行参数 + QApplication a(argc, argv); + + // 打印ViewLink SDK版本信息 + qDebug() << "ViewLink SDK Version: " << GetSDKVersion(); + + // 初始化ViewLink SDK + VLK_Init(); + + + // 创建主窗口对象 + Widget w; + // 显示主窗口 + w.show(); + + // 启动Qt应用程序事件循环,等待用户交互 + int ret = a.exec(); + + // 断开所有ViewLink连接 + VLK_Disconnect(); + + // 反初始化ViewLink SDK,释放资源 + VLK_UnInit(); + + // 返回应用程序退出码 + return ret; +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/qml/Map.qml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/qml/Map.qml new file mode 100644 index 0000000..1e4a25f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/qml/Map.qml @@ -0,0 +1,330 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtLocation 5.15 +import QtPositioning 5.15 + +Item { + id: root + anchors.fill: parent + + // 创建属性存储当前地图类型 + property string currentMapType: "normal" // "normal" 或 "satellite" + + // 创建存储目标标记的列表 + property var targetMarkers: [] + + // 创建目标标记的方法,供C++调用 + function createTargetMarker(coordinate, distance, uncertainty, targetId) { + // 创建标记组件 + var component = Qt.createComponent("TargetMarker.qml"); + if (component.status === Component.Ready) { + var marker = component.createObject(map, { + "coordinate": coordinate, + "distance": distance, + "uncertainty": uncertainty, + "targetId": targetId + }); + + if (marker) { + targetMarkers.push(marker); + return marker; + } else { + console.error("创建目标标记对象失败"); + return null; + } + } else { + console.error("加载TargetMarker.qml组件失败:", component.errorString()); + + // 如果无法加载组件,使用简单圆形作为标记 + var circleMarker = simpleTargetComponent.createObject(map, { + "coordinate": coordinate, + "distance": distance, + "uncertainty": uncertainty, + "targetId": targetId + }); + + if (circleMarker) { + targetMarkers.push(circleMarker); + return circleMarker; + } + + return null; + } + } + + // 清除所有目标标记 + function clearTargetMarkers() { + for (var i = 0; i < targetMarkers.length; i++) { + if (targetMarkers[i]) { + targetMarkers[i].destroy(); + } + } + targetMarkers = []; + } + + // 简单目标标记组件定义 + Component { + id: simpleTargetComponent + + MapQuickItem { + property double distance: 0 + property double uncertainty: 20 + property int targetId: 0 + + anchorPoint.x: sourceItem.width / 2 + anchorPoint.y: sourceItem.height / 2 + + sourceItem: Item { + width: uncertaintyCircle.width + height: uncertaintyCircle.height + + Rectangle { + id: uncertaintyCircle + width: uncertainty * 2 + height: uncertainty * 2 + radius: width / 2 + color: "#80FF0000" // 半透明红色 + border.width: 1 + border.color: "red" + } + + Rectangle { + id: targetCircle + width: 16 + height: 16 + radius: 8 + color: "red" + border.width: 2 + border.color: "white" + anchors.centerIn: parent + } + + Text { + text: "目标 #" + targetId + "\n" + Math.round(distance) + "m" + color: "white" + font.bold: true + style: Text.Outline + styleColor: "black" + anchors.centerIn: parent + anchors.verticalCenterOffset: -30 + horizontalAlignment: Text.AlignHCenter + } + } + } + } + + // 使用单一地图提供商,简化设计以避免错误 + Plugin { + id: mapPlugin + // 使用OSM地图提供商(通常最可靠) + name: "osm" + } + + // 如果需要尝试其他地图提供商,可以手动修改上面的name属性 + // 常见选项: "osm", "esri", "here", "mapbox"等 + + // 地图视图 + Map { + id: map + objectName: "map" + anchors.fill: parent + plugin: mapPlugin + center: uavPosition + zoomLevel: 14 + + // 记录地图类型信息 + Component.onCompleted: { + console.log("地图提供商:", mapPlugin.name); + console.log("支持的地图类型数量:", supportedMapTypes.length); + + // 显示所有可用的地图类型 + for (var i = 0; i < supportedMapTypes.length; i++) { + console.log("地图类型", i, ":", supportedMapTypes[i].name, "描述:", supportedMapTypes[i].description); + } + + // 如果地图类型存在,设置初始地图类型 + if (supportedMapTypes.length > 0) { + activeMapType = supportedMapTypes[0]; // 默认使用第一种类型 + console.log("初始地图类型设置为:", activeMapType.name); + } + } + + // 地图控制选项 + gesture.enabled: true + gesture.acceptedGestures: MapGestureArea.PanGesture | MapGestureArea.PinchGesture | MapGestureArea.FlickGesture + + // 无人机位置标记 + MapQuickItem { + id: uavMarker + objectName: "uavMarker" + coordinate: uavPosition + sourceItem: Rectangle { + width: 20 + height: 20 + color: "red" + border.width: 2 + border.color: "white" + radius: 10 + } + anchorPoint.x: 10 + anchorPoint.y: 10 + } + + // 轨迹路径 + MapPolyline { + id: trajectory + line.width: 3 + line.color: "blue" + path: uavTrajectory + } + + // 自定义指南针组件 + Rectangle { + id: compass + anchors.right: parent.right + anchors.top: parent.top + anchors.margins: 10 + width: 40 + height: 40 + color: "white" + opacity: 0.8 + radius: 20 + + Text { + anchors.centerIn: parent + text: "N" + font.bold: true + font.pixelSize: 16 + } + } + + // 自定义比例尺 + Rectangle { + id: scaleBar + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: 10 + width: 100 + height: 20 + color: "white" + opacity: 0.8 + radius: 5 + + Row { + anchors.centerIn: parent + spacing: 2 + + Rectangle { + width: 50 + height: 5 + color: "black" + } + + Rectangle { + width: 50 + height: 5 + color: "black" + } + } + + Text { + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: "100m" + font.pixelSize: 10 + } + } + } + + // 缩放控制 + Rectangle { + id: zoomControl + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + width: 30 + height: 60 + color: "white" + opacity: 0.8 + radius: 5 + + Column { + anchors.fill: parent + + Button { + width: 30 + height: 30 + text: "+" + onClicked: map.zoomLevel += 1 + } + + Button { + width: 30 + height: 30 + text: "-" + onClicked: map.zoomLevel -= 1 + } + } + } + + // 居中按钮 + Rectangle { + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 10 + width: 30 + height: 30 + color: "white" + opacity: 0.8 + radius: 5 + + Button { + anchors.fill: parent + text: "⌖" + onClicked: map.center = uavPosition + } + } + + // 添加地图类型切换按钮 + Rectangle { + id: mapTypeControl + anchors.left: parent.left + anchors.top: parent.top + anchors.margins: 10 + width: 120 + height: 30 + color: "white" + opacity: 0.8 + radius: 5 + + // 保存地图类型索引 + property int currentMapTypeIndex: 0 + + Button { + anchors.fill: parent + text: "切换地图类型" + + onClicked: { + // 检查是否有多种地图类型 + if (map.supportedMapTypes.length <= 1) { + console.log("只有一种地图类型可用,无法切换"); + return; + } + + // 循环切换地图类型 + parent.currentMapTypeIndex = (parent.currentMapTypeIndex + 1) % map.supportedMapTypes.length; + map.activeMapType = map.supportedMapTypes[parent.currentMapTypeIndex]; + + // 更新当前地图类型状态 + if (map.activeMapType.name.toLowerCase().indexOf("satellite") >= 0 || + map.activeMapType.name.toLowerCase().indexOf("aerial") >= 0 || + map.activeMapType.description.toLowerCase().indexOf("satellite") >= 0) { + currentMapType = "satellite"; + } else { + currentMapType = "normal"; + } + + console.log("已切换到地图类型:", map.activeMapType.name, "index:", parent.currentMapTypeIndex); + } + } + } +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/qml/TargetMarker.qml b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/qml/TargetMarker.qml new file mode 100644 index 0000000..42be40d --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/qml/TargetMarker.qml @@ -0,0 +1,94 @@ +import QtQuick 2.15 +import QtLocation 5.15 +import QtPositioning 5.15 + +MapQuickItem { + id: targetMarker + + // 属性定义 + property double distance: 0 + property double uncertainty: 20 + property int targetId: 0 + + // 设置锚点为中心 + anchorPoint.x: sourceItem.width / 2 + anchorPoint.y: sourceItem.height / 2 + + // 标记的图形表示 + sourceItem: Item { + width: uncertaintyCircle.width + height: uncertaintyCircle.height + + // 不确定性圆圈(半透明红色区域) + Rectangle { + id: uncertaintyCircle + width: uncertainty * 2 // 直径是不确定性的2倍 + height: uncertainty * 2 + radius: width / 2 + color: "#33FF0000" // 半透明红色 + border.width: 1 + border.color: "red" + + // 添加脉动动画,使目标更明显 + SequentialAnimation on opacity { + running: true + loops: Animation.Infinite + NumberAnimation { from: 0.2; to: 0.5; duration: 1000; easing.type: Easing.InOutQuad } + NumberAnimation { from: 0.5; to: 0.2; duration: 1000; easing.type: Easing.InOutQuad } + } + } + + // 目标中心点(红色点) + Rectangle { + id: targetPoint + width: 10 + height: 10 + radius: 5 + color: "red" + border.width: 1 + border.color: "white" + anchors.centerIn: parent + } + + // 十字准线 + Rectangle { + id: horizontalLine + width: 20 + height: 2 + color: "red" + anchors.centerIn: parent + } + + Rectangle { + id: verticalLine + width: 2 + height: 20 + color: "red" + anchors.centerIn: parent + } + + // 信息文本(显示目标编号和距离) + Text { + id: infoText + text: "目标 #" + targetId + "\n" + Math.round(distance) + "米" + color: "white" + font.bold: true + font.pixelSize: 12 + style: Text.Outline + styleColor: "black" + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: -30 + horizontalAlignment: Text.AlignHCenter + + // 添加背景矩形使文字更清晰 + Rectangle { + z: -1 + anchors.fill: parent + anchors.margins: -4 + color: "#80000000" // 半透明黑色 + radius: 4 + } + } + } +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/res.qrc b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/res.qrc new file mode 100644 index 0000000..10392bb --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/res.qrc @@ -0,0 +1,9 @@ + + + image/circle_empty_48x48.png + image/circle_selected_32x32.png + image/RecordingFlash_32x32.png + qml/Map.qml + qml/TargetMarker.qml + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.cpp new file mode 100644 index 0000000..9101ca1 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.cpp @@ -0,0 +1,2009 @@ +#include "widget.h" +#include "ui_widget.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "imagepreviewdialog.h" + +Widget::Widget(QWidget *parent) : + QWidget(parent), + ui(new Ui::Widget) +{ + ui->setupUi(this); + qRegisterMetaType("VLK_DEV_MODEL"); + qRegisterMetaType("VLK_DEV_CONFIG"); + qRegisterMetaType("VLK_DEV_TELEMETRY"); + + connect(this, SIGNAL(SignalConnectionStatus(int, const QString&)), this, SLOT(onSlotConnectionStatus(int, const QString&))); + connect(this, SIGNAL(SignalDeviceModel(VLK_DEV_MODEL)), this, SLOT(onSlotDeviceModel(VLK_DEV_MODEL))); + connect(this, SIGNAL(SignalDeviceConfig(VLK_DEV_CONFIG)), this, SLOT(onSlotDeviceConfig(VLK_DEV_CONFIG))); + connect(this, SIGNAL(SignalDeviceTelemetry(VLK_DEV_TELEMETRY)), this, SLOT(onSlotDeviceTelemetry(VLK_DEV_TELEMETRY))); + + InitUI(); + + VLK_RegisterDevStatusCB(VLK_DevStatusCallback, this); + + // 设置视频显示控件保持1920:1080的比例 + ui->widgetMainVideo->setKeepAspectRatio(true); + ui->widgetMainVideo->setStandardSize(1920, 1080); + ui->widgetMainVideo->SetMainDialog(this); + + // 初始化红外识别相关成员变量 + m_pImageProcessor = new ImageProcessor(); + // 使用智谱AI API的密钥 + m_pZhipuAPI = new ZhipuAPI("3bbb7dee27ac40e38a9b2026065dfa09.oLgHTXxNnz4FM392", 60); + m_confidenceThreshold = 0.7f; // 默认置信度 + m_lastCapturedImagePath = ""; + + // 初始化目标距离估计相关成员 + m_lastLaserDistance = 0.0f; + m_distanceEstimationEnabled = true; + m_labelDistanceValue = nullptr; + + // 初始化地图目标标记相关成员 + m_targetsOnMap = false; + m_lastGimbalYaw = 0.0; + m_lastGimbalPitch = 0.0; + m_btnShowTargetsOnMap = nullptr; + + // 设置检测数据日志文件 + QString logDir = "./detection_logs"; + QDir dir(logDir); + if (!dir.exists()) { + dir.mkpath("."); + } + m_detectionLogFile = QString("%1/detection_log_%2.csv") + .arg(logDir) + .arg(QDateTime::currentDateTime().toString("yyyyMMdd")); + + // 初始化MAVLink客户端和无人机状态 + m_mavlinkClient = new MAVLinkClient(); + m_isUAVArmed = false; + m_isMAVConnected = false; + + // 设置MAVLink回调函数 + m_mavlinkClient->setHeartbeatCallback([this](const mavlink_heartbeat_t& heartbeat) { + this->handleHeartbeat(heartbeat); + }); + + m_mavlinkClient->setSystemStatusCallback([this](const mavlink_sys_status_t& status) { + this->handleSystemStatus(status); + }); + + m_mavlinkClient->setAttitudeCallback([this](const mavlink_attitude_t& attitude) { + this->handleAttitude(attitude); + }); + + m_mavlinkClient->setPositionCallback([this](const mavlink_global_position_int_t& position) { + this->handlePosition(position); + }); + + // 添加GPS回调函数 + m_mavlinkClient->setGPSCallback([this](const mavlink_gps_raw_int_t& gps) { + this->handleGPS(gps); + }); + + // 创建地图控件 + m_mapWidget = new MapWidget(); + ui->layoutMap->addWidget(m_mapWidget); + + // 界面默认同时显示摄像头控制和无人机控制 + + // 初始化声源定位相关成员 + m_soundNetworkManager = new QNetworkAccessManager(this); + m_soundDataTimer = new QTimer(this); + connect(m_soundDataTimer, &QTimer::timeout, this, &Widget::fetchSoundLocatorData); + m_isSoundLocatorRunning = false; + m_soundLocatorIP = "127.0.0.1"; + m_soundLocatorPort = 5000; + + // 初始化声源定位可视化组件 + m_soundScene = nullptr; + m_soundView = nullptr; + m_soundSourceItem = nullptr; + m_soundDirectionLine = nullptr; + m_soundInfoText = nullptr; + m_soundDetectorItem = nullptr; + m_soundX = 0.0; + m_soundY = 0.0; + m_soundStrength = 0.0; + m_soundAngle = 0.0; + initSoundVisualization(); + + // 初始化UI状态 + updateUIState(); + + // 初始化GPS状态标签 + if (m_labelGPSValue) { + m_labelGPSValue->setText("未连接"); + } + if (m_labelSatellitesValue) { + m_labelSatellitesValue->setText("0"); + } + + // 添加目标距离显示标签 + QGridLayout *identifyLayout = qobject_cast(ui->groupBoxIdentify->layout()); + if (identifyLayout) { + // 找到btnIdentifyTarget的位置 + int row = -1, col = -1, rowSpan = -1, colSpan = -1; + identifyLayout->getItemPosition(identifyLayout->indexOf(ui->btnIdentifyTarget), &row, &col, &rowSpan, &colSpan); + + if (row >= 0) { + // 添加估计距离显示 + QHBoxLayout *distanceLayout = new QHBoxLayout(); + QLabel *labelDistance = new QLabel(tr("估计距离:"), ui->groupBoxIdentify); + labelDistance->setObjectName("labelDistance"); + + QLabel *labelDistanceValue = new QLabel(tr("未知"), ui->groupBoxIdentify); + labelDistanceValue->setObjectName("labelDistanceValue"); + m_labelDistanceValue = labelDistanceValue; + + distanceLayout->addWidget(labelDistance); + distanceLayout->addWidget(labelDistanceValue); + distanceLayout->addStretch(); + + // 在btnClearIdentification的下一行添加距离显示 + int clearBtnRow = -1; + identifyLayout->getItemPosition(identifyLayout->indexOf(ui->btnClearIdentification), &clearBtnRow, &col, &rowSpan, &colSpan); + if (clearBtnRow >= 0) { + identifyLayout->addLayout(distanceLayout, clearBtnRow + 1, 0, 1, 2); + + // 添加显示目标在地图上的按钮 + m_btnShowTargetsOnMap = new QPushButton(tr("在地图上显示目标"), ui->groupBoxIdentify); + m_btnShowTargetsOnMap->setObjectName("btnShowTargetsOnMap"); + m_btnShowTargetsOnMap->setEnabled(false); // 初始时禁用 + connect(m_btnShowTargetsOnMap, &QPushButton::clicked, this, &Widget::on_btnShowTargetsOnMap_clicked); + + identifyLayout->addWidget(m_btnShowTargetsOnMap, clearBtnRow + 2, 0, 1, 2); + } else { + identifyLayout->addLayout(distanceLayout, row + 1, 0, 1, 2); + } + } + } + + // 初始化TCP移动控制相关成员 + m_moveControlSocket = -1; + m_moveControlConnected = false; + m_moveControlIP = "192.168.1.100"; // 默认IP,将被用户设置覆盖 + m_moveControlPort = 1234; // 默认端口,将被用户设置覆盖 + m_lastSoundProcessed = true; // 初始化为true,表示没有未处理的声音 +} + +Widget::~Widget() +{ + m_VideoObjNetwork.Close(); + m_VideoObjUSBCamera.Close(); + + // 释放红外识别相关资源 + if (m_pImageProcessor) + { + delete m_pImageProcessor; + m_pImageProcessor = nullptr; + } + + if (m_pZhipuAPI) + { + delete m_pZhipuAPI; + m_pZhipuAPI = nullptr; + } + + // 断开MAVLink连接并释放资源 + if (m_mavlinkClient) + { + if (m_mavlinkClient->isConnected()) + { + m_mavlinkClient->disconnect(); + } + delete m_mavlinkClient; + m_mavlinkClient = nullptr; + } + + // 停止声源定位服务并释放资源 + if (m_soundDataTimer) + { + m_soundDataTimer->stop(); + } + + // 清理场景和视图 + if (m_soundScene) { + m_soundScene->clear(); + delete m_soundScene; + m_soundScene = nullptr; + } + + // 关闭TCP连接 + disconnectFromMoveControlTCP(); + + delete ui; +} + +void Widget::InitUI() +{ + // initialize serial port list + ui->cmbSerialPort->clear(); + QList listSerialPortInfo = QSerialPortInfo::availablePorts(); + foreach(const QSerialPortInfo &port_info, listSerialPortInfo) + { + ui->cmbSerialPort->addItem(port_info.portName()); + } + + ui->lineEditBaudrate->setText("115200"); + + // initialize tcp gimbal list + ui->cmbIPAddr->addItem("192.168.2.119"); + ui->lineEditPort->setText("2000"); + + // initialize network url list + ui->cmbNetworkVideoURL->addItem("rtsp://192.168.2.119:554"); + + // initialize USB Camera list + QList listAvailableCamera = QCamera::availableDevices(); + foreach (const QByteArray &camera, listAvailableCamera) + { + ui->cmbUSBCamera->addItem(QCamera::deviceDescription(camera)); + } + + // initialize image sensor combobox items + ui->cmbImageSensor->addItem(tr("Visible1"), VLK_IMAGE_TYPE_VISIBLE1); + ui->cmbImageSensor->addItem(tr("IR"), VLK_IMAGE_TYPE_IR1); + // ui->cmbImageSensor->addItem(tr("Visible2"), VLK_IMAGE_TYPE_VISIBLE2); + // ui->cmbImageSensor->addItem(tr("IR2"), VLK_IMAGE_TYPE_IR2); + // ui->cmbImageSensor->addItem(tr("Fusion"), VLK_IMAGE_TYPE_FUSION); + + // initialize IR color combobox items + ui->cmbIRColor->addItem(tr("White hot"), VLK_IR_COLOR_WHITEHOT); + ui->cmbIRColor->addItem(tr("Black hot"), VLK_IR_COLOR_BLACKHOT); + ui->cmbIRColor->addItem(tr("Pseudo hot"), VLK_IR_COLOR_PSEUDOHOT); + + // 添加GPS状态UI元素到飞行状态信息组 + QGridLayout *gridLayout = qobject_cast(ui->groupBoxStatus->layout()); + if (gridLayout) { + // 当前行数 + int row = gridLayout->rowCount(); + + // 添加GPS状态标签 + QLabel *labelGPS = new QLabel(tr("GPS状态:"), ui->groupBoxStatus); + labelGPS->setObjectName("labelGPS"); + gridLayout->addWidget(labelGPS, row, 0); + + QLabel *labelGPSValue = new QLabel(tr("未连接"), ui->groupBoxStatus); + labelGPSValue->setObjectName("labelGPSValue"); + gridLayout->addWidget(labelGPSValue, row, 1); + m_labelGPSValue = labelGPSValue; + + // 添加卫星数量标签 + QLabel *labelSatellites = new QLabel(tr("卫星数量:"), ui->groupBoxStatus); + labelSatellites->setObjectName("labelSatellites"); + gridLayout->addWidget(labelSatellites, row, 2); + + QLabel *labelSatellitesValue = new QLabel("0", ui->groupBoxStatus); + labelSatellitesValue->setObjectName("labelSatellitesValue"); + gridLayout->addWidget(labelSatellitesValue, row, 3); + m_labelSatellitesValue = labelSatellitesValue; + + // 添加HDOP标签 (增加一行) + row++; + QLabel *labelHDOP = new QLabel(tr("水平精度:"), ui->groupBoxStatus); + labelHDOP->setObjectName("labelHDOP"); + gridLayout->addWidget(labelHDOP, row, 0); + + QLabel *labelHDOPValue = new QLabel(tr("未知"), ui->groupBoxStatus); + labelHDOPValue->setObjectName("labelHDOPValue"); + gridLayout->addWidget(labelHDOPValue, row, 1); + m_labelHDOPValue = labelHDOPValue; + + // 添加VDOP标签 + QLabel *labelVDOP = new QLabel(tr("垂直精度:"), ui->groupBoxStatus); + labelVDOP->setObjectName("labelVDOP"); + gridLayout->addWidget(labelVDOP, row, 2); + + QLabel *labelVDOPValue = new QLabel(tr("未知"), ui->groupBoxStatus); + labelVDOPValue->setObjectName("labelVDOPValue"); + gridLayout->addWidget(labelVDOPValue, row, 3); + m_labelVDOPValue = labelVDOPValue; + } +} + +int Widget::VLK_ConnStatusCallback(int iConnStatus, const char* szMessage, int iMsgLen, void* pUserParam) +{ + Widget* pThis = (Widget*)pUserParam; + if (NULL == pThis) + { + return 0; + } + + QString strMessage; + if (szMessage != NULL && iMsgLen > 0 ) + { + strMessage = QString::fromUtf8(szMessage); + } + + emit pThis->SignalConnectionStatus(iConnStatus, strMessage); + + return 0; +} + +int Widget::VLK_DevStatusCallback(int iType, const char* szBuffer, int iBufLen, void* pUserParam) +{ + Widget* pThis = (Widget*)pUserParam; + if (NULL == pThis) + { + return 0; + } + + if (iType == VLK_DEV_STATUS_TYPE_MODEL) + { + if (iBufLen != sizeof(VLK_DEV_MODEL)) + { + qCritical("################## bad device model info\n"); + return 0; + } + + VLK_DEV_MODEL* pModel = (VLK_DEV_MODEL*)szBuffer; + qDebug("model code: %02x, model name: %s\n", pModel->cModelCode, pModel->szModelName); + + emit pThis->SignalDeviceModel(*pModel); + } + else if (iType == VLK_DEV_STATUS_TYPE_CONFIG) + { + if (iBufLen != sizeof(VLK_DEV_CONFIG)) + { + qCritical("################## bad device configure\n"); + return 0; + } + + VLK_DEV_CONFIG* pDevConfig = (VLK_DEV_CONFIG*)szBuffer; + qDebug("VersionNO: %s, DeviceID: %s, SerialNO: %s\n", + pDevConfig->cVersionNO, pDevConfig->cDeviceID, pDevConfig->cSerialNO); + + emit pThis->SignalDeviceConfig(*pDevConfig); + } + else if (iType == VLK_DEV_STATUS_TYPE_TELEMETRY) + { + if (iBufLen != sizeof(VLK_DEV_TELEMETRY)) + { + qCritical("################## bad telemetry data\n"); + return 0; + } + + VLK_DEV_TELEMETRY* pTelemetry = (VLK_DEV_TELEMETRY*)szBuffer; + + // 只在云台状态有变化时输出日志 + static double lastYaw = 0.0, lastPitch = 0.0; + if (pTelemetry->dYaw != lastYaw || pTelemetry->dPitch != lastPitch) { + qDebug("Telemetry - Yaw: %.2f, Pitch: %.2f\n", + pTelemetry->dYaw, pTelemetry->dPitch); + lastYaw = pTelemetry->dYaw; + lastPitch = pTelemetry->dPitch; + } + + emit pThis->SignalDeviceTelemetry(*pTelemetry); + } + + return 0; +} + +void Widget::on_btnConnectTCP_clicked() +{ + // check if serial port connected + if (!!VLK_IsSerialPortConnected()) + { + VLK_DisconnectSerialPort(); + ui->btnConnctSerialPort->setText(tr("Connect")); + } + + // check if tcp connected + if (!!VLK_IsTCPConnected()) + { + VLK_DisconnectTCP(); + ui->btnConnectTCP->setText(tr("Connect")); + } + else + { + // connect TCP Gimbal + VLK_CONN_PARAM Param; + memset(&Param, 0, sizeof(VLK_CONN_PARAM)); + Param.emType = VLK_CONN_TYPE_TCP; + + QString strIPAddr = ui->cmbIPAddr->currentText(); + std::string stdstrIPAddr = strIPAddr.toStdString(); + strncpy(Param.ConnParam.IPAddr.szIPV4, stdstrIPAddr.c_str(), 15); + Param.ConnParam.IPAddr.szIPV4[15] = '\0'; + Param.ConnParam.IPAddr.iPort = ui->lineEditPort->text().toInt(); + + if (VLK_ERROR_NO_ERROR != VLK_Connect(&Param, VLK_ConnStatusCallback, this)) + { + qCritical() << "create tcp connection failed!"; + ui->btnConnectTCP->setText(tr("Connect")); + } + else + { + ui->btnConnectTCP->setText(tr("Connecting")); + } + } +} + +void Widget::on_btnConnctSerialPort_clicked() +{ + // check if tcp connected + if (!!VLK_IsTCPConnected()) + { + VLK_DisconnectTCP(); + ui->btnConnectTCP->setText(tr("Connect")); + } + + // check if serial port connected + if (!!VLK_IsSerialPortConnected()) + { + VLK_DisconnectSerialPort(); + ui->btnConnctSerialPort->setText(tr("Connect")); + } + else + { + // connect serial port + VLK_CONN_PARAM Param; + memset(&Param, 0, sizeof(VLK_CONN_PARAM)); + Param.emType = VLK_CONN_TYPE_SERIAL_PORT; + + QString strSerialPort = ui->cmbSerialPort->currentText(); + std::string stdstrSerialPort = strSerialPort.toStdString(); + strncpy(Param.ConnParam.SerialPort.szSerialPortName, stdstrSerialPort.c_str(), 15); + Param.ConnParam.SerialPort.szSerialPortName[15] = '\0'; + Param.ConnParam.SerialPort.iBaudRate = ui->lineEditBaudrate->text().toInt(); + + if (VLK_ERROR_NO_ERROR != VLK_Connect(&Param, VLK_ConnStatusCallback, this)) + { + qCritical() << "create tcp connection failed!"; + ui->btnConnctSerialPort->setText(tr("Connect")); + } + else + { + ui->btnConnctSerialPort->setText(tr("Connecting")); + } + } +} + +void Widget::onSlotConnectionStatus(int iConnStatus, const QString& strMessage) +{ + Q_UNUSED(strMessage); + if (iConnStatus == VLK_CONN_STATUS_TCP_CONNECTED) + { + qDebug() << "TCP Gimbal connected !!!"; + ui->btnConnectTCP->setText(tr("Disconnect")); + } + else if (iConnStatus == VLK_CONN_STATUS_TCP_DISCONNECTED) + { + qDebug() << "TCP Gimbal disconnected !!!"; + ui->btnConnectTCP->setText("Connect"); + } + else if (iConnStatus == VLK_CONN_STATUS_SERIAL_PORT_CONNECTED) + { + qDebug() << "Serial port Gimbal connected !!!"; + ui->btnConnctSerialPort->setText(tr("Disconnect")); + } + else if (iConnStatus == VLK_CONN_STATUS_SERIAL_PORT_DISCONNECTED) + { + qDebug() << "Serial port Gimbal disconnected !!!"; + ui->btnConnctSerialPort->setText(tr("Connect")); + } + else + { + qCritical() << "unknown connection status: " << iConnStatus; + } +} + +void Widget::onSlotDeviceModel(VLK_DEV_MODEL model) +{ + Q_UNUSED(model); +} + +void Widget::onSlotDeviceConfig(VLK_DEV_CONFIG config) +{ + // 输出设备配置信息 + qDebug() << "设备配置:"; + qDebug() << " 版本: " << config.cVersionNO; + qDebug() << " 设备ID: " << config.cDeviceID; + qDebug() << " 序列号: " << config.cSerialNO; +} + +void Widget::onSlotDeviceTelemetry(VLK_DEV_TELEMETRY telemetry) +{ + // 更新UI上的云台状态信息 + QLabel* yawLabel = findChild("lbYaw"); + QLabel* pitchLabel = findChild("lbPitch"); + QLabel* targetLatLabel = findChild("lbTargetLat"); + QLabel* targetLngLabel = findChild("lbTargetLng"); + QLabel* targetAltLabel = findChild("lbTargetAlt"); + QLabel* zoomLabel = findChild("lbZoom"); + + if (yawLabel) yawLabel->setText(QString::number(telemetry.dYaw)); + if (pitchLabel) pitchLabel->setText(QString::number(telemetry.dPitch)); + if (targetLatLabel) targetLatLabel->setText(QString::number(telemetry.dTargetLat)); + if (targetLngLabel) targetLngLabel->setText(QString::number(telemetry.dTargetLng)); + if (targetAltLabel) targetAltLabel->setText(QString::number(telemetry.dTargetAlt)); + if (zoomLabel) zoomLabel->setText(QString::number(telemetry.dZoomMagTimes)); + + // 保存激光测距结果 + if (telemetry.sLaserDistance > 0) { + m_lastLaserDistance = telemetry.sLaserDistance; + + // 如果存在距离显示标签,更新显示 + if (m_labelDistanceValue) { + m_labelDistanceValue->setText(QString::number(m_lastLaserDistance) + "米"); + } + } +} + +void Widget::on_btnOpenNetworkVideo_clicked() +{ + m_VideoObjUSBCamera.Close(); + + if (m_VideoObjNetwork.IsOpen()) + { + m_VideoObjNetwork.Close(); + ui->widgetMainVideo->Clear(); + ui->btnOpenNetworkVideo->setText(tr("Open")); + } + else + { + QString strURL = ui->cmbNetworkVideoURL->currentText(); + m_VideoObjNetwork.Open(strURL.toStdString(), ui->widgetMainVideo); + ui->btnOpenNetworkVideo->setText(tr("Close")); + + // 确保视频保持1920:1080的宽高比 + ui->widgetMainVideo->setKeepAspectRatio(true); + ui->widgetMainVideo->setStandardSize(1920, 1080); + } +} + +void Widget::on_btnOpenUSBVideo_clicked() +{ + m_VideoObjNetwork.Close(); + + if (m_VideoObjUSBCamera.IsOpen()) + { + m_VideoObjUSBCamera.Close(); + ui->widgetMainVideo->Clear(); + ui->btnOpenUSBVideo->setText(tr("Open")); + } + else + { + QString strUSBCamera = ui->cmbUSBCamera->currentText(); + m_VideoObjUSBCamera.Open(strUSBCamera, ui->widgetMainVideo); + ui->btnOpenUSBVideo->setText(tr("Close")); + + // 确保视频保持1920:1080的宽高比 + ui->widgetMainVideo->setKeepAspectRatio(true); + ui->widgetMainVideo->setStandardSize(1920, 1080); + } +} + + +void Widget::on_btnUp_pressed() +{ + double dSpeedRate = (double)ui->SliderMoveSpeed->value() / (double)ui->SliderMoveSpeed->maximum(); + double dScaleSpeed = (double)VLK_MAX_PITCH_SPEED * dSpeedRate; + VLK_Move(0, (short)dScaleSpeed); +} + +void Widget::on_btnUp_released() +{ + VLK_Stop(); +} + +void Widget::on_btnLeft_pressed() +{ + double dSpeedRate = (double)ui->SliderMoveSpeed->value() / (double)ui->SliderMoveSpeed->maximum(); + double dScaleSpeed = (double)VLK_MAX_YAW_SPEED * dSpeedRate * -1; + VLK_Move(dScaleSpeed, 0); +} + +void Widget::on_btnLeft_released() +{ + VLK_Stop(); +} + +void Widget::on_btnHome_clicked() +{ + VLK_Home(); +} + +void Widget::on_btnRight_pressed() +{ + double dSpeedRate = (double)ui->SliderMoveSpeed->value() / (double)ui->SliderMoveSpeed->maximum(); + double dScaleSpeed = (double)VLK_MAX_YAW_SPEED * dSpeedRate; + VLK_Move(dScaleSpeed, 0); +} + +void Widget::on_btnRight_released() +{ + VLK_Stop(); +} + +void Widget::on_btnDown_pressed() +{ + double dSpeedRate = (double)ui->SliderMoveSpeed->value() / (double)ui->SliderMoveSpeed->maximum(); + double dScaleSpeed = (double)VLK_MAX_PITCH_SPEED * dSpeedRate * -1; + VLK_Move(0, dScaleSpeed); +} + +void Widget::on_btnDown_released() +{ + VLK_Stop(); +} + +void Widget::on_cmbImageSensor_activated(int index) +{ + VLK_IMAGE_TYPE emType = (VLK_IMAGE_TYPE)ui->cmbImageSensor->itemData(index).toInt(); + VLK_IR_COLOR emColor = (VLK_IR_COLOR)ui->cmbIRColor->itemData(ui->cmbIRColor->currentIndex()).toInt(); + VLK_SetImageColor(emType, ui->checkBoxPIP->isChecked() ? 1 : 0, emColor); +} + +void Widget::on_cmbIRColor_activated(int index) +{ + VLK_IMAGE_TYPE emType = (VLK_IMAGE_TYPE)ui->cmbImageSensor->itemData(ui->cmbImageSensor->currentIndex()).toInt(); + VLK_IR_COLOR emColor = (VLK_IR_COLOR)ui->cmbIRColor->itemData(index).toInt(); + VLK_SetImageColor(emType, ui->checkBoxPIP->isChecked() ? 1 : 0, emColor); +} + +void Widget::on_checkBoxPIP_clicked(bool checked) +{ + VLK_IMAGE_TYPE emType = (VLK_IMAGE_TYPE)ui->cmbImageSensor->itemData(ui->cmbImageSensor->currentIndex()).toInt(); + VLK_IR_COLOR emColor = (VLK_IR_COLOR)ui->cmbIRColor->itemData(ui->cmbIRColor->currentIndex()).toInt(); + VLK_SetImageColor(emType, checked ? 1 : 0, emColor); +} + +void Widget::on_btnZoomIn_pressed() +{ + VLK_ZoomIn(4); +} + +void Widget::on_btnZoomIn_released() +{ + VLK_StopZoom(); +} + +void Widget::on_btnZoomOut_pressed() +{ + VLK_ZoomOut(4); +} + +void Widget::on_btnZoomOut_released() +{ + VLK_StopZoom(); +} + +void Widget::on_btnGimbalTakePhoto_clicked() +{ + // please make sure there is SD card in the Gimbal + VLK_Photograph(); +} + +void Widget::on_btnStartRecord_clicked() +{ + // please make sure there is SD card in the Gimbal + VLK_SwitchRecord(1); +} + +void Widget::on_btnStopRecord_clicked() +{ + // please make sure there is SD card in the Gimbal + VLK_SwitchRecord(0); +} + +void Widget::on_sliderConfidence_valueChanged(int value) +{ + // 将滑块值转换为0-1之间的浮点数 + m_confidenceThreshold = value / 100.0f; + // 更新显示 + ui->labelConfidenceValue->setText(QString::number(m_confidenceThreshold, 'f', 2)); +} + +void Widget::on_btnIdentifyTarget_clicked() +{ + // 判断是否连接了云台 + if (!VLK_IsTCPConnected() && !VLK_IsSerialPortConnected()) + { + QMessageBox::warning(this, tr("警告"), tr("请先连接云台设备")); + return; + } + + // 创建临时文件目录 + QDir dir("./temp"); + if (!dir.exists()) + { + dir.mkpath("."); + } + + // 生成临时文件路径 + QString tempImagePath = QString("./temp/capture_%1.jpg").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss")); + m_lastCapturedImagePath = tempImagePath; + + // 获取当前视频帧(截屏)而非使用云台拍照 + QMessageBox::information(this, tr("提示"), tr("正在截取当前画面...")); + + // 获取视频显示区域的截图 + QPixmap screenshot = ui->widgetMainVideo->grab(); + if (screenshot.isNull()) + { + QMessageBox::warning(this, tr("警告"), tr("截图失败,请确保视频正在播放")); + return; + } + + // 保存截图到本地 + if (!screenshot.save(tempImagePath, "JPG", 100)) + { + QMessageBox::warning(this, tr("警告"), tr("无法保存截图")); + return; + } + + QMessageBox::information(this, tr("提示"), tr("正在分析图像...")); + + // 加载图像 + if (!m_pImageProcessor->loadImage(tempImagePath.toStdString())) + { + QMessageBox::warning(this, tr("警告"), tr("无法加载图像")); + return; + } + + // 根据预处理复选框决定是否预处理图像 + QString processedImagePath; + if (ui->checkBoxPreprocess->isChecked()) + { + QMessageBox::information(this, tr("提示"), tr("正在预处理图像...增强对比度")); + // 预处理图像 + m_pImageProcessor->preprocessImage(); + + // 保存预处理后的图像 + processedImagePath = QString("./temp/processed_%1.jpg").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss")); + m_pImageProcessor->saveProcessedImage(processedImagePath.toStdString()); + } + else + { + // 不预处理,直接使用原始图像 + processedImagePath = tempImagePath; + } + + // 构建上下文信息 + QString context = buildDetectionContext(); + + // 调用API进行图像识别与距离估计 + try { + // 使用带距离估计的方法 + std::string result = m_pZhipuAPI->identifyObjectsInImage( + processedImagePath.toStdString(), + context.toStdString() + ); + + // 解析检测结果 + m_detectedObjects = m_pImageProcessor->parseDetectionResult(result); + + if (m_detectedObjects.empty()) + { + QMessageBox::information(this, tr("结果"), tr("未检测到目标或无法解析坐标")); + return; + } + + // 保存当前云台角度用于目标定位 + QLabel* yawLabel = findChild("lbYaw"); + QLabel* pitchLabel = findChild("lbPitch"); + m_lastGimbalYaw = yawLabel ? yawLabel->text().toDouble() : 0.0; + m_lastGimbalPitch = pitchLabel ? pitchLabel->text().toDouble() : 0.0; + + // =================== 开启激光测距 =================== + QMessageBox::information(this, tr("提示"), tr("正在进行激光测距...")); + + // 先打开激光 + VLK_SwitchLaser(1); + + // 等待激光稳定 + QThread::msleep(500); + + // 进行激光单次测距 + VLK_LaserSingle(); + + // 等待测距结果 + QThread::msleep(1000); + + // 记录激光测距结果前的值 + float oldLaserDistance = m_lastLaserDistance; + + // 等待可能的回调更新m_lastLaserDistance + QThread::msleep(500); + + // 记录激光测距结果 + float measuredDistance = 0.0f; + if (m_lastLaserDistance > 0 && m_lastLaserDistance != oldLaserDistance) { + // 从云台获取的测距结果 + measuredDistance = m_lastLaserDistance; + + QMessageBox::information(this, tr("测距结果"), + tr("激光测距结果: %1 米").arg(measuredDistance)); + } else { + QMessageBox::warning(this, tr("警告"), + tr("未获取到有效的激光测距结果,将使用AI估计的距离")); + } + + // 关闭激光 + VLK_SwitchLaser(0); + // =================== 激光测距结束 =================== + + // 标记检测到的目标 + m_pImageProcessor->markDetectedObjects(m_detectedObjects, m_confidenceThreshold); + + // 保存标记后的图像 + QString markedImagePath = QString("./temp/marked_%1.jpg").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss")); + if (m_pImageProcessor->saveMarkedImage(markedImagePath.toStdString())) + { + // 显示检测结果 + QString resultMsg = tr("检测到 %1 个目标。\n").arg(m_detectedObjects.size()); + + // 更新距离显示,使用检测到的目标的平均距离 + float avgDistance = 0.0f; + int validCount = 0; + + // 如果获取到了激光测距结果,更新所有目标的距离 + if (measuredDistance > 0) { + for (auto& obj : m_detectedObjects) { + if (obj.confidence >= m_confidenceThreshold) { + // 使用激光测距结果替换AI估计的距离 + obj.distance = measuredDistance; + + // 更新距离描述 + if (measuredDistance < 100) { + obj.distanceDesc = "近距离目标"; + } else if (measuredDistance < 500) { + obj.distanceDesc = "中距离目标"; + } else { + obj.distanceDesc = "远距离目标"; + } + } + } + } + + for (const auto& obj : m_detectedObjects) + { + if (obj.confidence >= m_confidenceThreshold) + { + validCount++; + resultMsg += tr("目标 %1: %2 (置信度: %3)\n").arg(validCount) + .arg(QString::fromStdString(obj.description)) + .arg(obj.confidence, 0, 'f', 2); + + // 如果有距离信息,添加到结果中 + if (obj.distance > 0) { + resultMsg += tr("距离估计: %1米 - %2\n") + .arg(obj.distance, 0, 'f', 1) + .arg(QString::fromStdString(obj.distanceDesc)); + } + + resultMsg += "\n"; + + // 累计距离用于计算平均值 + avgDistance += obj.distance; + } + } + + // 计算平均距离并更新UI + if (validCount > 0 && avgDistance > 0) { + avgDistance /= validCount; + if (m_labelDistanceValue) { + m_labelDistanceValue->setText(tr("%1米").arg(avgDistance, 0, 'f', 1)); + } + + // 启用显示目标在地图上的按钮 + if (m_btnShowTargetsOnMap) { + m_btnShowTargetsOnMap->setEnabled(true); + } + } else { + if (m_labelDistanceValue) { + m_labelDistanceValue->setText(tr("未知")); + } + + // 禁用显示目标在地图上的按钮 + if (m_btnShowTargetsOnMap) { + m_btnShowTargetsOnMap->setEnabled(false); + } + } + + resultMsg += tr("\n已保存标记后的图像: %1").arg(markedImagePath); + + QMessageBox::information(this, tr("识别结果"), resultMsg); + + // 使用图片预览对话框显示标记后的图片 + ImagePreviewDialog *previewDialog = new ImagePreviewDialog(markedImagePath, this); + previewDialog->setAttribute(Qt::WA_DeleteOnClose); // 关闭后自动删除 + previewDialog->show(); + + // 自动保存检测数据 + saveDetectionDataToFile(); + + // =================== 自动在地图上标记目标 =================== + if (m_isMAVConnected && validCount > 0 && avgDistance > 0) { + // 确认用户是否要在地图上标记目标 + if (QMessageBox::question(this, tr("标记目标"), + tr("是否将目标位置自动标记在地图上?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + showDetectedTargetsOnMap(); + } + } + // =================== 自动标记结束 =================== + } + else + { + QMessageBox::warning(this, tr("警告"), tr("无法保存标记后的图像")); + } + } + catch (const std::exception& e) + { + QMessageBox::critical(this, tr("错误"), tr("识别过程发生错误: %1").arg(e.what())); + } +} + +void Widget::on_btnClearIdentification_clicked() +{ + // 清除检测结果 + m_detectedObjects.clear(); + + // 删除临时文件 + QDir dir("./temp"); + if (dir.exists()) + { + dir.removeRecursively(); + } + + // 清除地图上的目标标记 + if (m_mapWidget) { + m_mapWidget->clearTargetMarkers(); + } + m_targetsOnMap = false; + + // 禁用显示目标在地图上的按钮 + if (m_btnShowTargetsOnMap) { + m_btnShowTargetsOnMap->setEnabled(false); + } + + QMessageBox::information(this, tr("提示"), tr("已清除识别结果和临时文件")); +} + +void Widget::on_checkBoxPreprocess_stateChanged(int state) +{ + // 当预处理复选框状态变化时调用 + if (state == Qt::Checked) + { + // 预处理已开启 + ui->groupBoxIdentify->setTitle(tr("红外智能识别 - 已开启")); + } + else + { + // 预处理已关闭 + ui->groupBoxIdentify->setTitle(tr("红外智能识别 - 已关闭")); + } +} + +// 新增:显示目标在地图上的按钮点击事件 +void Widget::on_btnShowTargetsOnMap_clicked() +{ + if (m_detectedObjects.empty()) { + QMessageBox::warning(this, tr("警告"), tr("没有检测到的目标可以显示")); + return; + } + + if (!m_isMAVConnected) { + QMessageBox::warning(this, tr("警告"), tr("无人机未连接,无法获取位置信息")); + return; + } + + showDetectedTargetsOnMap(); +} + +// 计算目标地理位置 +QGeoCoordinate Widget::calculateTargetPosition(double distance, double gimbalYaw, double gimbalPitch) +{ + // 获取无人机当前位置 + QGeoCoordinate uavPosition = m_mapWidget->getCurrentPosition(); + + // 如果无人机位置无效,返回无效坐标 + if (!uavPosition.isValid()) { + qWarning() << "无人机位置无效,无法计算目标位置"; + return QGeoCoordinate(); + } + + // 获取无人机航向角(弧度) + float uavHeading = m_attitude.yaw; // 航向角是偏航角 + + // 转换云台角度为弧度 + double gimbalYawRad = qDegreesToRadians(gimbalYaw); + double gimbalPitchRad = qDegreesToRadians(gimbalPitch); + + // 计算实际方向角(无人机航向 + 云台偏航) + double heading = uavHeading + gimbalYawRad; + + // 使用俯仰角计算水平距离 + double horizontalDistance = distance * qCos(gimbalPitchRad); + + // 计算高度差(正值表示目标低于无人机) + double heightDifference = distance * qSin(gimbalPitchRad); + + // 计算经纬度偏移 + double latOffset = horizontalDistance * qCos(heading); + double lonOffset = horizontalDistance * qSin(heading); + + // 转换为经纬度变化(近似计算) + // 经度1度约等于距离 = 111320 * cos(latitude) 米 + // 纬度1度约等于距离 = 110540 米 + double latChange = latOffset / 110540.0; + double lonChange = lonOffset / (111320.0 * qCos(qDegreesToRadians(uavPosition.latitude()))); + + // 计算目标位置 + double targetLat = uavPosition.latitude() + latChange; + double targetLon = uavPosition.longitude() + lonChange; + double targetAlt = uavPosition.altitude() - heightDifference; // 假设无人机高度是海拔高度 + + qDebug() << "目标位置计算: 距离=" << distance << "m, 水平距离=" << horizontalDistance + << "m, 高度差=" << heightDifference << "m"; + qDebug() << " 无人机位置: " << uavPosition.latitude() << ", " << uavPosition.longitude() + << ", 高度: " << uavPosition.altitude() << "m"; + qDebug() << " 目标位置: " << targetLat << ", " << targetLon << ", 高度: " << targetAlt << "m"; + + return QGeoCoordinate(targetLat, targetLon, targetAlt); +} + +// 计算目标位置估计的不确定性(米) +double Widget::calculateUncertainty(double distance) +{ + // 不确定性随距离增加而增加 + // 这里使用一个简单的线性模型:基础不确定性 + 距离因子 + double baseUncertainty = 10.0; // 基础不确定性10米 + double distanceFactor = 0.05; // 每米增加5厘米的不确定性 + + return baseUncertainty + distance * distanceFactor; +} + +// 在地图上显示检测到的目标 +void Widget::showDetectedTargetsOnMap() +{ + if (m_detectedObjects.empty() || !m_mapWidget) { + return; + } + + // 清除之前的目标标记 + m_mapWidget->clearTargetMarkers(); + + // 设置地图中心为无人机位置 + m_mapWidget->setMapCenter(m_mapWidget->getCurrentPosition()); + + // 根据置信度阈值过滤目标,并添加到地图 + int validTargets = 0; + for (const auto& target : m_detectedObjects) { + if (target.confidence >= m_confidenceThreshold && target.distance > 0) { + addTargetToMap(target); + validTargets++; + } + } + + if (validTargets > 0) { + m_targetsOnMap = true; + QMessageBox::information(this, tr("地图标记"), + tr("已在地图上标记 %1 个目标").arg(validTargets)); + } else { + QMessageBox::warning(this, tr("警告"), + tr("没有满足条件的目标可以标记")); + } +} + +// 添加单个目标到地图 +void Widget::addTargetToMap(const DetectedObject& target) +{ + // 计算目标位置 + QGeoCoordinate targetPosition = calculateTargetPosition( + target.distance, m_lastGimbalYaw, m_lastGimbalPitch); + + // 如果计算出的位置无效,返回 + if (!targetPosition.isValid()) { + qWarning() << "无法计算目标位置,跳过地图标记"; + return; + } + + // 计算不确定性(米) + double uncertainty = calculateUncertainty(target.distance); + + // 在地图上添加标记 + m_mapWidget->addTargetMarker(targetPosition, target.distance, uncertainty); + + qDebug() << "已添加目标到地图: " << QString::fromStdString(target.description) + << " 在位置 " << targetPosition.latitude() << ", " << targetPosition.longitude() + << " 距离: " << target.distance << "m, 不确定性: " << uncertainty << "m"; +} + +// 更新UI状态 +void Widget::updateUIState() +{ + // 根据无人机连接状态更新UI + if (m_isMAVConnected) { + ui->btnConnectUAV->setText("断开"); + + // 根据解锁状态更新按钮文本 + if (m_isUAVArmed) { + ui->btnArmDisarm->setText("上锁"); + } else { + ui->btnArmDisarm->setText("解锁"); + } + + // 启用控制按钮 + ui->btnTakeoff->setEnabled(m_isUAVArmed); + ui->btnLand->setEnabled(m_isUAVArmed); + ui->btnRTL->setEnabled(m_isUAVArmed); + ui->btnMode->setEnabled(true); + ui->comboBoxMode->setEnabled(true); + } else { + ui->btnConnectUAV->setText("连接"); + ui->btnArmDisarm->setText("解锁"); + + // 禁用控制按钮 + ui->btnArmDisarm->setEnabled(false); + ui->btnTakeoff->setEnabled(false); + ui->btnLand->setEnabled(false); + ui->btnRTL->setEnabled(false); + ui->btnMode->setEnabled(false); + ui->comboBoxMode->setEnabled(false); + } + + // 更新声源定位UI状态 + ui->btnStartSoundLocator->setEnabled(!m_isSoundLocatorRunning); + ui->btnStopSoundLocator->setEnabled(m_isSoundLocatorRunning); + ui->lineEditSoundIP->setEnabled(!m_isSoundLocatorRunning); + ui->lineEditSoundPort->setEnabled(!m_isSoundLocatorRunning); +} + +// 修改无人机连接按钮点击 +void Widget::on_btnConnectUAV_clicked() +{ + if (m_mavlinkClient->isConnected()) { + // 断开连接 + m_mavlinkClient->disconnect(); + m_isMAVConnected = false; + QMessageBox::information(this, "断开连接", "已断开与无人机的连接"); + } else { + // 连接无人机 + QString host = ui->lineEditUAVIP->text(); + int port = ui->lineEditUAVPort->text().toInt(); + + if (!m_mavlinkClient->connect(host.toStdString(), port)) { + QMessageBox::warning(this, "连接失败", "无法连接到无人机,请检查IP地址和端口是否正确"); + } + } + + updateUIState(); +} + +// 解锁/上锁按钮点击 +void Widget::on_btnArmDisarm_clicked() +{ + if (!m_mavlinkClient->isConnected()) { + QMessageBox::warning(this, "操作失败", "请先连接无人机"); + return; + } + + // 构造ARM/DISARM命令 + // MAV_CMD_COMPONENT_ARM_DISARM (400) + // 参数1: 0=解锁, 1=上锁 + bool success = sendMavlinkCommand( + 400, // MAV_CMD_COMPONENT_ARM_DISARM + m_isUAVArmed ? 0 : 1, // 参数1: 0=解锁, 1=上锁 + 0, // 参数2: (确认代码, 如果是上锁,则为21196) + 0, 0, 0, 0, 0 // 其他参数未使用 + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", m_isUAVArmed ? "上锁失败" : "解锁失败"); + } + + // 注意:实际的解锁状态会通过心跳消息回调更新 +} + +// 起飞按钮点击 +void Widget::on_btnTakeoff_clicked() +{ + if (!m_mavlinkClient->isConnected() || !m_isUAVArmed) { + QMessageBox::warning(this, "操作失败", "请先连接无人机并解锁"); + return; + } + + // 默认起飞高度为10米,可以使用对话框让用户输入 + bool ok; + float altitude = QInputDialog::getDouble(this, "起飞高度", "请输入起飞高度(米):", + 10.0, 1.0, 100.0, 1, &ok); + if (!ok) return; + + // 构造起飞命令 + // MAV_CMD_NAV_TAKEOFF (22) + bool success = sendMavlinkCommand( + 22, // MAV_CMD_NAV_TAKEOFF + 0, // 参数1: 未使用 + 0, 0, // 参数2-3: 未使用 + float(NAN), // 参数4: 偏航角,NAN表示当前角度 + float(NAN), // 参数5: 纬度,NAN表示当前位置 + float(NAN), // 参数6: 经度,NAN表示当前位置 + altitude // 参数7: 高度(m) + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", "起飞命令发送失败"); + } +} + +// 降落按钮点击 +void Widget::on_btnLand_clicked() +{ + if (!m_mavlinkClient->isConnected() || !m_isUAVArmed) { + QMessageBox::warning(this, "操作失败", "请先连接无人机并解锁"); + return; + } + + // 构造降落命令 + // MAV_CMD_NAV_LAND (21) + bool success = sendMavlinkCommand( + 21, // MAV_CMD_NAV_LAND + 0, // 参数1: 中止高度(已废弃) + 0, // 参数2: 精度设置(0=低精度) + 0, // 参数3: 未使用 + float(NAN), // 参数4: 偏航角,NAN表示当前角度 + float(NAN), // 参数5: 纬度,NAN表示当前位置 + float(NAN), // 参数6: 经度,NAN表示当前位置 + 0 // 参数7: 高度(m),通常为0 + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", "降落命令发送失败"); + } +} + +// 返航按钮点击 +void Widget::on_btnRTL_clicked() +{ + if (!m_mavlinkClient->isConnected() || !m_isUAVArmed) { + QMessageBox::warning(this, "操作失败", "请先连接无人机并解锁"); + return; + } + + // 构造返航命令,使用MAV_CMD_NAV_RETURN_TO_LAUNCH (20) + bool success = sendMavlinkCommand( + 20, // MAV_CMD_NAV_RETURN_TO_LAUNCH + 0, 0, 0, 0, 0, 0, 0 // 所有参数未使用 + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", "返航命令发送失败"); + } +} + +// 切换模式按钮点击 +void Widget::on_btnMode_clicked() +{ + if (!m_mavlinkClient->isConnected()) { + QMessageBox::warning(this, "操作失败", "请先连接无人机"); + return; + } + + int modeIndex = ui->comboBoxMode->currentIndex(); + + // 设置模式命令 + // MAV_CMD_DO_SET_MODE (176) + uint8_t baseMode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED; + uint32_t customMode = 0; + + switch (modeIndex) { + case 0: // 手动模式 + customMode = 0; // MANUAL + break; + case 1: // 稳定模式 + customMode = 2; // STABILIZE + break; + case 2: // 定高模式 + customMode = 3; // ALTITUDE HOLD + break; + case 3: // 定点模式 + customMode = 16; // POSITION + break; + case 4: // 自动模式 + customMode = 3; // AUTO + break; + default: + customMode = 0; // MANUAL + } + + bool success = sendMavlinkCommand( + 176, // MAV_CMD_DO_SET_MODE + baseMode, // 参数1: 基本模式 + customMode, // 参数2: 自定义模式 + 0, 0, 0, 0, 0 // 其他参数未使用 + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", "模式切换失败"); + } +} + +// MAVLink回调处理函数 +void Widget::handleHeartbeat(const mavlink_heartbeat_t& heartbeat) +{ + // 保存心跳信息 + m_heartbeat = heartbeat; + + // 检查解锁状态 + bool armed = (heartbeat.base_mode & MAV_MODE_FLAG_SAFETY_ARMED); + if (m_isUAVArmed != armed) { + m_isUAVArmed = armed; + // 更新UI + QMetaObject::invokeMethod(this, "updateUIState", Qt::QueuedConnection); + } + + // 更新连接状态 + if (!m_isMAVConnected) { + m_isMAVConnected = true; + // 连接建立,请求数据流 + m_mavlinkClient->requestDataStream(); + // 通知UI连接建立 + QMetaObject::invokeMethod(this, [this]() { + updateUIState(); + QMessageBox::information(this, "连接成功", "无人机连接已建立"); + }, Qt::QueuedConnection); + } +} + +void Widget::handleSystemStatus(const mavlink_sys_status_t& status) +{ + // 保存系统状态 + m_sysStatus = status; + + // 更新UI上的电池信息 + QMetaObject::invokeMethod(this, [this]() { + // 转换为电池百分比 + int remaining = m_sysStatus.battery_remaining; + if (remaining < 0) remaining = 0; + + // 更新UI显示 + QLabel* batteryLabel = findChild("valueBattery"); + if (batteryLabel) { + batteryLabel->setText(QString("%1%").arg(remaining)); + } + }, Qt::QueuedConnection); +} + +void Widget::handleAttitude(const mavlink_attitude_t& attitude) +{ + // 保存姿态信息 + m_attitude = attitude; + + // 将弧度转换为角度 + float roll = attitude.roll * 180.0f / M_PI; + float pitch = attitude.pitch * 180.0f / M_PI; + float yaw = attitude.yaw * 180.0f / M_PI; + + // 更新UI上的姿态信息 + QMetaObject::invokeMethod(this, [this, roll, pitch, yaw]() { + QLabel* rollLabel = findChild("valueRoll"); + QLabel* pitchLabel = findChild("valuePitch"); + QLabel* headingLabel = findChild("valueHeading"); + + if (rollLabel) rollLabel->setText(QString("%1°").arg(roll, 0, 'f', 1)); + if (pitchLabel) pitchLabel->setText(QString("%1°").arg(pitch, 0, 'f', 1)); + if (headingLabel) headingLabel->setText(QString("%1°").arg(yaw, 0, 'f', 1)); + }, Qt::QueuedConnection); +} + +void Widget::handlePosition(const mavlink_global_position_int_t& position) +{ + // 保存位置信息 + m_position = position; + + // 转换高度单位为米 + float altitude = position.alt / 1000.0f; + float relativeAltitude = position.relative_alt / 1000.0f; + + // 计算地速(米/秒) + float groundSpeed = sqrtf(powf(position.vx / 100.0f, 2) + powf(position.vy / 100.0f, 2)); + + // 转换为QGeoCoordinate + QGeoCoordinate pos(position.lat / 1.0e7, position.lon / 1.0e7, altitude); + + // 更新UI上的位置信息 + QMetaObject::invokeMethod(this, [this, altitude, relativeAltitude, groundSpeed, pos]() { + QLabel* altitudeLabel = findChild("valueAltitude"); + QLabel* speedLabel = findChild("valueSpeed"); + + if (altitudeLabel) altitudeLabel->setText(QString("%1 m").arg(relativeAltitude, 0, 'f', 1)); + if (speedLabel) speedLabel->setText(QString("%1 m/s").arg(groundSpeed, 0, 'f', 1)); + + // 更新地图位置 + m_mapWidget->setUAVPosition(pos); + }, Qt::QueuedConnection); +} + +// 发送MAVLink命令 +bool Widget::sendMavlinkCommand(uint16_t command, float param1, float param2, + float param3, float param4, float param5, + float param6, float param7) +{ + if (!m_mavlinkClient || !m_mavlinkClient->isConnected()) { + return false; + } + + // 调用MAVLinkClient类的sendCommand方法发送命令 + return m_mavlinkClient->sendCommand(command, param1, param2, param3, param4, param5, param6, param7); +} + +// 实现地图类型切换槽函数 +void Widget::on_btnSwitchMapType_clicked() +{ + if (!m_mapWidget) { + qWarning() << "地图组件未初始化"; + return; + } + + try { + m_mapWidget->toggleMapType(); + + // 更新按钮文本 + QPushButton *btn = qobject_cast(sender()); + if (btn) { + if (m_mapWidget->getCurrentMapType() == "normal") { + btn->setText("切换卫星地图"); + } else { + btn->setText("切换普通地图"); + } + } else { + qWarning() << "无法找到发送信号的按钮"; + } + } catch (const std::exception &e) { + qWarning() << "切换地图类型异常:" << e.what(); + } catch (...) { + qWarning() << "切换地图类型未知异常"; + } +} + +void Widget::on_btnStartSoundLocator_clicked() +{ + // 获取IP和端口 + m_soundLocatorIP = ui->lineEditSoundIP->text().trimmed(); + m_soundLocatorPort = ui->lineEditSoundPort->text().toInt(); + + // 确保IP不为空且端口有效 + if (m_soundLocatorIP.isEmpty() || m_soundLocatorPort <= 0 || m_soundLocatorPort > 65535) + { + ui->textEditSoundLog->append("错误:无效的IP地址或端口"); + return; + } + + // 开始定时请求数据 + m_isSoundLocatorRunning = true; + ui->btnStartSoundLocator->setEnabled(false); + ui->btnStopSoundLocator->setEnabled(true); + ui->lineEditSoundIP->setEnabled(false); + ui->lineEditSoundPort->setEnabled(false); + + ui->textEditSoundLog->append("开始监听声源定位数据..."); + + // 连接到TCP移动控制服务器 + m_moveControlIP = m_soundLocatorIP; // 使用相同的IP + connectToMoveControlTCP(); + + // 重置声音处理标志 + m_lastSoundProcessed = true; + + // 立即获取一次数据 + fetchSoundLocatorData(); + + // 启动定时器 + m_soundDataTimer->start(500); // 每500毫秒获取一次数据 +} + +void Widget::on_btnStopSoundLocator_clicked() +{ + // 停止定时器 + m_soundDataTimer->stop(); + m_isSoundLocatorRunning = false; + + ui->btnStartSoundLocator->setEnabled(true); + ui->btnStopSoundLocator->setEnabled(false); + ui->lineEditSoundIP->setEnabled(true); + ui->lineEditSoundPort->setEnabled(true); + + ui->textEditSoundLog->append("停止监听声源定位数据"); + + // 断开TCP移动控制连接 + disconnectFromMoveControlTCP(); +} + +void Widget::fetchSoundLocatorData() +{ + // 构造请求URL + QString url = QString("http://%1:%2/data").arg(m_soundLocatorIP).arg(m_soundLocatorPort); + + QNetworkRequest request; + request.setUrl(QUrl(url)); + + // 发送GET请求 + QNetworkReply *reply = m_soundNetworkManager->get(request); + + // 使用lambda处理响应 + connect(reply, &QNetworkReply::finished, [this, reply]() { + reply->deleteLater(); + + if (reply->error() == QNetworkReply::NoError) { + // 读取响应数据 + QByteArray responseData = reply->readAll(); + + // 解析JSON + QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData); + if (!jsonDoc.isNull() && jsonDoc.isObject()) { + QJsonObject jsonObj = jsonDoc.object(); + + // 提取声源数据 + double x = jsonObj["X"].toDouble(); + double y = jsonObj["Y"].toDouble(); + double strength = jsonObj["strength"].toDouble(); + double angle = jsonObj["angle"].toDouble(); + + // 更新UI + QString logMessage = QString("声源数据: X=%1, Y=%2, 强度=%3, 角度=%4°") + .arg(x, 0, 'f', 2) + .arg(y, 0, 'f', 2) + .arg(strength, 0, 'f', 2) + .arg(angle, 0, 'f', 2); + ui->textEditSoundLog->append(logMessage); + + // 更新可视化组件 + updateSoundVisualization(x, y, strength, angle); + + // 如果强度足够大且上一次声音已处理,则向该方向移动 + if (strength >= 1.0 && m_lastSoundProcessed && m_moveControlConnected) { + m_lastSoundProcessed = false; // 标记为未处理 + ui->textEditSoundLog->append(QString("检测到有效声源,向角度 %1° 方向移动2米").arg(angle)); + moveTowardSoundSource(angle); + m_lastSoundProcessed = true; // 处理完成 + } else if (strength < 1.0) { + ui->textEditSoundLog->append("警告:声源强度较低,可能没有明显声源"); + } + } else { + ui->textEditSoundLog->append("错误:无法解析服务器响应"); + } + } else { + // 请求出错 + ui->textEditSoundLog->append("错误:" + reply->errorString()); + + // 如果是连接错误且当前正在运行,自动停止 + if (reply->error() == QNetworkReply::ConnectionRefusedError && m_isSoundLocatorRunning) { + ui->textEditSoundLog->append("连接被拒绝,服务可能未启动。自动停止监听。"); + on_btnStopSoundLocator_clicked(); + } + } + + // 限制文本框内容长度,避免占用过多内存 + if (ui->textEditSoundLog->document()->lineCount() > 100) { + QTextCursor cursor = ui->textEditSoundLog->textCursor(); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor, 50); + cursor.removeSelectedText(); + } + + // 滚动到底部 + ui->textEditSoundLog->verticalScrollBar()->setValue( + ui->textEditSoundLog->verticalScrollBar()->maximum()); + }); +} + +void Widget::onSoundDataReceived() +{ + // 这个函数目前并不需要具体实现,因为我们直接在网络请求的回调中处理了响应数据 + // 如果将来需要单独处理声源数据,可以在这里实现 +} + +// 添加GPS回调处理函数实现 +void Widget::handleGPS(const mavlink_gps_raw_int_t& gps) +{ + // 保存GPS状态 + m_gps = gps; + + // 获取GPS修复类型和卫星数量 + int fixType = gps.fix_type; + int satellites = gps.satellites_visible; + + // 更新UI上的GPS信息 + QMetaObject::invokeMethod(this, [this, fixType, satellites]() { + // 简化为只判断是否连接 + QString fixText = (fixType > 0) ? "已连接" : "未连接"; + + // 更新UI显示 + if (m_labelGPSValue) { + m_labelGPSValue->setText(fixText); + } + if (m_labelSatellitesValue) { + m_labelSatellitesValue->setText(QString::number(satellites)); + } + + // 可选:显示HDOP和VDOP值(定位精度指标) + if (m_gps.eph != UINT16_MAX) { + float hdop = m_gps.eph / 100.0f; // 将HDOP转换为浮点数 + if (m_labelHDOPValue) { + m_labelHDOPValue->setText(QString::number(hdop, 'f', 1)); + } + } else { + if (m_labelHDOPValue) { + m_labelHDOPValue->setText("未知"); + } + } + + if (m_gps.epv != UINT16_MAX) { + float vdop = m_gps.epv / 100.0f; // 将VDOP转换为浮点数 + if (m_labelVDOPValue) { + m_labelVDOPValue->setText(QString::number(vdop, 'f', 1)); + } + } else { + if (m_labelVDOPValue) { + m_labelVDOPValue->setText("未知"); + } + } + }, Qt::QueuedConnection); +} + +// 初始化声源定位可视化组件 +void Widget::initSoundVisualization() +{ + // 创建场景和视图 + m_soundScene = new QGraphicsScene(this); + m_soundScene->setSceneRect(-100, -100, 200, 200); + + m_soundView = new QGraphicsView(m_soundScene); + m_soundView->setRenderHint(QPainter::Antialiasing); + m_soundView->setBackgroundBrush(QBrush(QColor(240, 240, 240))); + m_soundView->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + m_soundView->setMinimumSize(380, 180); + + // 添加网格线 + QPen gridPen(QColor(210, 210, 210), 0.5); + for (int i = -100; i <= 100; i += 20) { + m_soundScene->addLine(i, -100, i, 100, gridPen); + m_soundScene->addLine(-100, i, 100, i, gridPen); + } + + // 添加坐标轴 + QPen axisPen(Qt::black, 2); + m_soundScene->addLine(-100, 0, 100, 0, axisPen); + m_soundScene->addLine(0, -100, 0, 100, axisPen); + + // 添加坐标轴标签 + QFont labelFont; + labelFont.setBold(true); + labelFont.setPointSize(10); + + QGraphicsTextItem* xAxisLabel = m_soundScene->addText("X", labelFont); + xAxisLabel->setPos(90, 5); + xAxisLabel->setDefaultTextColor(Qt::darkBlue); + + QGraphicsTextItem* yAxisLabel = m_soundScene->addText("Y", labelFont); + yAxisLabel->setPos(5, -95); + yAxisLabel->setDefaultTextColor(Qt::darkBlue); + + // 添加标题 + QGraphicsTextItem* titleLabel = m_soundScene->addText("声源定位可视化", labelFont); + titleLabel->setPos(-95, -95); + titleLabel->setDefaultTextColor(Qt::darkBlue); + + // 创建声源点 + m_soundSourceItem = m_soundScene->addEllipse(-5, -5, 10, 10, QPen(Qt::red, 2), QBrush(QColor(255, 0, 0, 180))); + m_soundSourceItem->setZValue(10); + + // 创建方向线 + QPen directionPen(QColor(64, 158, 255), 2, Qt::DashLine); + m_soundDirectionLine = m_soundScene->addLine(0, 0, 0, 0, directionPen); + m_soundDirectionLine->setZValue(5); + + // 创建探测器点 + m_soundDetectorItem = m_soundScene->addEllipse(-4, -4, 8, 8, QPen(QColor(0, 128, 0), 1.5), QBrush(QColor(0, 150, 0, 200))); + m_soundDetectorItem->setZValue(8); + + // 创建信息文本 + QFont infoFont; + infoFont.setPointSize(9); + m_soundInfoText = m_soundScene->addText("无声源数据", infoFont); + m_soundInfoText->setPos(20, 50); + m_soundInfoText->setZValue(15); + m_soundInfoText->setDefaultTextColor(Qt::darkRed); + + // 添加到布局 + ui->layoutSoundVisualization->addWidget(m_soundView); +} + +void Widget::updateSoundVisualization(double x, double y, double strength, double angle) +{ + if (!m_soundScene || !m_soundSourceItem || !m_soundDirectionLine || !m_soundInfoText) { + return; + } + + // 保存当前数据 + m_soundX = x; + m_soundY = y; + m_soundStrength = strength; + m_soundAngle = angle; + + // 转换坐标系,将声源数据的坐标转换为场景坐标 + // 缩放因子:将[-15,15]的范围映射到[-100,100] + double scaleFactorX = 100.0 / 15.0; + double scaleFactorY = 100.0 / 15.0; + + double sceneX = x * scaleFactorX; + double sceneY = -y * scaleFactorY; // 注意Y轴反向 + + // 更新声源点位置和大小 + double size = std::max(10.0, strength * 5.0); + m_soundSourceItem->setRect(sceneX - size/2, sceneY - size/2, size, size); + + // 计算方向线 + double angleRad = (angle * M_PI) / 180.0; + double dirLength = 50.0; // 方向线长度 + double dirX = dirLength * std::sin(angleRad); + double dirY = -dirLength * std::cos(angleRad); // 注意Y轴反向 + + // 更新方向线,从探测器(0,0)指向方向 + m_soundDirectionLine->setLine(0, 0, dirX, dirY); + + // 添加方向箭头 + QPolygonF arrowHead; + double arrowSize = 8.0; + double angle1 = angleRad + M_PI*3/4; + double angle2 = angleRad - M_PI*3/4; + + arrowHead.append(QPointF(dirX, dirY)); + arrowHead.append(QPointF(dirX - arrowSize * std::cos(angle1), + dirY - arrowSize * std::sin(angle1))); + arrowHead.append(QPointF(dirX - arrowSize * std::cos(angle2), + dirY - arrowSize * std::sin(angle2))); + + // 清除旧的箭头 + foreach (QGraphicsItem* item, m_soundScene->items()) { + if (item->type() == QGraphicsPolygonItem::Type) { + m_soundScene->removeItem(item); + delete item; + } + } + + // 添加新箭头 + QGraphicsPolygonItem* arrow = m_soundScene->addPolygon(arrowHead, + QPen(QColor(64, 158, 255)), + QBrush(QColor(64, 158, 255))); + arrow->setZValue(6); + + // 更新信息文本 + QString infoText = QString("声源信息:\nX: %1\nY: %2\n强度: %3\n角度: %4°") + .arg(x, 0, 'f', 2) + .arg(y, 0, 'f', 2) + .arg(strength, 0, 'f', 2) + .arg(angle, 0, 'f', 2); + m_soundInfoText->setPlainText(infoText); + + // 如果声源强度太小,则降低透明度 + if (strength < 1.0) { + m_soundSourceItem->setOpacity(0.3); + m_soundDirectionLine->setOpacity(0.3); + arrow->setOpacity(0.3); + } else { + m_soundSourceItem->setOpacity(1.0); + m_soundDirectionLine->setOpacity(1.0); + } +} + +// 构建发送给大模型的上下文信息 +QString Widget::buildDetectionContext() +{ + QString context; + + // 添加云台状态信息 + QLabel* yawLabel = findChild("lbYaw"); + QLabel* pitchLabel = findChild("lbPitch"); + QLabel* zoomLabel = findChild("lbZoom"); + + QString yawText = yawLabel ? yawLabel->text() : ""; + QString pitchText = pitchLabel ? pitchLabel->text() : ""; + QString zoomText = zoomLabel ? zoomLabel->text() : ""; + + if (!yawText.isEmpty() && !pitchText.isEmpty()) { + context += QString("当前云台方位角: %1度,俯仰角: %2度,").arg(yawText).arg(pitchText); + } + + if (!zoomText.isEmpty()) { + context += QString("当前变焦倍数: %1倍。").arg(zoomText); + } + + // 添加设备基本信息 + context += "该红外设备用于侦察监视。红外热成像能够在夜间或低能见度环境下发现人员和车辆等热源。"; + + // 添加距离估计信息 + context += "根据图像中目标的特征,请估计它们的大致距离。红外图像中,距离越近的目标通常热特征越明显,轮廓越清晰。"; + context += "请基于目标的大小、热信号强度、图像细节等估计距离,并考虑以下因素:"; + context += "1. 热信号强度与距离:距离近的目标通常有更强烈的热信号;"; + context += "2. 图像清晰度:距离近的目标通常轮廓更清晰,细节更丰富;"; + context += "3. 目标大小:同类目标中,图像中占比较大的通常距离较近;"; + + // 添加任务要求 + context += "任务要求:除了识别图像中的目标,还请估计每个目标的距离(单位:米)。"; + context += "请按以下格式返回结果:对于每个目标,提供 [目标类型]: [描述], [置信度], [距离估计(米)], [距离描述]。"; + context += "例如:[人员]: 站立的男性, 0.95, 120, 中距离目标"; + + qDebug() << "构建的上下文信息:" << context; + return context; +} + +// 保存检测数据到文件 +void Widget::saveDetectionDataToFile() +{ + // 如果没有检测到目标,不保存 + if (m_detectedObjects.empty()) { + QMessageBox::warning(this, tr("保存失败"), tr("没有检测数据可保存")); + return; + } + + // 检查文件是否存在,如果不存在,添加表头 + bool fileExists = QFile::exists(m_detectionLogFile); + + QFile file(m_detectionLogFile); + if (!file.open(QIODevice::Append | QIODevice::Text)) { + QMessageBox::critical(this, tr("保存失败"), tr("无法打开文件进行写入")); + return; + } + + QTextStream out(&file); + + // 如果文件不存在,写入CSV表头 + if (!fileExists) { + out << "时间,目标类型,描述,置信度,X坐标,Y坐标,估计距离(米),距离描述\n"; + } + + // 获取当前时间 + QString currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"); + m_lastDetectionTime = currentTime; + + // 写入每个检测到的目标 + for (const auto& obj : m_detectedObjects) { + if (obj.confidence >= m_confidenceThreshold) { + out << currentTime << "," + << QString::fromStdString(obj.type) << "," + << "\"" << QString::fromStdString(obj.description) << "\"," + << obj.confidence << "," + << obj.x << "," + << obj.y << "," + << obj.distance << "," + << "\"" << QString::fromStdString(obj.distanceDesc) << "\"\n"; + } + } + + file.close(); + + QMessageBox::information(this, tr("保存成功"), + tr("已将%1个目标的检测数据保存到文件:\n%2").arg(m_detectedObjects.size()).arg(m_detectionLogFile)); +} + +// TCP控制相关方法实现 +bool Widget::connectToMoveControlTCP() +{ + // 如果已连接,先断开 + if (m_moveControlConnected) { + disconnectFromMoveControlTCP(); + } + + // 创建socket + if ((m_moveControlSocket = ::socket(AF_INET, SOCK_STREAM, 0)) < 0) { + ui->textEditSoundLog->append("错误:TCP控制Socket创建失败"); + return false; + } + + m_moveControlAddr.sin_family = AF_INET; + m_moveControlAddr.sin_port = htons(m_moveControlPort); + + // 转换IP地址 + if (inet_pton(AF_INET, m_moveControlIP.toStdString().c_str(), &m_moveControlAddr.sin_addr) <= 0) { + ui->textEditSoundLog->append("错误:TCP控制无效的IP地址"); + ::close(m_moveControlSocket); + m_moveControlSocket = -1; + return false; + } + + // 连接服务器 + ui->textEditSoundLog->append(QString("正在连接到移动控制服务器 %1:%2").arg(m_moveControlIP).arg(m_moveControlPort)); + if (::connect(m_moveControlSocket, (struct sockaddr *)&m_moveControlAddr, sizeof(m_moveControlAddr)) < 0) { + ui->textEditSoundLog->append("错误:TCP控制连接失败"); + ::close(m_moveControlSocket); + m_moveControlSocket = -1; + return false; + } + + ui->textEditSoundLog->append("TCP移动控制连接成功"); + m_moveControlConnected = true; + return true; +} + +void Widget::disconnectFromMoveControlTCP() +{ + if (m_moveControlSocket >= 0) { + ::close(m_moveControlSocket); + m_moveControlSocket = -1; + m_moveControlConnected = false; + ui->textEditSoundLog->append("TCP移动控制已断开连接"); + } +} + +bool Widget::sendMoveCommand(double x, double y) +{ + if (!m_moveControlConnected) { + ui->textEditSoundLog->append("错误:TCP控制未连接,无法发送移动命令"); + return false; + } + + // 构造坐标字符串 + QString cmd = QString("%1,%2").arg(x, 0, 'f', 2).arg(y, 0, 'f', 2); + std::string cmdStr = cmd.toStdString(); + + // 发送坐标 + if (::send(m_moveControlSocket, cmdStr.c_str(), cmdStr.length(), 0) < 0) { + ui->textEditSoundLog->append("错误:发送移动命令失败"); + return false; + } + + ui->textEditSoundLog->append(QString("已发送移动命令: %1").arg(cmd)); + + // 接收服务器响应 + char buffer[1024] = {0}; + int valread = ::read(m_moveControlSocket, buffer, 1024); + if (valread > 0) { + buffer[valread] = '\0'; + ui->textEditSoundLog->append(QString("服务器响应: %1").arg(buffer)); + } + + return true; +} + +void Widget::moveTowardSoundSource(double angle) +{ + // 计算向声源方向移动2米的X和Y坐标 + // 角度转换为弧度,注意角度是相对于Y轴正方向的 + double radians = (angle * M_PI) / 180.0; + + // 计算X和Y分量,注意坐标系转换 + // 在声源定位系统中,角度0度表示正前方,90度表示右侧 + // 而在移动控制系统中,X轴正方向是前进,Y轴正方向是左侧 + double distance = 2.0; // 移动2米 + double x = distance * std::cos(radians); // X轴分量 + double y = distance * std::sin(radians); // Y轴分量 + + // 发送移动命令 + sendMoveCommand(x, y); +} + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.cpp.new b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.cpp.new new file mode 100644 index 0000000..526e713 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.cpp.new @@ -0,0 +1,1268 @@ +#include "widget.h" +#include "ui_widget.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "imagepreviewdialog.h" + +Widget::Widget(QWidget *parent) : + QWidget(parent), + ui(new Ui::Widget) +{ + ui->setupUi(this); + qRegisterMetaType("VLK_DEV_MODEL"); + qRegisterMetaType("VLK_DEV_CONFIG"); + qRegisterMetaType("VLK_DEV_TELEMETRY"); + + connect(this, SIGNAL(SignalConnectionStatus(int, const QString&)), this, SLOT(onSlotConnectionStatus(int, const QString&))); + connect(this, SIGNAL(SignalDeviceModel(VLK_DEV_MODEL)), this, SLOT(onSlotDeviceModel(VLK_DEV_MODEL))); + connect(this, SIGNAL(SignalDeviceConfig(VLK_DEV_CONFIG)), this, SLOT(onSlotDeviceConfig(VLK_DEV_CONFIG))); + connect(this, SIGNAL(SignalDeviceTelemetry(VLK_DEV_TELEMETRY)), this, SLOT(onSlotDeviceTelemetry(VLK_DEV_TELEMETRY))); + + InitUI(); + + VLK_RegisterDevStatusCB(VLK_DevStatusCallback, this); + + // 初始化红外识别相关成员变量 + m_pImageProcessor = new ImageProcessor(); + // 使用智谱AI API的密钥 + m_pZhipuAPI = new ZhipuAPI("3bbb7dee27ac40e38a9b2026065dfa09.oLgHTXxNnz4FM392", 60); + m_confidenceThreshold = 0.7f; // 默认置信度 + m_lastCapturedImagePath = ""; + + // 初始化目标距离估计相关成员 + m_lastLaserDistance = 0.0f; + m_distanceEstimationEnabled = true; + m_labelDistanceValue = nullptr; + + // 设置检测数据日志文件 + QString logDir = "./detection_logs"; + QDir dir(logDir); + if (!dir.exists()) { + dir.mkpath("."); + } + m_detectionLogFile = QString("%1/detection_log_%2.csv") + .arg(logDir) + .arg(QDateTime::currentDateTime().toString("yyyyMMdd")); + + // 初始化MAVLink客户端和无人机状态 + m_mavlinkClient = new MAVLinkClient(); + m_isUAVArmed = false; + m_isMAVConnected = false; + + // 设置MAVLink回调函数 + m_mavlinkClient->setHeartbeatCallback([this](const mavlink_heartbeat_t& heartbeat) { + this->handleHeartbeat(heartbeat); + }); + + m_mavlinkClient->setSystemStatusCallback([this](const mavlink_sys_status_t& status) { + this->handleSystemStatus(status); + }); + + m_mavlinkClient->setAttitudeCallback([this](const mavlink_attitude_t& attitude) { + this->handleAttitude(attitude); + }); + + m_mavlinkClient->setPositionCallback([this](const mavlink_global_position_int_t& position) { + this->handlePosition(position); + }); + + // 添加GPS回调函数 + m_mavlinkClient->setGPSCallback([this](const mavlink_gps_raw_int_t& gps) { + this->handleGPS(gps); + }); + + // 创建地图控件 + m_mapWidget = new MapWidget(); + ui->layoutMap->addWidget(m_mapWidget); + + // 界面默认同时显示摄像头控制和无人机控制 + + // 初始化声源定位相关成员 + m_soundNetworkManager = new QNetworkAccessManager(this); + m_soundDataTimer = new QTimer(this); + connect(m_soundDataTimer, &QTimer::timeout, this, &Widget::fetchSoundLocatorData); + m_isSoundLocatorRunning = false; + m_soundLocatorIP = "127.0.0.1"; + m_soundLocatorPort = 5000; + + // 初始化声源定位可视化组件 + m_soundScene = nullptr; + m_soundView = nullptr; + m_soundSourceItem = nullptr; + m_soundDirectionLine = nullptr; + m_soundInfoText = nullptr; + m_soundDetectorItem = nullptr; + m_soundX = 0.0; + m_soundY = 0.0; + m_soundStrength = 0.0; + m_soundAngle = 0.0; + initSoundVisualization(); + + // 初始化UI状态 + updateUIState(); + + // 初始化GPS状态标签 + if (m_labelGPSValue) { + m_labelGPSValue->setText("未连接"); + } + if (m_labelSatellitesValue) { + m_labelSatellitesValue->setText("0"); + } + + // 添加目标距离显示标签 + QGridLayout *identifyLayout = qobject_cast(ui->groupBoxIdentify->layout()); + if (identifyLayout) { + // 找到btnIdentifyTarget的位置 + int row = -1, col = -1, rowSpan = -1, colSpan = -1; + identifyLayout->getItemPosition(identifyLayout->indexOf(ui->btnIdentifyTarget), &row, &col, &rowSpan, &colSpan); + + if (row >= 0) { + // 添加估计距离显示 + QHBoxLayout *distanceLayout = new QHBoxLayout(); + QLabel *labelDistance = new QLabel(tr("估计距离:"), ui->groupBoxIdentify); + labelDistance->setObjectName("labelDistance"); + + QLabel *labelDistanceValue = new QLabel(tr("未知"), ui->groupBoxIdentify); + labelDistanceValue->setObjectName("labelDistanceValue"); + m_labelDistanceValue = labelDistanceValue; + + distanceLayout->addWidget(labelDistance); + distanceLayout->addWidget(labelDistanceValue); + distanceLayout->addStretch(); + + // 在btnClearIdentification的下一行添加距离显示 + int clearBtnRow = -1; + identifyLayout->getItemPosition(identifyLayout->indexOf(ui->btnClearIdentification), &clearBtnRow, &col, &rowSpan, &colSpan); + if (clearBtnRow >= 0) { + identifyLayout->addLayout(distanceLayout, clearBtnRow + 1, 0, 1, 2); + } else { + identifyLayout->addLayout(distanceLayout, row + 1, 0, 1, 2); + } + } + } +} + +Widget::~Widget() +{ + m_VideoObjNetwork.Close(); + m_VideoObjUSBCamera.Close(); + + // 释放红外识别相关资源 + if (m_pImageProcessor) + { + delete m_pImageProcessor; + m_pImageProcessor = nullptr; + } + + if (m_pZhipuAPI) + { + delete m_pZhipuAPI; + m_pZhipuAPI = nullptr; + } + + // 断开MAVLink连接并释放资源 + if (m_mavlinkClient) + { + if (m_mavlinkClient->isConnected()) + { + m_mavlinkClient->disconnect(); + } + delete m_mavlinkClient; + m_mavlinkClient = nullptr; + } + + // 停止声源定位服务并释放资源 + if (m_soundDataTimer) + { + m_soundDataTimer->stop(); + } + + // 清理场景和视图 + if (m_soundScene) { + m_soundScene->clear(); + delete m_soundScene; + m_soundScene = nullptr; + } + + delete ui; +} + +void Widget::InitUI() +{ + // initialize serial port list + ui->cmbSerialPort->clear(); + QList listSerialPortInfo = QSerialPortInfo::availablePorts(); + foreach(const QSerialPortInfo &port_info, listSerialPortInfo) + { + ui->cmbSerialPort->addItem(port_info.portName()); + } + + ui->lineEditBaudrate->setText("115200"); + + // initialize tcp gimbal list + ui->cmbIPAddr->addItem("192.168.2.119"); + ui->lineEditPort->setText("2000"); + + // initialize network url list + ui->cmbNetworkVideoURL->addItem("rtsp://192.168.2.119:554"); + + // initialize USB Camera list + QList listAvailableCamera = QCamera::availableDevices(); + foreach (const QByteArray &camera, listAvailableCamera) + { + ui->cmbUSBCamera->addItem(QCamera::deviceDescription(camera)); + } + + // initialize image sensor combobox items + ui->cmbImageSensor->addItem(tr("Visible1"), VLK_IMAGE_TYPE_VISIBLE1); + ui->cmbImageSensor->addItem(tr("IR"), VLK_IMAGE_TYPE_IR1); + // ui->cmbImageSensor->addItem(tr("Visible2"), VLK_IMAGE_TYPE_VISIBLE2); + // ui->cmbImageSensor->addItem(tr("IR2"), VLK_IMAGE_TYPE_IR2); + // ui->cmbImageSensor->addItem(tr("Fusion"), VLK_IMAGE_TYPE_FUSION); + + // initialize IR color combobox items + ui->cmbIRColor->addItem(tr("White hot"), VLK_IR_COLOR_WHITEHOT); + ui->cmbIRColor->addItem(tr("Black hot"), VLK_IR_COLOR_BLACKHOT); + ui->cmbIRColor->addItem(tr("Pseudo hot"), VLK_IR_COLOR_PSEUDOHOT); + + // 添加GPS状态UI元素到飞行状态信息组 + QGridLayout *gridLayout = qobject_cast(ui->groupBoxStatus->layout()); + if (gridLayout) { + // 当前行数 + int row = gridLayout->rowCount(); + + // 添加GPS状态标签 + QLabel *labelGPS = new QLabel(tr("GPS状态:"), ui->groupBoxStatus); + labelGPS->setObjectName("labelGPS"); + gridLayout->addWidget(labelGPS, row, 0); + + QLabel *labelGPSValue = new QLabel(tr("未连接"), ui->groupBoxStatus); + labelGPSValue->setObjectName("labelGPSValue"); + gridLayout->addWidget(labelGPSValue, row, 1); + m_labelGPSValue = labelGPSValue; + + // 添加卫星数量标签 + QLabel *labelSatellites = new QLabel(tr("卫星数量:"), ui->groupBoxStatus); + labelSatellites->setObjectName("labelSatellites"); + gridLayout->addWidget(labelSatellites, row, 2); + + QLabel *labelSatellitesValue = new QLabel("0", ui->groupBoxStatus); + labelSatellitesValue->setObjectName("labelSatellitesValue"); + gridLayout->addWidget(labelSatellitesValue, row, 3); + m_labelSatellitesValue = labelSatellitesValue; + + // 添加HDOP标签 (增加一行) + row++; + QLabel *labelHDOP = new QLabel(tr("水平精度:"), ui->groupBoxStatus); + labelHDOP->setObjectName("labelHDOP"); + gridLayout->addWidget(labelHDOP, row, 0); + + QLabel *labelHDOPValue = new QLabel(tr("未知"), ui->groupBoxStatus); + labelHDOPValue->setObjectName("labelHDOPValue"); + gridLayout->addWidget(labelHDOPValue, row, 1); + m_labelHDOPValue = labelHDOPValue; + + // 添加VDOP标签 + QLabel *labelVDOP = new QLabel(tr("垂直精度:"), ui->groupBoxStatus); + labelVDOP->setObjectName("labelVDOP"); + gridLayout->addWidget(labelVDOP, row, 2); + + QLabel *labelVDOPValue = new QLabel(tr("未知"), ui->groupBoxStatus); + labelVDOPValue->setObjectName("labelVDOPValue"); + gridLayout->addWidget(labelVDOPValue, row, 3); + m_labelVDOPValue = labelVDOPValue; + } +} + +int Widget::VLK_ConnStatusCallback(int iConnStatus, const char* szMessage, int iMsgLen, void* pUserParam) +{ + Widget* pThis = (Widget*)pUserParam; + if (NULL == pThis) + { + return 0; + } + + QString strMessage; + if (szMessage != NULL && iMsgLen > 0 ) + { + strMessage = QString::fromUtf8(szMessage); + } + + emit pThis->SignalConnectionStatus(iConnStatus, strMessage); + + return 0; +} + +int Widget::VLK_DevStatusCallback(int iType, const char* szBuffer, int iBufLen, void* pUserParam) +{ + Widget* pThis = (Widget*)pUserParam; + if (NULL == pThis) + { + return 0; + } + + if (iType == VLK_DEV_STATUS_TYPE_MODEL) + { + if (iBufLen != sizeof(VLK_DEV_MODEL)) + { + qCritical("################## bad device model info\n"); + return 0; + } + + VLK_DEV_MODEL* pModel = (VLK_DEV_MODEL*)szBuffer; + qDebug("model code: %02x, model name: %s\n", pModel->cModelCode, pModel->szModelName); + + emit pThis->SignalDeviceModel(*pModel); + } + else if (iType == VLK_DEV_STATUS_TYPE_CONFIG) + { + if (iBufLen != sizeof(VLK_DEV_CONFIG)) + { + qCritical("################## bad device configure\n"); + return 0; + } + + VLK_DEV_CONFIG* pDevConfig = (VLK_DEV_CONFIG*)szBuffer; + qDebug("VersionNO: %s, DeviceID: %s, SerialNO: %s\n", + pDevConfig->cVersionNO, pDevConfig->cDeviceID, pDevConfig->cSerialNO); + + emit pThis->SignalDeviceConfig(*pDevConfig); + } + else if (iType == VLK_DEV_STATUS_TYPE_TELEMETRY) + { + if (iBufLen != sizeof(VLK_DEV_TELEMETRY)) + { + qCritical("################## bad telemetry data\n"); + return 0; + } + + VLK_DEV_TELEMETRY* pTelemetry = (VLK_DEV_TELEMETRY*)szBuffer; + + // 只在云台状态有变化时输出日志 + static double lastYaw = 0.0, lastPitch = 0.0; + if (pTelemetry->dYaw != lastYaw || pTelemetry->dPitch != lastPitch) { + qDebug("Telemetry - Yaw: %.2f, Pitch: %.2f\n", + pTelemetry->dYaw, pTelemetry->dPitch); + lastYaw = pTelemetry->dYaw; + lastPitch = pTelemetry->dPitch; + } + + emit pThis->SignalDeviceTelemetry(*pTelemetry); + } + + return 0; +} + +void Widget::on_btnConnectTCP_clicked() +{ + // check if serial port connected + if (!!VLK_IsSerialPortConnected()) + { + VLK_DisconnectSerialPort(); + ui->btnConnctSerialPort->setText(tr("Connect")); + } + + // check if tcp connected + if (!!VLK_IsTCPConnected()) + { + VLK_DisconnectTCP(); + ui->btnConnectTCP->setText(tr("Connect")); + } + else + { + // connect TCP Gimbal + VLK_CONN_PARAM Param; + memset(&Param, 0, sizeof(VLK_CONN_PARAM)); + Param.emType = VLK_CONN_TYPE_TCP; + + QString strIPAddr = ui->cmbIPAddr->currentText(); + std::string stdstrIPAddr = strIPAddr.toStdString(); + strncpy(Param.ConnParam.IPAddr.szIPV4, stdstrIPAddr.c_str(), 15); + Param.ConnParam.IPAddr.szIPV4[15] = '\0'; + Param.ConnParam.IPAddr.iPort = ui->lineEditPort->text().toInt(); + + if (VLK_ERROR_NO_ERROR != VLK_Connect(&Param, VLK_ConnStatusCallback, this)) + { + qCritical() << "create tcp connection failed!"; + ui->btnConnectTCP->setText(tr("Connect")); + } + else + { + ui->btnConnectTCP->setText(tr("Connecting")); + } + } +} + +void Widget::on_btnConnctSerialPort_clicked() +{ + // check if tcp connected + if (!!VLK_IsTCPConnected()) + { + VLK_DisconnectTCP(); + ui->btnConnectTCP->setText(tr("Connect")); + } + + // check if serial port connected + if (!!VLK_IsSerialPortConnected()) + { + VLK_DisconnectSerialPort(); + ui->btnConnctSerialPort->setText(tr("Connect")); + } + else + { + // connect serial port + VLK_CONN_PARAM Param; + memset(&Param, 0, sizeof(VLK_CONN_PARAM)); + Param.emType = VLK_CONN_TYPE_SERIAL_PORT; + + QString strSerialPort = ui->cmbSerialPort->currentText(); + std::string stdstrSerialPort = strSerialPort.toStdString(); + strncpy(Param.ConnParam.SerialPort.szSerialPortName, stdstrSerialPort.c_str(), 15); + Param.ConnParam.SerialPort.szSerialPortName[15] = '\0'; + Param.ConnParam.SerialPort.iBaudRate = ui->lineEditBaudrate->text().toInt(); + + if (VLK_ERROR_NO_ERROR != VLK_Connect(&Param, VLK_ConnStatusCallback, this)) + { + qCritical() << "create tcp connection failed!"; + ui->btnConnctSerialPort->setText(tr("Connect")); + } + else + { + ui->btnConnctSerialPort->setText(tr("Connecting")); + } + } +} + +void Widget::onSlotConnectionStatus(int iConnStatus, const QString& strMessage) +{ + Q_UNUSED(strMessage); + if (iConnStatus == VLK_CONN_STATUS_TCP_CONNECTED) + { + qDebug() << "TCP Gimbal connected !!!"; + ui->btnConnectTCP->setText(tr("Disconnect")); + } + else if (iConnStatus == VLK_CONN_STATUS_TCP_DISCONNECTED) + { + qDebug() << "TCP Gimbal disconnected !!!"; + ui->btnConnectTCP->setText("Connect"); + } + else if (iConnStatus == VLK_CONN_STATUS_SERIAL_PORT_CONNECTED) + { + qDebug() << "Serial port Gimbal connected !!!"; + ui->btnConnctSerialPort->setText(tr("Disconnect")); + } + else if (iConnStatus == VLK_CONN_STATUS_SERIAL_PORT_DISCONNECTED) + { + qDebug() << "Serial port Gimbal disconnected !!!"; + ui->btnConnctSerialPort->setText(tr("Connect")); + } + else + { + qCritical() << "unknown connection status: " << iConnStatus; + } +} + +void Widget::onSlotDeviceModel(VLK_DEV_MODEL model) +{ + Q_UNUSED(model); +} + +void Widget::onSlotDeviceConfig(VLK_DEV_CONFIG config) +{ + // 输出设备配置信息 + qDebug() << "设备配置:"; + qDebug() << " 版本: " << config.cVersionNO; + qDebug() << " 设备ID: " << config.cDeviceID; + qDebug() << " 序列号: " << config.cSerialNO; +} + +void Widget::onSlotDeviceTelemetry(VLK_DEV_TELEMETRY telemetry) +{ + // 更新UI上的云台状态信息 + ui->lbYaw->setText(QString::number(telemetry.dYaw)); + ui->lbPitch->setText(QString::number(telemetry.dPitch)); + ui->lbTargetLat->setText(QString::number(telemetry.dTargetLat)); + ui->lbTargetLng->setText(QString::number(telemetry.dTargetLng)); + ui->lbTargetAlt->setText(QString::number(telemetry.dTargetAlt)); + ui->lbZoom->setText(QString::number(telemetry.dZoomMagTimes)); +} + +void Widget::on_btnOpenNetworkVideo_clicked() +{ + m_VideoObjUSBCamera.Close(); + + if (m_VideoObjNetwork.IsOpen()) + { + m_VideoObjNetwork.Close(); + ui->widgetMainVideo->Clear(); + ui->btnOpenNetworkVideo->setText(tr("Open")); + } + else + { + QString strURL = ui->cmbNetworkVideoURL->currentText(); + m_VideoObjNetwork.Open(strURL.toStdString(), ui->widgetMainVideo); + ui->btnOpenNetworkVideo->setText(tr("Close")); + } +} + +void Widget::on_btnOpenUSBVideo_clicked() +{ + m_VideoObjNetwork.Close(); + + if (m_VideoObjUSBCamera.IsOpen()) + { + m_VideoObjUSBCamera.Close(); + ui->widgetMainVideo->Clear(); + ui->btnOpenUSBVideo->setText(tr("Open")); + } + else + { + QString strUSBCamera = ui->cmbUSBCamera->currentText(); + m_VideoObjUSBCamera.Open(strUSBCamera, ui->widgetMainVideo); + ui->btnOpenUSBVideo->setText(tr("Close")); + } +} + + +void Widget::on_btnUp_pressed() +{ + double dSpeedRate = (double)ui->SliderMoveSpeed->value() / (double)ui->SliderMoveSpeed->maximum(); + double dScaleSpeed = (double)VLK_MAX_PITCH_SPEED * dSpeedRate; + VLK_Move(0, (short)dScaleSpeed); +} + +void Widget::on_btnUp_released() +{ + VLK_Stop(); +} + +void Widget::on_btnLeft_pressed() +{ + double dSpeedRate = (double)ui->SliderMoveSpeed->value() / (double)ui->SliderMoveSpeed->maximum(); + double dScaleSpeed = (double)VLK_MAX_YAW_SPEED * dSpeedRate * -1; + VLK_Move(dScaleSpeed, 0); +} + +void Widget::on_btnLeft_released() +{ + VLK_Stop(); +} + +void Widget::on_btnHome_clicked() +{ + VLK_Home(); +} + +void Widget::on_btnRight_pressed() +{ + double dSpeedRate = (double)ui->SliderMoveSpeed->value() / (double)ui->SliderMoveSpeed->maximum(); + double dScaleSpeed = (double)VLK_MAX_YAW_SPEED * dSpeedRate; + VLK_Move(dScaleSpeed, 0); +} + +void Widget::on_btnRight_released() +{ + VLK_Stop(); +} + +void Widget::on_btnDown_pressed() +{ + double dSpeedRate = (double)ui->SliderMoveSpeed->value() / (double)ui->SliderMoveSpeed->maximum(); + double dScaleSpeed = (double)VLK_MAX_PITCH_SPEED * dSpeedRate * -1; + VLK_Move(0, dScaleSpeed); +} + +void Widget::on_btnDown_released() +{ + VLK_Stop(); +} + +void Widget::on_cmbImageSensor_activated(int index) +{ + VLK_IMAGE_TYPE emType = (VLK_IMAGE_TYPE)ui->cmbImageSensor->itemData(index).toInt(); + VLK_IR_COLOR emColor = (VLK_IR_COLOR)ui->cmbIRColor->itemData(ui->cmbIRColor->currentIndex()).toInt(); + VLK_SetImageColor(emType, ui->checkBoxPIP->isChecked() ? 1 : 0, emColor); +} + +void Widget::on_cmbIRColor_activated(int index) +{ + VLK_IMAGE_TYPE emType = (VLK_IMAGE_TYPE)ui->cmbImageSensor->itemData(ui->cmbImageSensor->currentIndex()).toInt(); + VLK_IR_COLOR emColor = (VLK_IR_COLOR)ui->cmbIRColor->itemData(index).toInt(); + VLK_SetImageColor(emType, ui->checkBoxPIP->isChecked() ? 1 : 0, emColor); +} + +void Widget::on_checkBoxPIP_clicked(bool checked) +{ + VLK_IMAGE_TYPE emType = (VLK_IMAGE_TYPE)ui->cmbImageSensor->itemData(ui->cmbImageSensor->currentIndex()).toInt(); + VLK_IR_COLOR emColor = (VLK_IR_COLOR)ui->cmbIRColor->itemData(ui->cmbIRColor->currentIndex()).toInt(); + VLK_SetImageColor(emType, checked ? 1 : 0, emColor); +} + +void Widget::on_btnZoomIn_pressed() +{ + VLK_ZoomIn(4); +} + +void Widget::on_btnZoomIn_released() +{ + VLK_StopZoom(); +} + +void Widget::on_btnZoomOut_pressed() +{ + VLK_ZoomOut(4); +} + +void Widget::on_btnZoomOut_released() +{ + VLK_StopZoom(); +} + +void Widget::on_btnGimbalTakePhoto_clicked() +{ + // please make sure there is SD card in the Gimbal + VLK_Photograph(); +} + +void Widget::on_btnStartRecord_clicked() +{ + // please make sure there is SD card in the Gimbal + VLK_SwitchRecord(1); +} + +void Widget::on_btnStopRecord_clicked() +{ + // please make sure there is SD card in the Gimbal + VLK_SwitchRecord(0); +} + +void Widget::on_sliderConfidence_valueChanged(int value) +{ + // 将滑块值转换为0-1之间的浮点数 + m_confidenceThreshold = value / 100.0f; + // 更新显示 + ui->labelConfidenceValue->setText(QString::number(m_confidenceThreshold, 'f', 2)); +} + +void Widget::on_btnIdentifyTarget_clicked() +{ + // 判断是否连接了云台 + if (!VLK_IsTCPConnected() && !VLK_IsSerialPortConnected()) + { + QMessageBox::warning(this, tr("警告"), tr("请先连接云台设备")); + return; + } + + // 创建临时文件目录 + QDir dir("./temp"); + if (!dir.exists()) + { + dir.mkpath("."); + } + + // 生成临时文件路径 + QString tempImagePath = QString("./temp/capture_%1.jpg").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss")); + m_lastCapturedImagePath = tempImagePath; + + // 获取当前视频帧(截屏)而非使用云台拍照 + QMessageBox::information(this, tr("提示"), tr("正在截取当前画面...")); + + // 获取视频显示区域的截图 + QPixmap screenshot = ui->widgetMainVideo->grab(); + if (screenshot.isNull()) + { + QMessageBox::warning(this, tr("警告"), tr("截图失败,请确保视频正在播放")); + return; + } + + // 保存截图到本地 + if (!screenshot.save(tempImagePath, "JPG", 100)) + { + QMessageBox::warning(this, tr("警告"), tr("无法保存截图")); + return; + } + + QMessageBox::information(this, tr("提示"), tr("正在分析图像...")); + + // 加载图像 + if (!m_pImageProcessor->loadImage(tempImagePath.toStdString())) + { + QMessageBox::warning(this, tr("警告"), tr("无法加载图像")); + return; + } + + // 根据预处理复选框决定是否预处理图像 + QString processedImagePath; + if (ui->checkBoxPreprocess->isChecked()) + { + QMessageBox::information(this, tr("提示"), tr("正在预处理图像...增强对比度")); + // 预处理图像 + m_pImageProcessor->preprocessImage(); + + // 保存预处理后的图像 + processedImagePath = QString("./temp/processed_%1.jpg").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss")); + m_pImageProcessor->saveProcessedImage(processedImagePath.toStdString()); + } + else + { + // 不预处理,直接使用原始图像 + processedImagePath = tempImagePath; + } + + // 构建上下文信息 + QString context = buildDetectionContext(); + + // 调用API进行图像识别与距离估计 + try { + // 使用带距离估计的方法 + std::string result = m_pZhipuAPI->identifyObjectsWithDistance( + processedImagePath.toStdString(), + context.toStdString() + ); + + // 解析检测结果 + m_detectedObjects = m_pImageProcessor->parseDetectionResult(result); + + if (m_detectedObjects.empty()) + { + QMessageBox::information(this, tr("结果"), tr("未检测到目标或无法解析坐标")); + return; + } + + // 标记检测到的目标 + m_pImageProcessor->markDetectedObjects(m_detectedObjects, m_confidenceThreshold); + + // 保存标记后的图像 + QString markedImagePath = QString("./temp/marked_%1.jpg").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss")); + if (m_pImageProcessor->saveMarkedImage(markedImagePath.toStdString())) + { + // 显示检测结果 + QString resultMsg = tr("检测到 %1 个目标。\n").arg(m_detectedObjects.size()); + + // 更新距离显示,使用检测到的目标的平均距离 + float avgDistance = 0.0f; + int validCount = 0; + + for (const auto& obj : m_detectedObjects) + { + if (obj.confidence >= m_confidenceThreshold) + { + validCount++; + resultMsg += tr("目标 %1: %2 (置信度: %3)\n").arg(validCount) + .arg(QString::fromStdString(obj.description)) + .arg(obj.confidence, 0, 'f', 2); + + // 如果有距离信息,添加到结果中 + if (obj.distance > 0) { + resultMsg += tr("距离估计: %1米 - %2\n") + .arg(obj.distance, 0, 'f', 1) + .arg(QString::fromStdString(obj.distanceDesc)); + } + + resultMsg += "\n"; + + // 累计距离用于计算平均值 + avgDistance += obj.distance; + } + } + + // 计算平均距离并更新UI + if (validCount > 0 && avgDistance > 0) { + avgDistance /= validCount; + if (m_labelDistanceValue) { + m_labelDistanceValue->setText(tr("%1米").arg(avgDistance, 0, 'f', 1)); + } + } else { + if (m_labelDistanceValue) { + m_labelDistanceValue->setText(tr("未知")); + } + } + + resultMsg += tr("\n已保存标记后的图像: %1").arg(markedImagePath); + + QMessageBox::information(this, tr("识别结果"), resultMsg); + + // 使用图片预览对话框显示标记后的图片 + ImagePreviewDialog *previewDialog = new ImagePreviewDialog(markedImagePath, this); + previewDialog->setAttribute(Qt::WA_DeleteOnClose); // 关闭后自动删除 + previewDialog->show(); + + // 自动保存检测数据 + saveDetectionDataToFile(); + } + else + { + QMessageBox::warning(this, tr("警告"), tr("无法保存标记后的图像")); + } + } + catch (const std::exception& e) + { + QMessageBox::critical(this, tr("错误"), tr("识别过程发生错误: %1").arg(e.what())); + } +} + +void Widget::on_btnClearIdentification_clicked() +{ + // 清除检测结果 + m_detectedObjects.clear(); + + // 删除临时文件 + QDir dir("./temp"); + if (dir.exists()) + { + dir.removeRecursively(); + } + + QMessageBox::information(this, tr("提示"), tr("已清除识别结果和临时文件")); +} + +void Widget::on_checkBoxPreprocess_stateChanged(int state) +{ + // 当预处理复选框状态变化时调用 + if (state == Qt::Checked) + { + // 预处理已开启 + ui->groupBoxIdentify->setTitle(tr("红外智能识别 - 已开启")); + } + else + { + // 预处理已关闭 + ui->groupBoxIdentify->setTitle(tr("红外智能识别 - 已关闭")); + } +} + +// 更新UI状态 +void Widget::updateUIState() +{ + // 根据无人机连接状态更新UI + if (m_isMAVConnected) { + ui->btnConnectUAV->setText("断开"); + + // 根据解锁状态更新按钮文本 + if (m_isUAVArmed) { + ui->btnArmDisarm->setText("上锁"); + } else { + ui->btnArmDisarm->setText("解锁"); + } + + // 启用控制按钮 + ui->btnTakeoff->setEnabled(m_isUAVArmed); + ui->btnLand->setEnabled(m_isUAVArmed); + ui->btnRTL->setEnabled(m_isUAVArmed); + ui->btnMode->setEnabled(true); + ui->comboBoxMode->setEnabled(true); + } else { + ui->btnConnectUAV->setText("连接"); + ui->btnArmDisarm->setText("解锁"); + + // 禁用控制按钮 + ui->btnArmDisarm->setEnabled(false); + ui->btnTakeoff->setEnabled(false); + ui->btnLand->setEnabled(false); + ui->btnRTL->setEnabled(false); + ui->btnMode->setEnabled(false); + ui->comboBoxMode->setEnabled(false); + } + + // 更新声源定位UI状态 + ui->btnStartSoundLocator->setEnabled(!m_isSoundLocatorRunning); + ui->btnStopSoundLocator->setEnabled(m_isSoundLocatorRunning); + ui->lineEditSoundIP->setEnabled(!m_isSoundLocatorRunning); + ui->lineEditSoundPort->setEnabled(!m_isSoundLocatorRunning); +} + +// 修改无人机连接按钮点击 +void Widget::on_btnConnectUAV_clicked() +{ + if (m_mavlinkClient->isConnected()) { + // 断开连接 + m_mavlinkClient->disconnect(); + m_isMAVConnected = false; + QMessageBox::information(this, "断开连接", "已断开与无人机的连接"); + } else { + // 连接无人机 + QString host = ui->lineEditUAVIP->text(); + int port = ui->lineEditUAVPort->text().toInt(); + + if (!m_mavlinkClient->connect(host.toStdString(), port)) { + QMessageBox::warning(this, "连接失败", "无法连接到无人机,请检查IP地址和端口是否正确"); + } + } + + updateUIState(); +} + +// 解锁/上锁按钮点击 +void Widget::on_btnArmDisarm_clicked() +{ + if (!m_mavlinkClient->isConnected()) { + QMessageBox::warning(this, "操作失败", "请先连接无人机"); + return; + } + + // 构造ARM/DISARM命令 + // MAV_CMD_COMPONENT_ARM_DISARM (400) + // 参数1: 0=解锁, 1=上锁 + bool success = sendMavlinkCommand( + 400, // MAV_CMD_COMPONENT_ARM_DISARM + m_isUAVArmed ? 0 : 1, // 参数1: 0=解锁, 1=上锁 + 0, // 参数2: (确认代码, 如果是上锁,则为21196) + 0, 0, 0, 0, 0 // 其他参数未使用 + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", m_isUAVArmed ? "上锁失败" : "解锁失败"); + } + + // 注意:实际的解锁状态会通过心跳消息回调更新 +} + +// 起飞按钮点击 +void Widget::on_btnTakeoff_clicked() +{ + if (!m_mavlinkClient->isConnected() || !m_isUAVArmed) { + QMessageBox::warning(this, "操作失败", "请先连接无人机并解锁"); + return; + } + + // 默认起飞高度为10米,可以使用对话框让用户输入 + bool ok; + float altitude = QInputDialog::getDouble(this, "起飞高度", "请输入起飞高度(米):", + 10.0, 1.0, 100.0, 1, &ok); + if (!ok) return; + + // 构造起飞命令 + // MAV_CMD_NAV_TAKEOFF (22) + bool success = sendMavlinkCommand( + 22, // MAV_CMD_NAV_TAKEOFF + 0, // 参数1: 未使用 + 0, 0, // 参数2-3: 未使用 + float(NAN), // 参数4: 偏航角,NAN表示当前角度 + float(NAN), // 参数5: 纬度,NAN表示当前位置 + float(NAN), // 参数6: 经度,NAN表示当前位置 + altitude // 参数7: 高度(m) + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", "起飞命令发送失败"); + } +} + +// 降落按钮点击 +void Widget::on_btnLand_clicked() +{ + if (!m_mavlinkClient->isConnected() || !m_isUAVArmed) { + QMessageBox::warning(this, "操作失败", "请先连接无人机并解锁"); + return; + } + + // 构造降落命令 + // MAV_CMD_NAV_LAND (21) + bool success = sendMavlinkCommand( + 21, // MAV_CMD_NAV_LAND + 0, // 参数1: 中止高度(已废弃) + 0, // 参数2: 精度设置(0=低精度) + 0, // 参数3: 未使用 + float(NAN), // 参数4: 偏航角,NAN表示当前角度 + float(NAN), // 参数5: 纬度,NAN表示当前位置 + float(NAN), // 参数6: 经度,NAN表示当前位置 + 0 // 参数7: 高度(m),通常为0 + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", "降落命令发送失败"); + } +} + +// 返航按钮点击 +void Widget::on_btnRTL_clicked() +{ + if (!m_mavlinkClient->isConnected() || !m_isUAVArmed) { + QMessageBox::warning(this, "操作失败", "请先连接无人机并解锁"); + return; + } + + // 构造返航命令,使用MAV_CMD_NAV_RETURN_TO_LAUNCH (20) + bool success = sendMavlinkCommand( + 20, // MAV_CMD_NAV_RETURN_TO_LAUNCH + 0, 0, 0, 0, 0, 0, 0 // 所有参数未使用 + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", "返航命令发送失败"); + } +} + +// 切换模式按钮点击 +void Widget::on_btnMode_clicked() +{ + if (!m_mavlinkClient->isConnected()) { + QMessageBox::warning(this, "操作失败", "请先连接无人机"); + return; + } + + int modeIndex = ui->comboBoxMode->currentIndex(); + + // 设置模式命令 + // MAV_CMD_DO_SET_MODE (176) + uint8_t baseMode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED; + uint32_t customMode = 0; + + switch (modeIndex) { + case 0: // 手动模式 + customMode = 0; // MANUAL + break; + case 1: // 稳定模式 + customMode = 2; // STABILIZE + break; + case 2: // 定高模式 + customMode = 3; // ALTITUDE HOLD + break; + case 3: // 定点模式 + customMode = 16; // POSITION + break; + case 4: // 自动模式 + customMode = 3; // AUTO + break; + default: + customMode = 0; // MANUAL + } + + bool success = sendMavlinkCommand( + 176, // MAV_CMD_DO_SET_MODE + baseMode, // 参数1: 基本模式 + customMode, // 参数2: 自定义模式 + 0, 0, 0, 0, 0 // 其他参数未使用 + ); + + if (!success) { + QMessageBox::warning(this, "操作失败", "模式切换失败"); + } +} + +// MAVLink回调处理函数 +void Widget::handleHeartbeat(const mavlink_heartbeat_t& heartbeat) +{ + // 保存心跳信息 + m_heartbeat = heartbeat; + + // 检查解锁状态 + bool armed = (heartbeat.base_mode & MAV_MODE_FLAG_SAFETY_ARMED); + if (m_isUAVArmed != armed) { + m_isUAVArmed = armed; + // 更新UI + QMetaObject::invokeMethod(this, "updateUIState", Qt::QueuedConnection); + } + + // 更新连接状态 + if (!m_isMAVConnected) { + m_isMAVConnected = true; + // 连接建立,请求数据流 + m_mavlinkClient->requestDataStream(); + // 通知UI连接建立 + QMetaObject::invokeMethod(this, [this]() { + updateUIState(); + QMessageBox::information(this, "连接成功", "无人机连接已建立"); + }, Qt::QueuedConnection); + } +} + +void Widget::handleSystemStatus(const mavlink_sys_status_t& status) +{ + // 保存系统状态 + m_sysStatus = status; + + // 更新UI上的电池信息 + QMetaObject::invokeMethod(this, [this]() { + // 转换为电池百分比 + int remaining = m_sysStatus.battery_remaining; + if (remaining < 0) remaining = 0; + + // 更新UI显示 + ui->valueBattery->setText(QString("%1%").arg(remaining)); + }, Qt::QueuedConnection); +} + +void Widget::handleAttitude(const mavlink_attitude_t& attitude) +{ + // 保存姿态信息 + m_attitude = attitude; + + // 将弧度转换为角度 + float roll = attitude.roll * 180.0f / M_PI; + float pitch = attitude.pitch * 180.0f / M_PI; + float yaw = attitude.yaw * 180.0f / M_PI; + + // 更新UI上的姿态信息 + QMetaObject::invokeMethod(this, [this, roll, pitch, yaw]() { + ui->valueRoll->setText(QString("%1°").arg(roll, 0, 'f', 1)); + ui->valuePitch->setText(QString("%1°").arg(pitch, 0, 'f', 1)); + ui->valueHeading->setText(QString("%1°").arg(yaw, 0, 'f', 1)); + }, Qt::QueuedConnection); +} + +void Widget::handlePosition(const mavlink_global_position_int_t& position) +{ + // 保存位置信息 + m_position = position; + + // 转换高度单位为米 + float altitude = position.alt / 1000.0f; + float relativeAltitude = position.relative_alt / 1000.0f; + + // 计算地速(米/秒) + float groundSpeed = sqrtf(powf(position.vx / 100.0f, 2) + powf(position.vy / 100.0f, 2)); + + // 转换为QGeoCoordinate + QGeoCoordinate pos(position.lat / 1.0e7, position.lon / 1.0e7, altitude); + + // 更新UI上的位置信息 + QMetaObject::invokeMethod(this, [this, altitude, relativeAltitude, groundSpeed, pos]() { + ui->valueAltitude->setText(QString("%1 m").arg(relativeAltitude, 0, 'f', 1)); + ui->valueSpeed->setText(QString("%1 m/s").arg(groundSpeed, 0, 'f', 1)); + + // 更新地图位置 + m_mapWidget->setUAVPosition(pos); + }, Qt::QueuedConnection); +} + +// 发送MAVLink命令 +bool Widget::sendMavlinkCommand(uint16_t command, float param1, float param2, + float param3, float param4, float param5, + float param6, float param7) +{ + if (!m_mavlinkClient || !m_mavlinkClient->isConnected()) { + return false; + } + + // 调用MAVLinkClient类的sendCommand方法发送命令 + return m_mavlinkClient->sendCommand(command, param1, param2, param3, param4, param5, param6, param7); +} + +// 实现地图类型切换槽函数 +void Widget::on_btnSwitchMapType_clicked() +{ + if (!m_mapWidget) { + qWarning() << "地图组件未初始化"; + return; + } + + try { + m_mapWidget->toggleMapType(); + + // 更新按钮文本 + QPushButton *btn = qobject_cast(sender()); + if (btn) { + if (m_mapWidget->getCurrentMapType() == "normal") { + btn->setText("切换卫星地图"); + } else { + btn->setText("切换普通地图"); + } + } else { + qWarning() << "无法找到发送信号的按钮"; + } + } catch (const std::exception &e) { + qWarning() << "切换地图类型异常:" << e.what(); + } catch (...) { + qWarning() << "切换地图类型未知异常"; + } +} + +void Widget::on_btnStartSoundLocator_clicked() +{ + // 获取IP和端口 + m_soundLocatorIP = ui->lineEditSoundIP->text().trimmed(); + m_soundLocatorPort = ui->lineEditSoundPort->text().toInt(); + + // 确保IP不为空且端口有效 + if (m_soundLocatorIP.isEmpty() || m_soundLocatorPort <= 0 || m_soundLocatorPort > 65535) + { + ui->textEditSoundLog->append("错误:无效的IP地址或端口"); + return; + } + + // 开始定时请求数据 + m_isSoundLocatorRunning = true; + ui->btnStartSoundLocator->setEnabled(false); + ui->btnStopSoundLocator->setEnabled(true); + ui->lineEditSoundIP->setEnabled(false); + ui->lineEditSoundPort->setEnabled(false); + + ui->textEditSoundLog->append("开始监听声源定位数据..."); + + // 立即获取一次数据 + fetchSoundLocatorData(); + + // 启动定时器 + m_soundDataTimer->start(500); // 每500毫秒获取一次数据 +} + +void Widget::on_btnStopSoundLocator_clicked() +{ + // 停止定时器 + m_soundDataTimer->stop(); + m_isSoundLocatorRunning = false; + + ui->btnStartSoundLocator->setEnabled(true); + ui->btnStopSoundLocator->setEnabled(false); + ui->lineEditSoundIP->setEnabled(true); + ui->lineEditSoundPort->setEnabled(true); + + ui->textEditSoundLog->append("停止监听声源定位数据"); +} + +void Widget::fetchSoundLocatorData() +{ + // 构造请求URL + QString url = QString("http://%1:%2/data").arg(m_soundLocatorIP).arg(m_soundLocatorPort); + + QNetworkRequest request; + request.setUrl(QUrl(url)); + + // 发送GET请求 + QNetworkReply *reply = m_soundNetworkManager->get(request); + + // 使用lambda处理响应 + connect(reply, &QNetworkReply::finished, [this, reply]() { + reply->deleteLater(); + + if (reply->error() == QNetworkReply::NoError) { + // 读取响应数据 + QByteArray responseData = reply->readAll(); + + // 解析JSON + QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData); + if (!jsonDoc.isNull() && jsonDoc.isObject()) { + QJsonObject jsonObj = jsonDoc.object(); + + // 提取声源数据 + double x = jsonObj["X"].toDouble(); + double y = jsonObj[ \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.h new file mode 100644 index 0000000..a6ebe8b --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.h @@ -0,0 +1,756 @@ +#ifndef WIDGET_H +#define WIDGET_H + +/** + * @brief Qt核心组件 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief 网络通信相关头文件 + */ +#include +#include +#include +#include + +/** + * @brief 项目自定义组件 + */ +#include "ViewLink.h" +#include "VideoObjNetwork.h" +#include "VideoObjUSBCamera.h" +#include "../identification system/src/image_processor.h" +#include "../identification system/src/zhipu_api.h" + +// 替换无人机连接类,使用workproject下的MAVLinkClient +#include "../workproject/include/mavlink_client.h" +#include "MapWidget.h" + +namespace Ui { +class Widget; +} + +/** + * @brief 主窗口Widget类 + * + * 基于多模态的战场隐蔽威胁发现和定位系统的主界面类。 + * 集成视频显示、目标识别、无人机控制、声源定位、地图显示等功能模块。 + * + * 主要功能包括: + * - 视频流显示(网络视频和USB摄像头) + * - 目标识别和威胁分析 + * - 无人机飞行控制(MAVLink协议) + * - 声源定位和可视化 + * - 地图显示和目标标记 + * - TCP移动控制 + * - 遥测数据显示 + */ +class Widget : public QWidget +{ + Q_OBJECT + +public: + /** + * @brief 构造函数 + * @param parent 父窗口指针 + */ + explicit Widget(QWidget *parent = 0); + + /** + * @brief 析构函数 + */ + ~Widget(); + +private slots: + /** + * @brief TCP连接按钮点击事件 + */ + void on_btnConnectTCP_clicked(); + + /** + * @brief 串口连接按钮点击事件 + */ + void on_btnConnctSerialPort_clicked(); + +private: + /** + * @brief VLK连接状态回调函数 + * @param iConnStatus 连接状态 + * @param szMessage 状态消息 + * @param iMsgLen 消息长度 + * @param pUserParam 用户参数 + * @return 回调结果 + */ + static int VLK_ConnStatusCallback(int iConnStatus, const char* szMessage, int iMsgLen, void* pUserParam); + + /** + * @brief VLK设备状态回调函数 + * @param iType 状态类型 + * @param szBuffer 状态数据 + * @param iBufLen 数据长度 + * @param pUserParam 用户参数 + * @return 回调结果 + */ + static int VLK_DevStatusCallback(int iType, const char* szBuffer, int iBufLen, void* pUserParam); + +signals: + /** + * @brief 连接状态信号 + * @param iConnStatus 连接状态 + * @param strMessage 状态消息 + */ + void SignalConnectionStatus(int iConnStatus, const QString& strMessage); + + /** + * @brief 设备型号信号 + * @param model 设备型号 + */ + void SignalDeviceModel(VLK_DEV_MODEL model); + + /** + * @brief 设备配置信号 + * @param config 设备配置 + */ + void SignalDeviceConfig(VLK_DEV_CONFIG config); + + /** + * @brief 设备遥测信号 + * @param telemetry 遥测数据 + */ + void SignalDeviceTelemetry(VLK_DEV_TELEMETRY telemetry); + +private slots: + /** + * @brief 连接状态槽函数 + * @param iConnStatus 连接状态 + * @param strMessage 状态消息 + */ + void onSlotConnectionStatus(int iConnStatus, const QString& strMessage); + + /** + * @brief 设备型号槽函数 + * @param model 设备型号 + */ + void onSlotDeviceModel(VLK_DEV_MODEL model); + + /** + * @brief 设备配置槽函数 + * @param config 设备配置 + */ + void onSlotDeviceConfig(VLK_DEV_CONFIG config); + + /** + * @brief 设备遥测槽函数 + * @param telemetry 遥测数据 + */ + void onSlotDeviceTelemetry(VLK_DEV_TELEMETRY telemetry); + + /** + * @brief 向上按钮按下事件 + */ + void on_btnUp_pressed(); + + /** + * @brief 向上按钮释放事件 + */ + void on_btnUp_released(); + + /** + * @brief 向左按钮按下事件 + */ + void on_btnLeft_pressed(); + + /** + * @brief 向左按钮释放事件 + */ + void on_btnLeft_released(); + + /** + * @brief 回中按钮点击事件 + */ + void on_btnHome_clicked(); + + /** + * @brief 向右按钮按下事件 + */ + void on_btnRight_pressed(); + + /** + * @brief 向右按钮释放事件 + */ + void on_btnRight_released(); + + /** + * @brief 向下按钮按下事件 + */ + void on_btnDown_pressed(); + + /** + * @brief 向下按钮释放事件 + */ + void on_btnDown_released(); + + /** + * @brief 图像传感器选择事件 + * @param index 选择的索引 + */ + void on_cmbImageSensor_activated(int index); + + /** + * @brief 红外彩色选择事件 + * @param index 选择的索引 + */ + void on_cmbIRColor_activated(int index); + + /** + * @brief 画中画复选框点击事件 + * @param checked 是否选中 + */ + void on_checkBoxPIP_clicked(bool checked); + + /** + * @brief 打开网络视频按钮点击事件 + */ + void on_btnOpenNetworkVideo_clicked(); + + /** + * @brief 打开USB视频按钮点击事件 + */ + void on_btnOpenUSBVideo_clicked(); + + /** + * @brief 放大按钮按下事件 + */ + void on_btnZoomIn_pressed(); + + /** + * @brief 放大按钮释放事件 + */ + void on_btnZoomIn_released(); + + /** + * @brief 缩小按钮按下事件 + */ + void on_btnZoomOut_pressed(); + + /** + * @brief 缩小按钮释放事件 + */ + void on_btnZoomOut_released(); + + /** + * @brief 云台拍照按钮点击事件 + */ + void on_btnGimbalTakePhoto_clicked(); + + /** + * @brief 开始录制按钮点击事件 + */ + void on_btnStartRecord_clicked(); + + /** + * @brief 停止录制按钮点击事件 + */ + void on_btnStopRecord_clicked(); + + /** + * @brief 识别目标按钮点击事件 + */ + void on_btnIdentifyTarget_clicked(); + + /** + * @brief 清除识别按钮点击事件 + */ + void on_btnClearIdentification_clicked(); + + /** + * @brief 置信度滑块值改变事件 + * @param value 新的置信度值 + */ + void on_sliderConfidence_valueChanged(int value); + + // 添加预处理复选框状态变化的槽函数 + void on_checkBoxPreprocess_stateChanged(int state); + + // 无人机控制相关槽函数 + /** + * @brief 连接无人机按钮点击事件 + */ + void on_btnConnectUAV_clicked(); + + /** + * @brief 解锁/锁定按钮点击事件 + */ + void on_btnArmDisarm_clicked(); + + /** + * @brief 起飞按钮点击事件 + */ + void on_btnTakeoff_clicked(); + + /** + * @brief 降落按钮点击事件 + */ + void on_btnLand_clicked(); + + /** + * @brief 返航按钮点击事件 + */ + void on_btnRTL_clicked(); + + /** + * @brief 模式切换按钮点击事件 + */ + void on_btnMode_clicked(); + + // 添加切换地图类型的槽函数 + /** + * @brief 切换地图类型按钮点击事件 + */ + void on_btnSwitchMapType_clicked(); + + // 添加声源定位相关槽函数 + /** + * @brief 开始声源定位按钮点击事件 + */ + void on_btnStartSoundLocator_clicked(); + + /** + * @brief 停止声源定位按钮点击事件 + */ + void on_btnStopSoundLocator_clicked(); + + /** + * @brief 声源数据接收事件 + */ + void onSoundDataReceived(); + + /** + * @brief 更新声源可视化 + * @param x X坐标 + * @param y Y坐标 + * @param strength 强度 + * @param angle 角度 + */ + void updateSoundVisualization(double x, double y, double strength, double angle); + + // 添加显示目标在地图上的槽函数 + /** + * @brief 在地图上显示目标按钮点击事件 + */ + void on_btnShowTargetsOnMap_clicked(); + +private: + /** + * @brief 初始化UI控件 + */ + void InitUI(); + + /** + * @brief 初始化TCP连接 + */ + void initTcpConnect(); + + /** + * @brief 初始化串口连接 + */ + void initSerialConnect(); + + /** + * @brief 更新UI状态 + */ + void updateUIState(); + + /** + * @brief 保存检测到的目标和距离数据到文件 + */ + void saveDetectionDataToFile(); + + /** + * @brief 构建发送给大模型的上下文信息 + * @return 上下文信息字符串 + */ + QString buildDetectionContext(); + + // MAVLink回调函数 + /** + * @brief 处理心跳包 + * @param heartbeat 心跳数据 + */ + void handleHeartbeat(const mavlink_heartbeat_t& heartbeat); + + /** + * @brief 处理系统状态 + * @param status 系统状态数据 + */ + void handleSystemStatus(const mavlink_sys_status_t& status); + + /** + * @brief 处理姿态数据 + * @param attitude 姿态数据 + */ + void handleAttitude(const mavlink_attitude_t& attitude); + + /** + * @brief 处理位置数据 + * @param position 位置数据 + */ + void handlePosition(const mavlink_global_position_int_t& position); + + /** + * @brief 处理GPS数据 + * @param gps GPS数据 + */ + void handleGPS(const mavlink_gps_raw_int_t& gps); + + /** + * @brief 发送MAVLink命令 + * @param command 命令ID + * @param param1-7 命令参数 + * @return 发送是否成功 + */ + bool sendMavlinkCommand(uint16_t command, float param1 = 0, float param2 = 0, + float param3 = 0, float param4 = 0, float param5 = 0, + float param6 = 0, float param7 = 0); + + // 声源定位相关方法 + /** + * @brief 获取声源定位数据 + */ + void fetchSoundLocatorData(); + + /** + * @brief 初始化声源可视化 + */ + void initSoundVisualization(); + + /** + * @brief 计算目标地理位置 + * @param distance 距离 + * @param gimbalYaw 云台偏航角 + * @param gimbalPitch 云台俯仰角 + * @return 目标地理位置 + */ + QGeoCoordinate calculateTargetPosition(double distance, double gimbalYaw, double gimbalPitch); + + /** + * @brief 在地图上显示检测到的目标 + */ + void showDetectedTargetsOnMap(); + + /** + * @brief 添加单个目标到地图 + * @param target 检测到的目标 + */ + void addTargetToMap(const DetectedObject& target); + + /** + * @brief 计算目标位置估计的不确定性 + * @param distance 距离 + * @return 不确定性(米) + */ + double calculateUncertainty(double distance); + + // TCP控制相关方法 + /** + * @brief 连接到移动控制TCP服务器 + * @return 连接是否成功 + */ + bool connectToMoveControlTCP(); + + /** + * @brief 断开移动控制TCP连接 + */ + void disconnectFromMoveControlTCP(); + + /** + * @brief 发送移动命令 + * @param x X方向移动量 + * @param y Y方向移动量 + * @return 发送是否成功 + */ + bool sendMoveCommand(double x, double y); + + /** + * @brief 向声源方向移动 + * @param angle 声源角度 + */ + void moveTowardSoundSource(double angle); + +private: + /** + * @brief UI界面指针 + */ + Ui::Widget *ui; + + /** + * @brief 网络视频对象 + */ + CVideoObjNetwork m_VideoObjNetwork; + + /** + * @brief USB摄像头对象 + */ + CVideoObjUSBCamera m_VideoObjUSBCamera; + + /** + * @brief 图像处理器指针 + */ + ImageProcessor* m_pImageProcessor; + + /** + * @brief 智谱API指针 + */ + ZhipuAPI* m_pZhipuAPI; + + /** + * @brief 检测到的目标列表 + */ + std::vector m_detectedObjects; + + /** + * @brief 最后捕获的图像路径 + */ + QString m_lastCapturedImagePath; + + /** + * @brief 置信度阈值 + */ + float m_confidenceThreshold; + + // 目标距离相关成员 + /** + * @brief 距离值显示标签 + */ + QLabel* m_labelDistanceValue; + + /** + * @brief 检测日志文件路径 + */ + QString m_detectionLogFile; + + /** + * @brief 最后检测时间 + */ + QString m_lastDetectionTime; + + /** + * @brief 最后激光距离 + */ + float m_lastLaserDistance; + + /** + * @brief 距离估计是否启用 + */ + bool m_distanceEstimationEnabled; + + // 地图目标标记相关成员 + /** + * @brief 目标是否已显示在地图上 + */ + bool m_targetsOnMap; + + /** + * @brief 上次吊舱偏航角 + */ + double m_lastGimbalYaw; + + /** + * @brief 上次吊舱俯仰角 + */ + double m_lastGimbalPitch; + + /** + * @brief 显示目标按钮 + */ + QPushButton* m_btnShowTargetsOnMap; + + // 替换为MAVLinkClient + /** + * @brief MAVLink客户端指针 + */ + MAVLinkClient *m_mavlinkClient; + + /** + * @brief 地图组件指针 + */ + MapWidget *m_mapWidget; + + /** + * @brief 无人机是否已解锁 + */ + bool m_isUAVArmed; + + // 保存当前飞行数据 + /** + * @brief 心跳数据 + */ + mavlink_heartbeat_t m_heartbeat; + + /** + * @brief 系统状态数据 + */ + mavlink_sys_status_t m_sysStatus; + + /** + * @brief 姿态数据 + */ + mavlink_attitude_t m_attitude; + + /** + * @brief 位置数据 + */ + mavlink_global_position_int_t m_position; + + /** + * @brief GPS数据 + */ + mavlink_gps_raw_int_t m_gps; + + /** + * @brief MAVLink是否已连接 + */ + bool m_isMAVConnected; + + // 声音定位相关成员 + /** + * @brief 声源网络管理器 + */ + QNetworkAccessManager* m_soundNetworkManager; + + /** + * @brief 声源数据定时器 + */ + QTimer* m_soundDataTimer; + + /** + * @brief 声源定位是否正在运行 + */ + bool m_isSoundLocatorRunning; + + /** + * @brief 声源定位器IP地址 + */ + QString m_soundLocatorIP; + + /** + * @brief 声源定位器端口 + */ + int m_soundLocatorPort; + + /** + * @brief 声源可视化场景 + */ + QGraphicsScene* m_soundScene; + + /** + * @brief 声源可视化视图 + */ + QGraphicsView* m_soundView; + + /** + * @brief 声源位置图形项 + */ + QGraphicsEllipseItem* m_soundSourceItem; + + /** + * @brief 声源方向线图形项 + */ + QGraphicsLineItem* m_soundDirectionLine; + + /** + * @brief 声源信息文本图形项 + */ + QGraphicsTextItem* m_soundInfoText; + + /** + * @brief 声源检测器图形项 + */ + QGraphicsEllipseItem* m_soundDetectorItem; + + /** + * @brief 声源X坐标 + */ + double m_soundX; + + /** + * @brief 声源Y坐标 + */ + double m_soundY; + + /** + * @brief 声源强度 + */ + double m_soundStrength; + + /** + * @brief 声源角度 + */ + double m_soundAngle; + + // TCP移动控制相关成员 + /** + * @brief 移动控制套接字 + */ + int m_moveControlSocket; + + /** + * @brief 移动控制地址结构 + */ + struct sockaddr_in m_moveControlAddr; + + /** + * @brief 移动控制是否已连接 + */ + bool m_moveControlConnected; + + /** + * @brief 移动控制IP地址 + */ + QString m_moveControlIP; + + /** + * @brief 移动控制端口 + */ + int m_moveControlPort; + + /** + * @brief 上次声音是否已处理 + */ + bool m_lastSoundProcessed; + + // GPS状态标签 + /** + * @brief GPS值显示标签 + */ + QLabel* m_labelGPSValue; + + /** + * @brief 卫星数量显示标签 + */ + QLabel* m_labelSatellitesValue; + + /** + * @brief HDOP值显示标签 + */ + QLabel* m_labelHDOPValue; + + /** + * @brief VDOP值显示标签 + */ + QLabel* m_labelVDOPValue; +}; + +#endif // WIDGET_H diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.ui b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.ui new file mode 100644 index 0000000..3819305 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget.ui @@ -0,0 +1,1511 @@ + + + Widget + + + + 0 + 0 + 1600 + 900 + + + + 无人机与摄像头控制 + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + 连接设置 + + + + 16777215 + 200 + + + + + 10 + 75 + true + + + + QGroupBox { + border: 1px solid #8f8f8f; + border-radius: 5px; + margin-top: 1ex; + background-color: #f5f5f5; +} +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + padding: 0 3px; + background-color: #f5f5f5; +} + + + + + 10 + + + 10 + + + 10 + + + 10 + + + 10 + + + + + 摄像头连接 + + + + 9 + 75 + true + + + + + 8 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + 12 + + + + + + + TCP地址: + + + + + + + true + + + + + + + 端口: + + + + + + + + + + 连接 + + + + + + + + + + + 串口: + + + + + + + false + + + + + + + 波特率: + + + + + + + + + + 连接 + + + + + + + + + + + 12 + + + + + + + 网络视频源: + + + + + + + true + + + + + + + 开启 + + + + + + + + + + + USB摄像头: + + + + + + + + + + 开启 + + + + + + + + + + + + + + 无人机连接 + + + + 9 + 75 + true + + + + + 10 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + 无人机IP: + + + + + + + 127.0.0.1 + + + + + + + 端口: + + + + + + + 14550 + + + + + + + 连接 + + + + + + + + + + + + + + + + 1 + 0 + + + + + 5 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 280 + 0 + + + + + 280 + 16777215 + + + + + 8 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + 云台控制 + + + + 9 + 75 + true + + + + QGroupBox { + border: 1px solid #8f8f8f; + border-radius: 5px; + margin-top: 1ex; +} +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + padding: 0 3px; +} +QPushButton { + font-size: 8pt; + font-weight: normal; + padding: 2px; +} +QLabel { + font-size: 8pt; + font-weight: normal; +} +QComboBox { + font-size: 8pt; + font-weight: normal; +} + + + + + 8 + + + 8 + + + 8 + + + 8 + + + 8 + + + + + + + 速度 + + + + + + + 1 + + + 20 + + + 1 + + + 10 + + + Qt::Horizontal + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 向上 + + + + 80 + 25 + + + + QPushButton { + background-color: #e6f2ff; + border: 1px solid #99c2ff; + border-radius: 4px; +} +QPushButton:hover { + background-color: #cce6ff; +} +QPushButton:pressed { + background-color: #99c2ff; +} + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 向左 + + + + 70 + 25 + + + + QPushButton { + background-color: #e6f2ff; + border: 1px solid #99c2ff; + border-radius: 4px; +} +QPushButton:hover { + background-color: #cce6ff; +} +QPushButton:pressed { + background-color: #99c2ff; +} + + + + + + + 回正 + + + + 70 + 25 + + + + QPushButton { + background-color: #fffae6; + border: 1px solid #ffd480; + border-radius: 4px; +} +QPushButton:hover { + background-color: #fff5cc; +} +QPushButton:pressed { + background-color: #ffd480; +} + + + + + + + 向右 + + + + 70 + 25 + + + + QPushButton { + background-color: #e6f2ff; + border: 1px solid #99c2ff; + border-radius: 4px; +} +QPushButton:hover { + background-color: #cce6ff; +} +QPushButton:pressed { + background-color: #99c2ff; +} + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 向下 + + + + 80 + 25 + + + + QPushButton { + background-color: #e6f2ff; + border: 1px solid #99c2ff; + border-radius: 4px; +} +QPushButton:hover { + background-color: #cce6ff; +} +QPushButton:pressed { + background-color: #99c2ff; +} + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 图像传感器: + + + + + + + + + + + + + + 红外色彩: + + + + + + + + + + PIP + + + + + + + + + + + 放大 + + + + + + + 缩小 + + + + + + + + + 云台拍照 + + + + 0 + 25 + + + + + + + + + + 开始录像 + + + + + + + 停止录像 + + + + + + + + + + + + 智能识别 + + + + 9 + 75 + true + + + + QGroupBox { + border: 1px solid #8f8f8f; + border-radius: 5px; + margin-top: 1ex; +} +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + padding: 0 3px; +} +QPushButton { + font-size: 8pt; + font-weight: normal; + padding: 2px; +} +QLabel { + font-size: 8pt; + font-weight: normal; +} +QCheckBox { + font-size: 8pt; + font-weight: normal; +} + + + + + 8 + + + 8 + + + 8 + + + 8 + + + 8 + + + + + 智能识别功能: + + + Qt::AlignCenter + + + + + + + 识别置信度阈值: + + + Qt::AlignCenter + + + + 9 + 75 + true + + + + + + + + + + 0 + + + 100 + + + 70 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + + + + 0.7 + + + + 30 + 0 + + + + + + + + + + 预处理图像(增强对比度) + + + true + + + + + + + 目标识别 + + + + 0 + 25 + + + + QPushButton { + background-color: #e6f2ff; + border: 1px solid #99c2ff; + border-radius: 4px; +} +QPushButton:hover { + background-color: #cce6ff; +} +QPushButton:pressed { + background-color: #99c2ff; +} + + + + + + + 清除识别结果 + + + + 0 + 25 + + + + QPushButton { + background-color: #ffe6e6; + border: 1px solid #ffb3b3; + border-radius: 4px; +} +QPushButton:hover { + background-color: #ffcccc; + background-color: #ffb3b3; +} + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + 16777215 + 40 + + + + + 5 + + + 5 + + + 2 + + + 5 + + + 2 + + + + + 偏航角: + + + + + + + 0.00 + + + + + + + 俯仰角: + + + + + + + 0.00 + + + + + + + 目标纬度: + + + + + + + 0.00 + + + + + + + 目标经度: + + + + + + + 0.00 + + + + + + + 目标高度: + + + + + + + 0.00 + + + + + + + 变焦倍率: + + + + + + + 0.00 + + + + + + + + + + + + + + + + 1 + 0 + + + + + 5 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 无人机控制 + + + + 9 + 75 + true + + + + QGroupBox { + border: 1px solid #8f8f8f; + border-radius: 5px; + margin-top: 1ex; +} +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + padding: 0 3px; +} +QPushButton { + font-size: 8pt; + font-weight: normal; + padding: 2px; +} +QComboBox { + font-size: 8pt; + font-weight: normal; +} + + + + + + + 解锁 + + + + + + + 起飞 + + + + + + + 降落 + + + + + + + 返航 + + + + + + + + 手动模式 + + + + + 稳定模式 + + + + + 定高模式 + + + + + 定点模式 + + + + + 自动模式 + + + + + + + + 切换模式 + + + + + + + + + + 飞行状态 + + + + 16777215 + 150 + + + + + 9 + 75 + true + + + + QGroupBox { + border: 1px solid #8f8f8f; + border-radius: 5px; + margin-top: 1ex; + background-color: #f0f8ff; +} +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + padding: 0 3px; + background-color: #f0f8ff; +} +QLabel { + font-weight: normal; + font-size: 9pt; +} + + + + + 8 + + + 8 + + + + + 高度: + + + + + + + 0.0 m + + + + + + + 速度: + + + + + + + 0.0 m/s + + + + + + + 翻滚: + + + + + + + 0.0° + + + + + + + 俯仰: + + + + + + + 0.0° + + + + + + + 航向: + + + + + + + 0.0° + + + + + + + 电量: + + + + + + + 0% + + + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + 声源定位 + + + + 16777215 + 250 + + + + + 9 + 75 + true + + + + QGroupBox { + border: 1px solid #8f8f8f; + border-radius: 5px; + margin-top: 1ex; +} +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + padding: 0 3px; +} +QPushButton { + font-size: 8pt; + font-weight: normal; + padding: 2px; +} +QLabel { + font-size: 8pt; + font-weight: normal; +} +QLineEdit { + font-size: 8pt; + font-weight: normal; +} +QTextEdit { + font-size: 8pt; + font-weight: normal; +} + + + + + 10 + + + 10 + + + + + 5 + + + + + 5 + + + 5 + + + + + 声源定位服务IP: + + + + + + + 127.0.0.1 + + + + + + + 端口: + + + + + + + 5000 + + + + + + + + + + + 开始监听 + + + + + + + 停止监听 + + + false + + + + + + + + + + 300 + 100 + + + + + 16777215 + 150 + + + + true + + + 声源定位日志... + + + + + + + + + + 400 + 200 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + + + + VLKVideoWidget + QWidget +
VLKVideoWidget.h
+ 1 +
+
+ + +
diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget_new.ui.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget_new.ui.h new file mode 100644 index 0000000..f27af0d --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/demo_for_qt/widget_new.ui.h @@ -0,0 +1,1259 @@ +/******************************************************************************** +** Form generated from reading UI file 'widget.ui' +** +** Created by: Qt User Interface Compiler version 5.15.3 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef WIDGET_NEW_H +#define WIDGET_NEW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "VLKVideoWidget.h" + +QT_BEGIN_NAMESPACE + +class Ui_Widget +{ +public: + QVBoxLayout *verticalLayout_main; + QGroupBox *groupBoxConnect; + QHBoxLayout *horizontalLayout_connect; + QGroupBox *groupBoxCameraConnect; + QVBoxLayout *verticalLayout_cameraConnect; + QHBoxLayout *horizontalLayout_deviceConnect; + QHBoxLayout *horizontalLayout_tcp; + QLabel *label; + QComboBox *cmbIPAddr; + QLabel *label_3; + QLineEdit *lineEditPort; + QPushButton *btnConnectTCP; + QHBoxLayout *horizontalLayout_serial; + QLabel *label_2; + QComboBox *cmbSerialPort; + QLabel *label_4; + QLineEdit *lineEditBaudrate; + QPushButton *btnConnctSerialPort; + QHBoxLayout *horizontalLayout_videoConnect; + QHBoxLayout *horizontalLayout_networkVideo; + QLabel *label_5; + QComboBox *cmbNetworkVideoURL; + QPushButton *btnOpenNetworkVideo; + QHBoxLayout *horizontalLayout_usbVideo; + QLabel *label_6; + QComboBox *cmbUSBCamera; + QPushButton *btnOpenUSBVideo; + QGroupBox *groupBoxUAVConnect; + QHBoxLayout *horizontalLayout_15; + QLabel *labelUAVIP; + QLineEdit *lineEditUAVIP; + QLabel *labelUAVPort; + QLineEdit *lineEditUAVPort; + QPushButton *btnConnectUAV; + QHBoxLayout *horizontalLayout_main; + QWidget *widgetCameraControl; + QHBoxLayout *horizontalLayout_camera; + QWidget *widgetCameraControls; + QVBoxLayout *verticalLayout_cameraControls; + QGroupBox *groupBoxCameraControl; + QVBoxLayout *verticalLayout_gimbal; + QHBoxLayout *horizontalLayout_10; + QLabel *label_10; + QSlider *SliderMoveSpeed; + QHBoxLayout *horizontalLayout_4; + QSpacerItem *horizontalSpacer; + QPushButton *btnUp; + QSpacerItem *horizontalSpacer_2; + QHBoxLayout *horizontalLayout_5; + QPushButton *btnLeft; + QPushButton *btnHome; + QPushButton *btnRight; + QHBoxLayout *horizontalLayout_6; + QSpacerItem *horizontalSpacer_3; + QPushButton *btnDown; + QSpacerItem *horizontalSpacer_4; + QHBoxLayout *horizontalLayout_7; + QLabel *label_7; + QComboBox *cmbImageSensor; + QHBoxLayout *horizontalLayout_8; + QLabel *label_8; + QComboBox *cmbIRColor; + QCheckBox *checkBoxPIP; + QHBoxLayout *horizontalLayout_12; + QPushButton *btnZoomIn; + QPushButton *btnZoomOut; + QPushButton *btnGimbalTakePhoto; + QHBoxLayout *horizontalLayout_11; + QPushButton *btnStartRecord; + QPushButton *btnStopRecord; + QGroupBox *groupBoxIdentify; + QVBoxLayout *verticalLayout_identify; + QLabel *labelIRIdentification; + QLabel *labelConfidence; + QHBoxLayout *horizontalLayout_confidenceSlider; + QSlider *sliderConfidence; + QLabel *labelConfidenceValue; + QCheckBox *checkBoxPreprocess; + QPushButton *btnIdentifyTarget; + QPushButton *btnClearIdentification; + QSpacerItem *verticalSpacer; + QVBoxLayout *verticalLayout_video; + VLKVideoWidget *widgetMainVideo; + QWidget *widgetDevStatus; + QHBoxLayout *horizontalLayout_9; + QLabel *label_9; + QLabel *lbYaw; + QLabel *label_13; + QLabel *lbPitch; + QLabel *label_11; + QLabel *lbTargetLat; + QLabel *label_15; + QLabel *lbTargetLng; + QLabel *label_17; + QLabel *lbTargetAlt; + QLabel *label_19; + QLabel *lbZoom; + QWidget *widgetUAVControl; + QVBoxLayout *verticalLayout_uav; + QGroupBox *groupBoxUAVControl; + QHBoxLayout *horizontalLayout_16; + QPushButton *btnArmDisarm; + QPushButton *btnTakeoff; + QPushButton *btnLand; + QPushButton *btnRTL; + QComboBox *comboBoxMode; + QPushButton *btnMode; + QGroupBox *groupBoxStatus; + QGridLayout *gridLayout; + QLabel *labelAltitude; + QLabel *valueAltitude; + QLabel *labelSpeed; + QLabel *valueSpeed; + QLabel *labelRoll; + QLabel *valueRoll; + QLabel *labelPitch; + QLabel *valuePitch; + QLabel *labelHeading; + QLabel *valueHeading; + QLabel *labelBattery; + QLabel *valueBattery; + QFrame *frameMap; + QVBoxLayout *layoutMap; + QGroupBox *groupBoxSoundLocator; + QHBoxLayout *horizontalLayout_20; + QVBoxLayout *verticalLayout_15; + QGridLayout *gridLayout_2; + QLabel *labelSoundIP; + QLineEdit *lineEditSoundIP; + QLabel *labelSoundPort; + QLineEdit *lineEditSoundPort; + QHBoxLayout *horizontalLayout_18; + QPushButton *btnStartSoundLocator; + QPushButton *btnStopSoundLocator; + QTextEdit *textEditSoundLog; + QFrame *frameSoundVisualization; + QVBoxLayout *layoutSoundVisualization; + + void setupUi(QWidget *Widget) + { + if (Widget->objectName().isEmpty()) + Widget->setObjectName(QString::fromUtf8("Widget")); + Widget->resize(1600, 900); + verticalLayout_main = new QVBoxLayout(Widget); + verticalLayout_main->setSpacing(5); + verticalLayout_main->setContentsMargins(11, 11, 11, 11); + verticalLayout_main->setObjectName(QString::fromUtf8("verticalLayout_main")); + verticalLayout_main->setContentsMargins(5, 5, 5, 5); + groupBoxConnect = new QGroupBox(Widget); + groupBoxConnect->setObjectName(QString::fromUtf8("groupBoxConnect")); + groupBoxConnect->setMaximumSize(QSize(16777215, 200)); + QFont font; + font.setPointSize(10); + font.setBold(true); + font.setWeight(75); + groupBoxConnect->setFont(font); + horizontalLayout_connect = new QHBoxLayout(groupBoxConnect); + horizontalLayout_connect->setSpacing(10); + horizontalLayout_connect->setContentsMargins(11, 11, 11, 11); + horizontalLayout_connect->setObjectName(QString::fromUtf8("horizontalLayout_connect")); + horizontalLayout_connect->setContentsMargins(10, 10, 10, 10); + groupBoxCameraConnect = new QGroupBox(groupBoxConnect); + groupBoxCameraConnect->setObjectName(QString::fromUtf8("groupBoxCameraConnect")); + QFont font1; + font1.setPointSize(9); + font1.setBold(true); + font1.setWeight(75); + groupBoxCameraConnect->setFont(font1); + verticalLayout_cameraConnect = new QVBoxLayout(groupBoxCameraConnect); + verticalLayout_cameraConnect->setSpacing(8); + verticalLayout_cameraConnect->setContentsMargins(11, 11, 11, 11); + verticalLayout_cameraConnect->setObjectName(QString::fromUtf8("verticalLayout_cameraConnect")); + verticalLayout_cameraConnect->setContentsMargins(5, 5, 5, 5); + horizontalLayout_deviceConnect = new QHBoxLayout(); + horizontalLayout_deviceConnect->setSpacing(12); + horizontalLayout_deviceConnect->setObjectName(QString::fromUtf8("horizontalLayout_deviceConnect")); + horizontalLayout_tcp = new QHBoxLayout(); + horizontalLayout_tcp->setSpacing(6); + horizontalLayout_tcp->setObjectName(QString::fromUtf8("horizontalLayout_tcp")); + label = new QLabel(groupBoxCameraConnect); + label->setObjectName(QString::fromUtf8("label")); + + horizontalLayout_tcp->addWidget(label); + + cmbIPAddr = new QComboBox(groupBoxCameraConnect); + cmbIPAddr->setObjectName(QString::fromUtf8("cmbIPAddr")); + cmbIPAddr->setEditable(true); + + horizontalLayout_tcp->addWidget(cmbIPAddr); + + label_3 = new QLabel(groupBoxCameraConnect); + label_3->setObjectName(QString::fromUtf8("label_3")); + + horizontalLayout_tcp->addWidget(label_3); + + lineEditPort = new QLineEdit(groupBoxCameraConnect); + lineEditPort->setObjectName(QString::fromUtf8("lineEditPort")); + + horizontalLayout_tcp->addWidget(lineEditPort); + + btnConnectTCP = new QPushButton(groupBoxCameraConnect); + btnConnectTCP->setObjectName(QString::fromUtf8("btnConnectTCP")); + + horizontalLayout_tcp->addWidget(btnConnectTCP); + + + horizontalLayout_deviceConnect->addLayout(horizontalLayout_tcp); + + horizontalLayout_serial = new QHBoxLayout(); + horizontalLayout_serial->setSpacing(6); + horizontalLayout_serial->setObjectName(QString::fromUtf8("horizontalLayout_serial")); + label_2 = new QLabel(groupBoxCameraConnect); + label_2->setObjectName(QString::fromUtf8("label_2")); + + horizontalLayout_serial->addWidget(label_2); + + cmbSerialPort = new QComboBox(groupBoxCameraConnect); + cmbSerialPort->setObjectName(QString::fromUtf8("cmbSerialPort")); + cmbSerialPort->setEditable(false); + + horizontalLayout_serial->addWidget(cmbSerialPort); + + label_4 = new QLabel(groupBoxCameraConnect); + label_4->setObjectName(QString::fromUtf8("label_4")); + + horizontalLayout_serial->addWidget(label_4); + + lineEditBaudrate = new QLineEdit(groupBoxCameraConnect); + lineEditBaudrate->setObjectName(QString::fromUtf8("lineEditBaudrate")); + + horizontalLayout_serial->addWidget(lineEditBaudrate); + + btnConnctSerialPort = new QPushButton(groupBoxCameraConnect); + btnConnctSerialPort->setObjectName(QString::fromUtf8("btnConnctSerialPort")); + + horizontalLayout_serial->addWidget(btnConnctSerialPort); + + + horizontalLayout_deviceConnect->addLayout(horizontalLayout_serial); + + + verticalLayout_cameraConnect->addLayout(horizontalLayout_deviceConnect); + + horizontalLayout_videoConnect = new QHBoxLayout(); + horizontalLayout_videoConnect->setSpacing(12); + horizontalLayout_videoConnect->setObjectName(QString::fromUtf8("horizontalLayout_videoConnect")); + horizontalLayout_networkVideo = new QHBoxLayout(); + horizontalLayout_networkVideo->setSpacing(6); + horizontalLayout_networkVideo->setObjectName(QString::fromUtf8("horizontalLayout_networkVideo")); + label_5 = new QLabel(groupBoxCameraConnect); + label_5->setObjectName(QString::fromUtf8("label_5")); + + horizontalLayout_networkVideo->addWidget(label_5); + + cmbNetworkVideoURL = new QComboBox(groupBoxCameraConnect); + cmbNetworkVideoURL->setObjectName(QString::fromUtf8("cmbNetworkVideoURL")); + cmbNetworkVideoURL->setEditable(true); + + horizontalLayout_networkVideo->addWidget(cmbNetworkVideoURL); + + btnOpenNetworkVideo = new QPushButton(groupBoxCameraConnect); + btnOpenNetworkVideo->setObjectName(QString::fromUtf8("btnOpenNetworkVideo")); + + horizontalLayout_networkVideo->addWidget(btnOpenNetworkVideo); + + + horizontalLayout_videoConnect->addLayout(horizontalLayout_networkVideo); + + horizontalLayout_usbVideo = new QHBoxLayout(); + horizontalLayout_usbVideo->setSpacing(6); + horizontalLayout_usbVideo->setObjectName(QString::fromUtf8("horizontalLayout_usbVideo")); + label_6 = new QLabel(groupBoxCameraConnect); + label_6->setObjectName(QString::fromUtf8("label_6")); + + horizontalLayout_usbVideo->addWidget(label_6); + + cmbUSBCamera = new QComboBox(groupBoxCameraConnect); + cmbUSBCamera->setObjectName(QString::fromUtf8("cmbUSBCamera")); + + horizontalLayout_usbVideo->addWidget(cmbUSBCamera); + + btnOpenUSBVideo = new QPushButton(groupBoxCameraConnect); + btnOpenUSBVideo->setObjectName(QString::fromUtf8("btnOpenUSBVideo")); + + horizontalLayout_usbVideo->addWidget(btnOpenUSBVideo); + + + horizontalLayout_videoConnect->addLayout(horizontalLayout_usbVideo); + + + verticalLayout_cameraConnect->addLayout(horizontalLayout_videoConnect); + + + horizontalLayout_connect->addWidget(groupBoxCameraConnect); + + groupBoxUAVConnect = new QGroupBox(groupBoxConnect); + groupBoxUAVConnect->setObjectName(QString::fromUtf8("groupBoxUAVConnect")); + groupBoxUAVConnect->setFont(font1); + horizontalLayout_15 = new QHBoxLayout(groupBoxUAVConnect); + horizontalLayout_15->setSpacing(10); + horizontalLayout_15->setContentsMargins(11, 11, 11, 11); + horizontalLayout_15->setObjectName(QString::fromUtf8("horizontalLayout_15")); + horizontalLayout_15->setContentsMargins(5, 5, 5, 5); + labelUAVIP = new QLabel(groupBoxUAVConnect); + labelUAVIP->setObjectName(QString::fromUtf8("labelUAVIP")); + + horizontalLayout_15->addWidget(labelUAVIP); + + lineEditUAVIP = new QLineEdit(groupBoxUAVConnect); + lineEditUAVIP->setObjectName(QString::fromUtf8("lineEditUAVIP")); + + horizontalLayout_15->addWidget(lineEditUAVIP); + + labelUAVPort = new QLabel(groupBoxUAVConnect); + labelUAVPort->setObjectName(QString::fromUtf8("labelUAVPort")); + + horizontalLayout_15->addWidget(labelUAVPort); + + lineEditUAVPort = new QLineEdit(groupBoxUAVConnect); + lineEditUAVPort->setObjectName(QString::fromUtf8("lineEditUAVPort")); + + horizontalLayout_15->addWidget(lineEditUAVPort); + + btnConnectUAV = new QPushButton(groupBoxUAVConnect); + btnConnectUAV->setObjectName(QString::fromUtf8("btnConnectUAV")); + + horizontalLayout_15->addWidget(btnConnectUAV); + + + horizontalLayout_connect->addWidget(groupBoxUAVConnect); + + + verticalLayout_main->addWidget(groupBoxConnect); + + horizontalLayout_main = new QHBoxLayout(); + horizontalLayout_main->setSpacing(6); + horizontalLayout_main->setObjectName(QString::fromUtf8("horizontalLayout_main")); + widgetCameraControl = new QWidget(Widget); + widgetCameraControl->setObjectName(QString::fromUtf8("widgetCameraControl")); + QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + sizePolicy.setHorizontalStretch(1); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(widgetCameraControl->sizePolicy().hasHeightForWidth()); + widgetCameraControl->setSizePolicy(sizePolicy); + horizontalLayout_camera = new QHBoxLayout(widgetCameraControl); + horizontalLayout_camera->setSpacing(5); + horizontalLayout_camera->setContentsMargins(11, 11, 11, 11); + horizontalLayout_camera->setObjectName(QString::fromUtf8("horizontalLayout_camera")); + horizontalLayout_camera->setContentsMargins(0, 0, 0, 0); + widgetCameraControls = new QWidget(widgetCameraControl); + widgetCameraControls->setObjectName(QString::fromUtf8("widgetCameraControls")); + widgetCameraControls->setMinimumSize(QSize(280, 0)); + widgetCameraControls->setMaximumSize(QSize(280, 16777215)); + verticalLayout_cameraControls = new QVBoxLayout(widgetCameraControls); + verticalLayout_cameraControls->setSpacing(8); + verticalLayout_cameraControls->setContentsMargins(11, 11, 11, 11); + verticalLayout_cameraControls->setObjectName(QString::fromUtf8("verticalLayout_cameraControls")); + verticalLayout_cameraControls->setContentsMargins(5, 5, 5, 5); + groupBoxCameraControl = new QGroupBox(widgetCameraControls); + groupBoxCameraControl->setObjectName(QString::fromUtf8("groupBoxCameraControl")); + groupBoxCameraControl->setFont(font1); + verticalLayout_gimbal = new QVBoxLayout(groupBoxCameraControl); + verticalLayout_gimbal->setSpacing(8); + verticalLayout_gimbal->setContentsMargins(11, 11, 11, 11); + verticalLayout_gimbal->setObjectName(QString::fromUtf8("verticalLayout_gimbal")); + verticalLayout_gimbal->setContentsMargins(8, 8, 8, 8); + horizontalLayout_10 = new QHBoxLayout(); + horizontalLayout_10->setSpacing(6); + horizontalLayout_10->setObjectName(QString::fromUtf8("horizontalLayout_10")); + label_10 = new QLabel(groupBoxCameraControl); + label_10->setObjectName(QString::fromUtf8("label_10")); + + horizontalLayout_10->addWidget(label_10); + + SliderMoveSpeed = new QSlider(groupBoxCameraControl); + SliderMoveSpeed->setObjectName(QString::fromUtf8("SliderMoveSpeed")); + SliderMoveSpeed->setMinimum(1); + SliderMoveSpeed->setMaximum(20); + SliderMoveSpeed->setPageStep(1); + SliderMoveSpeed->setValue(10); + SliderMoveSpeed->setOrientation(Qt::Horizontal); + + horizontalLayout_10->addWidget(SliderMoveSpeed); + + + verticalLayout_gimbal->addLayout(horizontalLayout_10); + + horizontalLayout_4 = new QHBoxLayout(); + horizontalLayout_4->setSpacing(6); + horizontalLayout_4->setObjectName(QString::fromUtf8("horizontalLayout_4")); + horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + horizontalLayout_4->addItem(horizontalSpacer); + + btnUp = new QPushButton(groupBoxCameraControl); + btnUp->setObjectName(QString::fromUtf8("btnUp")); + btnUp->setMinimumSize(QSize(80, 25)); + + horizontalLayout_4->addWidget(btnUp); + + horizontalSpacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + horizontalLayout_4->addItem(horizontalSpacer_2); + + + verticalLayout_gimbal->addLayout(horizontalLayout_4); + + horizontalLayout_5 = new QHBoxLayout(); + horizontalLayout_5->setSpacing(6); + horizontalLayout_5->setObjectName(QString::fromUtf8("horizontalLayout_5")); + btnLeft = new QPushButton(groupBoxCameraControl); + btnLeft->setObjectName(QString::fromUtf8("btnLeft")); + btnLeft->setMinimumSize(QSize(70, 25)); + + horizontalLayout_5->addWidget(btnLeft); + + btnHome = new QPushButton(groupBoxCameraControl); + btnHome->setObjectName(QString::fromUtf8("btnHome")); + btnHome->setMinimumSize(QSize(70, 25)); + + horizontalLayout_5->addWidget(btnHome); + + btnRight = new QPushButton(groupBoxCameraControl); + btnRight->setObjectName(QString::fromUtf8("btnRight")); + btnRight->setMinimumSize(QSize(70, 25)); + + horizontalLayout_5->addWidget(btnRight); + + + verticalLayout_gimbal->addLayout(horizontalLayout_5); + + horizontalLayout_6 = new QHBoxLayout(); + horizontalLayout_6->setSpacing(6); + horizontalLayout_6->setObjectName(QString::fromUtf8("horizontalLayout_6")); + horizontalSpacer_3 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + horizontalLayout_6->addItem(horizontalSpacer_3); + + btnDown = new QPushButton(groupBoxCameraControl); + btnDown->setObjectName(QString::fromUtf8("btnDown")); + btnDown->setMinimumSize(QSize(80, 25)); + + horizontalLayout_6->addWidget(btnDown); + + horizontalSpacer_4 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + horizontalLayout_6->addItem(horizontalSpacer_4); + + + verticalLayout_gimbal->addLayout(horizontalLayout_6); + + horizontalLayout_7 = new QHBoxLayout(); + horizontalLayout_7->setSpacing(6); + horizontalLayout_7->setObjectName(QString::fromUtf8("horizontalLayout_7")); + label_7 = new QLabel(groupBoxCameraControl); + label_7->setObjectName(QString::fromUtf8("label_7")); + + horizontalLayout_7->addWidget(label_7); + + cmbImageSensor = new QComboBox(groupBoxCameraControl); + cmbImageSensor->setObjectName(QString::fromUtf8("cmbImageSensor")); + + horizontalLayout_7->addWidget(cmbImageSensor); + + + verticalLayout_gimbal->addLayout(horizontalLayout_7); + + horizontalLayout_8 = new QHBoxLayout(); + horizontalLayout_8->setSpacing(6); + horizontalLayout_8->setObjectName(QString::fromUtf8("horizontalLayout_8")); + label_8 = new QLabel(groupBoxCameraControl); + label_8->setObjectName(QString::fromUtf8("label_8")); + + horizontalLayout_8->addWidget(label_8); + + cmbIRColor = new QComboBox(groupBoxCameraControl); + cmbIRColor->setObjectName(QString::fromUtf8("cmbIRColor")); + + horizontalLayout_8->addWidget(cmbIRColor); + + checkBoxPIP = new QCheckBox(groupBoxCameraControl); + checkBoxPIP->setObjectName(QString::fromUtf8("checkBoxPIP")); + + horizontalLayout_8->addWidget(checkBoxPIP); + + + verticalLayout_gimbal->addLayout(horizontalLayout_8); + + horizontalLayout_12 = new QHBoxLayout(); + horizontalLayout_12->setSpacing(6); + horizontalLayout_12->setObjectName(QString::fromUtf8("horizontalLayout_12")); + btnZoomIn = new QPushButton(groupBoxCameraControl); + btnZoomIn->setObjectName(QString::fromUtf8("btnZoomIn")); + + horizontalLayout_12->addWidget(btnZoomIn); + + btnZoomOut = new QPushButton(groupBoxCameraControl); + btnZoomOut->setObjectName(QString::fromUtf8("btnZoomOut")); + + horizontalLayout_12->addWidget(btnZoomOut); + + + verticalLayout_gimbal->addLayout(horizontalLayout_12); + + btnGimbalTakePhoto = new QPushButton(groupBoxCameraControl); + btnGimbalTakePhoto->setObjectName(QString::fromUtf8("btnGimbalTakePhoto")); + btnGimbalTakePhoto->setMinimumSize(QSize(0, 25)); + + verticalLayout_gimbal->addWidget(btnGimbalTakePhoto); + + horizontalLayout_11 = new QHBoxLayout(); + horizontalLayout_11->setSpacing(6); + horizontalLayout_11->setObjectName(QString::fromUtf8("horizontalLayout_11")); + btnStartRecord = new QPushButton(groupBoxCameraControl); + btnStartRecord->setObjectName(QString::fromUtf8("btnStartRecord")); + + horizontalLayout_11->addWidget(btnStartRecord); + + btnStopRecord = new QPushButton(groupBoxCameraControl); + btnStopRecord->setObjectName(QString::fromUtf8("btnStopRecord")); + + horizontalLayout_11->addWidget(btnStopRecord); + + + verticalLayout_gimbal->addLayout(horizontalLayout_11); + + + verticalLayout_cameraControls->addWidget(groupBoxCameraControl); + + groupBoxIdentify = new QGroupBox(widgetCameraControls); + groupBoxIdentify->setObjectName(QString::fromUtf8("groupBoxIdentify")); + groupBoxIdentify->setFont(font1); + verticalLayout_identify = new QVBoxLayout(groupBoxIdentify); + verticalLayout_identify->setSpacing(8); + verticalLayout_identify->setContentsMargins(11, 11, 11, 11); + verticalLayout_identify->setObjectName(QString::fromUtf8("verticalLayout_identify")); + verticalLayout_identify->setContentsMargins(8, 8, 8, 8); + labelIRIdentification = new QLabel(groupBoxIdentify); + labelIRIdentification->setObjectName(QString::fromUtf8("labelIRIdentification")); + labelIRIdentification->setAlignment(Qt::AlignCenter); + + verticalLayout_identify->addWidget(labelIRIdentification); + + labelConfidence = new QLabel(groupBoxIdentify); + labelConfidence->setObjectName(QString::fromUtf8("labelConfidence")); + labelConfidence->setAlignment(Qt::AlignCenter); + labelConfidence->setFont(font1); + + verticalLayout_identify->addWidget(labelConfidence); + + horizontalLayout_confidenceSlider = new QHBoxLayout(); + horizontalLayout_confidenceSlider->setSpacing(6); + horizontalLayout_confidenceSlider->setObjectName(QString::fromUtf8("horizontalLayout_confidenceSlider")); + sliderConfidence = new QSlider(groupBoxIdentify); + sliderConfidence->setObjectName(QString::fromUtf8("sliderConfidence")); + sliderConfidence->setMinimum(0); + sliderConfidence->setMaximum(100); + sliderConfidence->setValue(70); + sliderConfidence->setOrientation(Qt::Horizontal); + sliderConfidence->setTickPosition(QSlider::TicksBelow); + + horizontalLayout_confidenceSlider->addWidget(sliderConfidence); + + labelConfidenceValue = new QLabel(groupBoxIdentify); + labelConfidenceValue->setObjectName(QString::fromUtf8("labelConfidenceValue")); + labelConfidenceValue->setMinimumSize(QSize(30, 0)); + + horizontalLayout_confidenceSlider->addWidget(labelConfidenceValue); + + + verticalLayout_identify->addLayout(horizontalLayout_confidenceSlider); + + checkBoxPreprocess = new QCheckBox(groupBoxIdentify); + checkBoxPreprocess->setObjectName(QString::fromUtf8("checkBoxPreprocess")); + checkBoxPreprocess->setChecked(true); + + verticalLayout_identify->addWidget(checkBoxPreprocess); + + btnIdentifyTarget = new QPushButton(groupBoxIdentify); + btnIdentifyTarget->setObjectName(QString::fromUtf8("btnIdentifyTarget")); + btnIdentifyTarget->setMinimumSize(QSize(0, 25)); + + verticalLayout_identify->addWidget(btnIdentifyTarget); + + btnClearIdentification = new QPushButton(groupBoxIdentify); + btnClearIdentification->setObjectName(QString::fromUtf8("btnClearIdentification")); + btnClearIdentification->setMinimumSize(QSize(0, 25)); + + verticalLayout_identify->addWidget(btnClearIdentification); + + + verticalLayout_identify->addWidget(); + + + verticalLayout_cameraControls->addWidget(groupBoxIdentify); + + verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + + verticalLayout_cameraControls->addItem(verticalSpacer); + + + horizontalLayout_camera->addWidget(widgetCameraControls); + + verticalLayout_video = new QVBoxLayout(); + verticalLayout_video->setSpacing(6); + verticalLayout_video->setObjectName(QString::fromUtf8("verticalLayout_video")); + widgetMainVideo = new VLKVideoWidget(widgetCameraControl); + widgetMainVideo->setObjectName(QString::fromUtf8("widgetMainVideo")); + QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Expanding); + sizePolicy1.setHorizontalStretch(0); + sizePolicy1.setVerticalStretch(0); + sizePolicy1.setHeightForWidth(widgetMainVideo->sizePolicy().hasHeightForWidth()); + widgetMainVideo->setSizePolicy(sizePolicy1); + + verticalLayout_video->addWidget(widgetMainVideo); + + widgetDevStatus = new QWidget(widgetCameraControl); + widgetDevStatus->setObjectName(QString::fromUtf8("widgetDevStatus")); + widgetDevStatus->setMaximumSize(QSize(16777215, 40)); + horizontalLayout_9 = new QHBoxLayout(widgetDevStatus); + horizontalLayout_9->setSpacing(5); + horizontalLayout_9->setContentsMargins(11, 11, 11, 11); + horizontalLayout_9->setObjectName(QString::fromUtf8("horizontalLayout_9")); + horizontalLayout_9->setContentsMargins(5, 2, 5, 2); + label_9 = new QLabel(widgetDevStatus); + label_9->setObjectName(QString::fromUtf8("label_9")); + + horizontalLayout_9->addWidget(label_9); + + lbYaw = new QLabel(widgetDevStatus); + lbYaw->setObjectName(QString::fromUtf8("lbYaw")); + + horizontalLayout_9->addWidget(lbYaw); + + label_13 = new QLabel(widgetDevStatus); + label_13->setObjectName(QString::fromUtf8("label_13")); + + horizontalLayout_9->addWidget(label_13); + + lbPitch = new QLabel(widgetDevStatus); + lbPitch->setObjectName(QString::fromUtf8("lbPitch")); + + horizontalLayout_9->addWidget(lbPitch); + + label_11 = new QLabel(widgetDevStatus); + label_11->setObjectName(QString::fromUtf8("label_11")); + + horizontalLayout_9->addWidget(label_11); + + lbTargetLat = new QLabel(widgetDevStatus); + lbTargetLat->setObjectName(QString::fromUtf8("lbTargetLat")); + + horizontalLayout_9->addWidget(lbTargetLat); + + label_15 = new QLabel(widgetDevStatus); + label_15->setObjectName(QString::fromUtf8("label_15")); + + horizontalLayout_9->addWidget(label_15); + + lbTargetLng = new QLabel(widgetDevStatus); + lbTargetLng->setObjectName(QString::fromUtf8("lbTargetLng")); + + horizontalLayout_9->addWidget(lbTargetLng); + + label_17 = new QLabel(widgetDevStatus); + label_17->setObjectName(QString::fromUtf8("label_17")); + + horizontalLayout_9->addWidget(label_17); + + lbTargetAlt = new QLabel(widgetDevStatus); + lbTargetAlt->setObjectName(QString::fromUtf8("lbTargetAlt")); + + horizontalLayout_9->addWidget(lbTargetAlt); + + label_19 = new QLabel(widgetDevStatus); + label_19->setObjectName(QString::fromUtf8("label_19")); + + horizontalLayout_9->addWidget(label_19); + + lbZoom = new QLabel(widgetDevStatus); + lbZoom->setObjectName(QString::fromUtf8("lbZoom")); + + horizontalLayout_9->addWidget(lbZoom); + + + verticalLayout_video->addWidget(widgetDevStatus); + + + horizontalLayout_camera->addLayout(verticalLayout_video); + + + horizontalLayout_main->addWidget(widgetCameraControl); + + widgetUAVControl = new QWidget(Widget); + widgetUAVControl->setObjectName(QString::fromUtf8("widgetUAVControl")); + sizePolicy.setHeightForWidth(widgetUAVControl->sizePolicy().hasHeightForWidth()); + widgetUAVControl->setSizePolicy(sizePolicy); + verticalLayout_uav = new QVBoxLayout(widgetUAVControl); + verticalLayout_uav->setSpacing(5); + verticalLayout_uav->setContentsMargins(11, 11, 11, 11); + verticalLayout_uav->setObjectName(QString::fromUtf8("verticalLayout_uav")); + verticalLayout_uav->setContentsMargins(0, 0, 0, 0); + groupBoxUAVControl = new QGroupBox(widgetUAVControl); + groupBoxUAVControl->setObjectName(QString::fromUtf8("groupBoxUAVControl")); + groupBoxUAVControl->setFont(font1); + horizontalLayout_16 = new QHBoxLayout(groupBoxUAVControl); + horizontalLayout_16->setSpacing(6); + horizontalLayout_16->setContentsMargins(11, 11, 11, 11); + horizontalLayout_16->setObjectName(QString::fromUtf8("horizontalLayout_16")); + btnArmDisarm = new QPushButton(groupBoxUAVControl); + btnArmDisarm->setObjectName(QString::fromUtf8("btnArmDisarm")); + + horizontalLayout_16->addWidget(btnArmDisarm); + + btnTakeoff = new QPushButton(groupBoxUAVControl); + btnTakeoff->setObjectName(QString::fromUtf8("btnTakeoff")); + + horizontalLayout_16->addWidget(btnTakeoff); + + btnLand = new QPushButton(groupBoxUAVControl); + btnLand->setObjectName(QString::fromUtf8("btnLand")); + + horizontalLayout_16->addWidget(btnLand); + + btnRTL = new QPushButton(groupBoxUAVControl); + btnRTL->setObjectName(QString::fromUtf8("btnRTL")); + + horizontalLayout_16->addWidget(btnRTL); + + comboBoxMode = new QComboBox(groupBoxUAVControl); + comboBoxMode->addItem(QString()); + comboBoxMode->addItem(QString()); + comboBoxMode->addItem(QString()); + comboBoxMode->addItem(QString()); + comboBoxMode->addItem(QString()); + comboBoxMode->setObjectName(QString::fromUtf8("comboBoxMode")); + + horizontalLayout_16->addWidget(comboBoxMode); + + btnMode = new QPushButton(groupBoxUAVControl); + btnMode->setObjectName(QString::fromUtf8("btnMode")); + + horizontalLayout_16->addWidget(btnMode); + + + verticalLayout_uav->addWidget(groupBoxUAVControl); + + groupBoxStatus = new QGroupBox(widgetUAVControl); + groupBoxStatus->setObjectName(QString::fromUtf8("groupBoxStatus")); + groupBoxStatus->setMaximumSize(QSize(16777215, 150)); + groupBoxStatus->setFont(font1); + gridLayout = new QGridLayout(groupBoxStatus); + gridLayout->setSpacing(8); + gridLayout->setContentsMargins(8, 8, 8, 8); + gridLayout->setObjectName(QString::fromUtf8("gridLayout")); + labelAltitude = new QLabel(groupBoxStatus); + labelAltitude->setObjectName(QString::fromUtf8("labelAltitude")); + + gridLayout->addWidget(labelAltitude, 0, 0, 1, 1); + + valueAltitude = new QLabel(groupBoxStatus); + valueAltitude->setObjectName(QString::fromUtf8("valueAltitude")); + + gridLayout->addWidget(valueAltitude, 0, 1, 1, 1); + + labelSpeed = new QLabel(groupBoxStatus); + labelSpeed->setObjectName(QString::fromUtf8("labelSpeed")); + + gridLayout->addWidget(labelSpeed, 0, 2, 1, 1); + + valueSpeed = new QLabel(groupBoxStatus); + valueSpeed->setObjectName(QString::fromUtf8("valueSpeed")); + + gridLayout->addWidget(valueSpeed, 0, 3, 1, 1); + + labelRoll = new QLabel(groupBoxStatus); + labelRoll->setObjectName(QString::fromUtf8("labelRoll")); + + gridLayout->addWidget(labelRoll, 1, 0, 1, 1); + + valueRoll = new QLabel(groupBoxStatus); + valueRoll->setObjectName(QString::fromUtf8("valueRoll")); + + gridLayout->addWidget(valueRoll, 1, 1, 1, 1); + + labelPitch = new QLabel(groupBoxStatus); + labelPitch->setObjectName(QString::fromUtf8("labelPitch")); + + gridLayout->addWidget(labelPitch, 1, 2, 1, 1); + + valuePitch = new QLabel(groupBoxStatus); + valuePitch->setObjectName(QString::fromUtf8("valuePitch")); + + gridLayout->addWidget(valuePitch, 1, 3, 1, 1); + + labelHeading = new QLabel(groupBoxStatus); + labelHeading->setObjectName(QString::fromUtf8("labelHeading")); + + gridLayout->addWidget(labelHeading, 2, 0, 1, 1); + + valueHeading = new QLabel(groupBoxStatus); + valueHeading->setObjectName(QString::fromUtf8("valueHeading")); + + gridLayout->addWidget(valueHeading, 2, 1, 1, 1); + + labelBattery = new QLabel(groupBoxStatus); + labelBattery->setObjectName(QString::fromUtf8("labelBattery")); + + gridLayout->addWidget(labelBattery, 2, 2, 1, 1); + + valueBattery = new QLabel(groupBoxStatus); + valueBattery->setObjectName(QString::fromUtf8("valueBattery")); + + gridLayout->addWidget(valueBattery, 2, 3, 1, 1); + + + verticalLayout_uav->addWidget(groupBoxStatus); + + frameMap = new QFrame(widgetUAVControl); + frameMap->setObjectName(QString::fromUtf8("frameMap")); + sizePolicy1.setHeightForWidth(frameMap->sizePolicy().hasHeightForWidth()); + frameMap->setSizePolicy(sizePolicy1); + frameMap->setFrameShape(QFrame::StyledPanel); + frameMap->setFrameShadow(QFrame::Raised); + layoutMap = new QVBoxLayout(frameMap); + layoutMap->setSpacing(6); + layoutMap->setContentsMargins(11, 11, 11, 11); + layoutMap->setObjectName(QString::fromUtf8("layoutMap")); + + verticalLayout_uav->addWidget(frameMap); + + groupBoxSoundLocator = new QGroupBox(widgetUAVControl); + groupBoxSoundLocator->setObjectName(QString::fromUtf8("groupBoxSoundLocator")); + groupBoxSoundLocator->setMaximumSize(QSize(16777215, 250)); + groupBoxSoundLocator->setFont(font1); + horizontalLayout_20 = new QHBoxLayout(groupBoxSoundLocator); + horizontalLayout_20->setSpacing(10); + horizontalLayout_20->setContentsMargins(10, 10, 10, 10); + horizontalLayout_20->setObjectName(QString::fromUtf8("horizontalLayout_20")); + verticalLayout_15 = new QVBoxLayout(); + verticalLayout_15->setSpacing(5); + verticalLayout_15->setObjectName(QString::fromUtf8("verticalLayout_15")); + gridLayout_2 = new QGridLayout(); + gridLayout_2->setSpacing(6); + gridLayout_2->setObjectName(QString::fromUtf8("gridLayout_2")); + gridLayout_2->setHorizontalSpacing(5); + gridLayout_2->setVerticalSpacing(5); + labelSoundIP = new QLabel(groupBoxSoundLocator); + labelSoundIP->setObjectName(QString::fromUtf8("labelSoundIP")); + + gridLayout_2->addWidget(labelSoundIP, 0, 0, 1, 1); + + lineEditSoundIP = new QLineEdit(groupBoxSoundLocator); + lineEditSoundIP->setObjectName(QString::fromUtf8("lineEditSoundIP")); + + gridLayout_2->addWidget(lineEditSoundIP, 0, 1, 1, 1); + + labelSoundPort = new QLabel(groupBoxSoundLocator); + labelSoundPort->setObjectName(QString::fromUtf8("labelSoundPort")); + + gridLayout_2->addWidget(labelSoundPort, 1, 0, 1, 1); + + lineEditSoundPort = new QLineEdit(groupBoxSoundLocator); + lineEditSoundPort->setObjectName(QString::fromUtf8("lineEditSoundPort")); + + gridLayout_2->addWidget(lineEditSoundPort, 1, 1, 1, 1); + + + verticalLayout_15->addLayout(gridLayout_2); + + horizontalLayout_18 = new QHBoxLayout(); + horizontalLayout_18->setSpacing(6); + horizontalLayout_18->setObjectName(QString::fromUtf8("horizontalLayout_18")); + btnStartSoundLocator = new QPushButton(groupBoxSoundLocator); + btnStartSoundLocator->setObjectName(QString::fromUtf8("btnStartSoundLocator")); + + horizontalLayout_18->addWidget(btnStartSoundLocator); + + btnStopSoundLocator = new QPushButton(groupBoxSoundLocator); + btnStopSoundLocator->setObjectName(QString::fromUtf8("btnStopSoundLocator")); + btnStopSoundLocator->setEnabled(false); + + horizontalLayout_18->addWidget(btnStopSoundLocator); + + + verticalLayout_15->addLayout(horizontalLayout_18); + + textEditSoundLog = new QTextEdit(groupBoxSoundLocator); + textEditSoundLog->setObjectName(QString::fromUtf8("textEditSoundLog")); + textEditSoundLog->setMinimumSize(QSize(300, 100)); + textEditSoundLog->setMaximumSize(QSize(16777215, 150)); + textEditSoundLog->setReadOnly(true); + + verticalLayout_15->addWidget(textEditSoundLog); + + + horizontalLayout_20->addLayout(verticalLayout_15); + + frameSoundVisualization = new QFrame(groupBoxSoundLocator); + frameSoundVisualization->setObjectName(QString::fromUtf8("frameSoundVisualization")); + frameSoundVisualization->setMinimumSize(QSize(400, 200)); + frameSoundVisualization->setFrameShape(QFrame::StyledPanel); + frameSoundVisualization->setFrameShadow(QFrame::Raised); + layoutSoundVisualization = new QVBoxLayout(frameSoundVisualization); + layoutSoundVisualization->setSpacing(6); + layoutSoundVisualization->setContentsMargins(11, 11, 11, 11); + layoutSoundVisualization->setObjectName(QString::fromUtf8("layoutSoundVisualization")); + + horizontalLayout_20->addWidget(frameSoundVisualization); + + + verticalLayout_uav->addWidget(groupBoxSoundLocator); + + + horizontalLayout_main->addWidget(widgetUAVControl); + + + verticalLayout_main->addLayout(horizontalLayout_main); + + + retranslateUi(Widget); + + QMetaObject::connectSlotsByName(Widget); + } // setupUi + + void retranslateUi(QWidget *Widget) + { + Widget->setWindowTitle(QCoreApplication::translate("Widget", "\346\227\240\344\272\272\346\234\272\344\270\216\346\221\204\345\203\217\345\244\264\346\216\247\345\210\266", nullptr)); + groupBoxConnect->setTitle(QCoreApplication::translate("Widget", "\350\277\236\346\216\245\350\256\276\347\275\256", nullptr)); + groupBoxConnect->setStyleSheet(QCoreApplication::translate("Widget", "QGroupBox {\n" +" border: 1px solid #8f8f8f;\n" +" border-radius: 5px;\n" +" margin-top: 1ex;\n" +" background-color: #f5f5f5;\n" +"}\n" +"QGroupBox::title {\n" +" subcontrol-origin: margin;\n" +" subcontrol-position: top center;\n" +" padding: 0 3px;\n" +" background-color: #f5f5f5;\n" +"}\n" +"", nullptr)); + groupBoxCameraConnect->setTitle(QCoreApplication::translate("Widget", "\346\221\204\345\203\217\345\244\264\350\277\236\346\216\245", nullptr)); + label->setText(QCoreApplication::translate("Widget", "TCP\345\234\260\345\235\200:", nullptr)); + label_3->setText(QCoreApplication::translate("Widget", "\347\253\257\345\217\243:", nullptr)); + btnConnectTCP->setText(QCoreApplication::translate("Widget", "\350\277\236\346\216\245", nullptr)); + label_2->setText(QCoreApplication::translate("Widget", "\344\270\262\345\217\243:", nullptr)); + label_4->setText(QCoreApplication::translate("Widget", "\346\263\242\347\211\271\347\216\207:", nullptr)); + btnConnctSerialPort->setText(QCoreApplication::translate("Widget", "\350\277\236\346\216\245", nullptr)); + label_5->setText(QCoreApplication::translate("Widget", "\347\275\221\347\273\234\350\247\206\351\242\221\346\272\220:", nullptr)); + btnOpenNetworkVideo->setText(QCoreApplication::translate("Widget", "\345\274\200\345\220\257", nullptr)); + label_6->setText(QCoreApplication::translate("Widget", "USB\346\221\204\345\203\217\345\244\264:", nullptr)); + btnOpenUSBVideo->setText(QCoreApplication::translate("Widget", "\345\274\200\345\220\257", nullptr)); + groupBoxUAVConnect->setTitle(QCoreApplication::translate("Widget", "\346\227\240\344\272\272\346\234\272\350\277\236\346\216\245", nullptr)); + labelUAVIP->setText(QCoreApplication::translate("Widget", "\346\227\240\344\272\272\346\234\272IP:", nullptr)); + lineEditUAVIP->setText(QCoreApplication::translate("Widget", "127.0.0.1", nullptr)); + labelUAVPort->setText(QCoreApplication::translate("Widget", "\347\253\257\345\217\243:", nullptr)); + lineEditUAVPort->setText(QCoreApplication::translate("Widget", "14550", nullptr)); + btnConnectUAV->setText(QCoreApplication::translate("Widget", "\350\277\236\346\216\245", nullptr)); + groupBoxCameraControl->setTitle(QCoreApplication::translate("Widget", "\344\272\221\345\217\260\346\216\247\345\210\266", nullptr)); + groupBoxCameraControl->setStyleSheet(QCoreApplication::translate("Widget", "QGroupBox {\n" +" border: 1px solid #8f8f8f;\n" +" border-radius: 5px;\n" +" margin-top: 1ex;\n" +"}\n" +"QGroupBox::title {\n" +" subcontrol-origin: margin;\n" +" subcontrol-position: top center;\n" +" padding: 0 3px;\n" +"}\n" +"QPushButton {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +" padding: 2px;\n" +"}\n" +"QLabel {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +"}\n" +"QComboBox {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +"}\n" +"", nullptr)); + label_10->setText(QCoreApplication::translate("Widget", "\351\200\237\345\272\246", nullptr)); + btnUp->setText(QCoreApplication::translate("Widget", "\345\220\221\344\270\212", nullptr)); + btnUp->setStyleSheet(QCoreApplication::translate("Widget", "QPushButton {\n" +" background-color: #e6f2ff;\n" +" border: 1px solid #99c2ff;\n" +" border-radius: 4px;\n" +"}\n" +"QPushButton:hover {\n" +" background-color: #cce6ff;\n" +"}\n" +"QPushButton:pressed {\n" +" background-color: #99c2ff;\n" +"}", nullptr)); + btnLeft->setText(QCoreApplication::translate("Widget", "\345\220\221\345\267\246", nullptr)); + btnLeft->setStyleSheet(QCoreApplication::translate("Widget", "QPushButton {\n" +" background-color: #e6f2ff;\n" +" border: 1px solid #99c2ff;\n" +" border-radius: 4px;\n" +"}\n" +"QPushButton:hover {\n" +" background-color: #cce6ff;\n" +"}\n" +"QPushButton:pressed {\n" +" background-color: #99c2ff;\n" +"}", nullptr)); + btnHome->setText(QCoreApplication::translate("Widget", "\345\233\236\346\255\243", nullptr)); + btnHome->setStyleSheet(QCoreApplication::translate("Widget", "QPushButton {\n" +" background-color: #fffae6;\n" +" border: 1px solid #ffd480;\n" +" border-radius: 4px;\n" +"}\n" +"QPushButton:hover {\n" +" background-color: #fff5cc;\n" +"}\n" +"QPushButton:pressed {\n" +" background-color: #ffd480;\n" +"}", nullptr)); + btnRight->setText(QCoreApplication::translate("Widget", "\345\220\221\345\217\263", nullptr)); + btnRight->setStyleSheet(QCoreApplication::translate("Widget", "QPushButton {\n" +" background-color: #e6f2ff;\n" +" border: 1px solid #99c2ff;\n" +" border-radius: 4px;\n" +"}\n" +"QPushButton:hover {\n" +" background-color: #cce6ff;\n" +"}\n" +"QPushButton:pressed {\n" +" background-color: #99c2ff;\n" +"}", nullptr)); + btnDown->setText(QCoreApplication::translate("Widget", "\345\220\221\344\270\213", nullptr)); + btnDown->setStyleSheet(QCoreApplication::translate("Widget", "QPushButton {\n" +" background-color: #e6f2ff;\n" +" border: 1px solid #99c2ff;\n" +" border-radius: 4px;\n" +"}\n" +"QPushButton:hover {\n" +" background-color: #cce6ff;\n" +"}\n" +"QPushButton:pressed {\n" +" background-color: #99c2ff;\n" +"}", nullptr)); + label_7->setText(QCoreApplication::translate("Widget", "\345\233\276\345\203\217\344\274\240\346\204\237\345\231\250:", nullptr)); + label_8->setText(QCoreApplication::translate("Widget", "\347\272\242\345\244\226\350\211\262\345\275\251:", nullptr)); + checkBoxPIP->setText(QCoreApplication::translate("Widget", "PIP", nullptr)); + btnZoomIn->setText(QCoreApplication::translate("Widget", "\346\224\276\345\244\247", nullptr)); + btnZoomOut->setText(QCoreApplication::translate("Widget", "\347\274\251\345\260\217", nullptr)); + btnGimbalTakePhoto->setText(QCoreApplication::translate("Widget", "\344\272\221\345\217\260\346\213\215\347\205\247", nullptr)); + btnStartRecord->setText(QCoreApplication::translate("Widget", "\345\274\200\345\247\213\345\275\225\345\203\217", nullptr)); + btnStopRecord->setText(QCoreApplication::translate("Widget", "\345\201\234\346\255\242\345\275\225\345\203\217", nullptr)); + groupBoxIdentify->setTitle(QCoreApplication::translate("Widget", "\346\231\272\350\203\275\350\257\206\345\210\253", nullptr)); + groupBoxIdentify->setStyleSheet(QCoreApplication::translate("Widget", "QGroupBox {\n" +" border: 1px solid #8f8f8f;\n" +" border-radius: 5px;\n" +" margin-top: 1ex;\n" +"}\n" +"QGroupBox::title {\n" +" subcontrol-origin: margin;\n" +" subcontrol-position: top center;\n" +" padding: 0 3px;\n" +"}\n" +"QPushButton {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +" padding: 2px;\n" +"}\n" +"QLabel {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +"}\n" +"QCheckBox {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +"}\n" +"", nullptr)); + labelIRIdentification->setText(QCoreApplication::translate("Widget", "\346\231\272\350\203\275\350\257\206\345\210\253\345\212\237\350\203\275\357\274\232", nullptr)); + labelConfidence->setText(QCoreApplication::translate("Widget", "\350\257\206\345\210\253\347\275\256\344\277\241\345\272\246\351\230\210\345\200\274\357\274\232", nullptr)); + labelConfidenceValue->setText(QCoreApplication::translate("Widget", "0.7", nullptr)); + checkBoxPreprocess->setText(QCoreApplication::translate("Widget", "\351\242\204\345\244\204\347\220\206\345\233\276\345\203\217(\345\242\236\345\274\272\345\257\271\346\257\224\345\272\246)", nullptr)); + btnIdentifyTarget->setText(QCoreApplication::translate("Widget", "\347\233\256\346\240\207\350\257\206\345\210\253", nullptr)); + btnIdentifyTarget->setStyleSheet(QCoreApplication::translate("Widget", "QPushButton {\n" +" background-color: #e6f2ff;\n" +" border: 1px solid #99c2ff;\n" +" border-radius: 4px;\n" +"}\n" +"QPushButton:hover {\n" +" background-color: #cce6ff;\n" +"}\n" +"QPushButton:pressed {\n" +" background-color: #99c2ff;\n" +"}", nullptr)); + btnClearIdentification->setText(QCoreApplication::translate("Widget", "\346\270\205\351\231\244\350\257\206\345\210\253\347\273\223\346\236\234", nullptr)); + btnClearIdentification->setStyleSheet(QCoreApplication::translate("Widget", "QPushButton {\n" +" background-color: #ffe6e6;\n" +" border: 1px solid #ffb3b3;\n" +" border-radius: 4px;\n" +"}\n" +"QPushButton:hover {\n" +" background-color: #ffcccc;\n" +" background-color: #ffb3b3;\n" +"}", nullptr)); + label_9->setText(QCoreApplication::translate("Widget", "\345\201\217\350\210\252\350\247\222:", nullptr)); + lbYaw->setText(QCoreApplication::translate("Widget", "0.00", nullptr)); + label_13->setText(QCoreApplication::translate("Widget", "\344\277\257\344\273\260\350\247\222:", nullptr)); + lbPitch->setText(QCoreApplication::translate("Widget", "0.00", nullptr)); + label_11->setText(QCoreApplication::translate("Widget", "\347\233\256\346\240\207\347\272\254\345\272\246:", nullptr)); + lbTargetLat->setText(QCoreApplication::translate("Widget", "0.00", nullptr)); + label_15->setText(QCoreApplication::translate("Widget", "\347\233\256\346\240\207\347\273\217\345\272\246:", nullptr)); + lbTargetLng->setText(QCoreApplication::translate("Widget", "0.00", nullptr)); + label_17->setText(QCoreApplication::translate("Widget", "\347\233\256\346\240\207\351\253\230\345\272\246:", nullptr)); + lbTargetAlt->setText(QCoreApplication::translate("Widget", "0.00", nullptr)); + label_19->setText(QCoreApplication::translate("Widget", "\345\217\230\347\204\246\345\200\215\347\216\207:", nullptr)); + lbZoom->setText(QCoreApplication::translate("Widget", "0.00", nullptr)); + groupBoxUAVControl->setTitle(QCoreApplication::translate("Widget", "\346\227\240\344\272\272\346\234\272\346\216\247\345\210\266", nullptr)); + groupBoxUAVControl->setStyleSheet(QCoreApplication::translate("Widget", "QGroupBox {\n" +" border: 1px solid #8f8f8f;\n" +" border-radius: 5px;\n" +" margin-top: 1ex;\n" +"}\n" +"QGroupBox::title {\n" +" subcontrol-origin: margin;\n" +" subcontrol-position: top center;\n" +" padding: 0 3px;\n" +"}\n" +"QPushButton {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +" padding: 2px;\n" +"}\n" +"QComboBox {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +"}\n" +"", nullptr)); + btnArmDisarm->setText(QCoreApplication::translate("Widget", "\350\247\243\351\224\201", nullptr)); + btnTakeoff->setText(QCoreApplication::translate("Widget", "\350\265\267\351\243\236", nullptr)); + btnLand->setText(QCoreApplication::translate("Widget", "\351\231\215\350\220\275", nullptr)); + btnRTL->setText(QCoreApplication::translate("Widget", "\350\277\224\350\210\252", nullptr)); + comboBoxMode->setItemText(0, QCoreApplication::translate("Widget", "\346\211\213\345\212\250\346\250\241\345\274\217", nullptr)); + comboBoxMode->setItemText(1, QCoreApplication::translate("Widget", "\347\250\263\345\256\232\346\250\241\345\274\217", nullptr)); + comboBoxMode->setItemText(2, QCoreApplication::translate("Widget", "\345\256\232\351\253\230\346\250\241\345\274\217", nullptr)); + comboBoxMode->setItemText(3, QCoreApplication::translate("Widget", "\345\256\232\347\202\271\346\250\241\345\274\217", nullptr)); + comboBoxMode->setItemText(4, QCoreApplication::translate("Widget", "\350\207\252\345\212\250\346\250\241\345\274\217", nullptr)); + + btnMode->setText(QCoreApplication::translate("Widget", "\345\210\207\346\215\242\346\250\241\345\274\217", nullptr)); + groupBoxStatus->setTitle(QCoreApplication::translate("Widget", "\351\243\236\350\241\214\347\212\266\346\200\201", nullptr)); + groupBoxStatus->setStyleSheet(QCoreApplication::translate("Widget", "QGroupBox {\n" +" border: 1px solid #8f8f8f;\n" +" border-radius: 5px;\n" +" margin-top: 1ex;\n" +" background-color: #f0f8ff;\n" +"}\n" +"QGroupBox::title {\n" +" subcontrol-origin: margin;\n" +" subcontrol-position: top center;\n" +" padding: 0 3px;\n" +" background-color: #f0f8ff;\n" +"}\n" +"QLabel {\n" +" font-weight: normal;\n" +" font-size: 9pt;\n" +"}\n" +"", nullptr)); + labelAltitude->setText(QCoreApplication::translate("Widget", "\351\253\230\345\272\246:", nullptr)); + valueAltitude->setText(QCoreApplication::translate("Widget", "0.0 m", nullptr)); + labelSpeed->setText(QCoreApplication::translate("Widget", "\351\200\237\345\272\246:", nullptr)); + valueSpeed->setText(QCoreApplication::translate("Widget", "0.0 m/s", nullptr)); + labelRoll->setText(QCoreApplication::translate("Widget", "\347\277\273\346\273\232:", nullptr)); + valueRoll->setText(QCoreApplication::translate("Widget", "0.0\302\260", nullptr)); + labelPitch->setText(QCoreApplication::translate("Widget", "\344\277\257\344\273\260:", nullptr)); + valuePitch->setText(QCoreApplication::translate("Widget", "0.0\302\260", nullptr)); + labelHeading->setText(QCoreApplication::translate("Widget", "\350\210\252\345\220\221:", nullptr)); + valueHeading->setText(QCoreApplication::translate("Widget", "0.0\302\260", nullptr)); + labelBattery->setText(QCoreApplication::translate("Widget", "\347\224\265\351\207\217:", nullptr)); + valueBattery->setText(QCoreApplication::translate("Widget", "0%", nullptr)); + groupBoxSoundLocator->setTitle(QCoreApplication::translate("Widget", "\345\243\260\346\272\220\345\256\232\344\275\215", nullptr)); + groupBoxSoundLocator->setStyleSheet(QCoreApplication::translate("Widget", "QGroupBox {\n" +" border: 1px solid #8f8f8f;\n" +" border-radius: 5px;\n" +" margin-top: 1ex;\n" +"}\n" +"QGroupBox::title {\n" +" subcontrol-origin: margin;\n" +" subcontrol-position: top center;\n" +" padding: 0 3px;\n" +"}\n" +"QPushButton {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +" padding: 2px;\n" +"}\n" +"QLabel {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +"}\n" +"QLineEdit {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +"}\n" +"QTextEdit {\n" +" font-size: 8pt;\n" +" font-weight: normal;\n" +"}\n" +"", nullptr)); + labelSoundIP->setText(QCoreApplication::translate("Widget", "\345\243\260\346\272\220\345\256\232\344\275\215\346\234\215\345\212\241IP:", nullptr)); + lineEditSoundIP->setText(QCoreApplication::translate("Widget", "127.0.0.1", nullptr)); + labelSoundPort->setText(QCoreApplication::translate("Widget", "\347\253\257\345\217\243:", nullptr)); + lineEditSoundPort->setText(QCoreApplication::translate("Widget", "5000", nullptr)); + btnStartSoundLocator->setText(QCoreApplication::translate("Widget", "\345\274\200\345\247\213\347\233\221\345\220\254", nullptr)); + btnStopSoundLocator->setText(QCoreApplication::translate("Widget", "\345\201\234\346\255\242\347\233\221\345\220\254", nullptr)); + textEditSoundLog->setPlaceholderText(QCoreApplication::translate("Widget", "\345\243\260\346\272\220\345\256\232\344\275\215\346\227\245\345\277\227...", nullptr)); + } // retranslateUi + +}; + +namespace Ui { + class Widget: public Ui_Widget {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // WIDGET_NEW_H diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/.gitignore b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/.gitignore new file mode 100644 index 0000000..3cbc377 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/.gitignore @@ -0,0 +1,71 @@ +# ---> VisualStudioCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +# C++ 编译生成的文件 +*.o +*.obj +*.a +*.so +*.so.* +*.dylib +*.dll +*.exe +*.out +*.app + +# Qt项目生成的文件 +*.moc +moc_*.cpp +moc_*.h +qrc_*.cpp +ui_*.h +*.qm +Makefile* +*.qmlc +*.jsc +*_qmlcache.qrc + +# 编译目录 +bin/ +debug/ +release/ +obj/ +build/ +*build-*/ + +# IDE相关文件 +.idea/ +*.swp +*.swo +*~ +*.bak +*.orig +.DS_Store + +# 临时文件 +tmp/ +temp/ +*.tmp +*.log +*.autosave + +# Linux 临时文件 +*~ + +# 由OpenCV生成的文件 +*.jpg.aux +*.png.aux + +# 保留特定文件,即使它们匹配上述模式 +!.gitignore \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/flask_app.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/flask_app.py new file mode 100644 index 0000000..bd24fb7 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/flask_app.py @@ -0,0 +1,101 @@ +import socket +import threading +import time +from flask import Flask, jsonify +from flask_cors import CORS + +app = Flask(__name__) +CORS(app) # 启用跨域支持 + +# 配置区 +TCP_IP = "0.0.0.0" +TCP_PORT = 12345 + +# 全局变量,用于存储最新数据 +latest_data = { + "X": 0.0, + "Y": 0.0, + "strength": 0.0, + "angle": 0.0 +} + +def clamp(value, min_val, max_val): + return max(min(value, max_val), min_val) + +def tcp_listener(): + """后台线程:监听 TCP 连接并更新 latest_data""" + global latest_data + server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + server_sock.bind((TCP_IP, TCP_PORT)) + server_sock.listen(1) + print(f"TCP服务器正在监听 {TCP_IP}:{TCP_PORT} ...") + client_sock, addr = server_sock.accept() + print("已接受连接:", addr) + client_sock.settimeout(0.1) + + while True: + try: + data_bytes = client_sock.recv(1024) + if not data_bytes: + print("连接已断开。") + break + line = data_bytes.decode('utf-8').strip() + if line: + # 数据格式: "X,Y,强度,Angle" + parts = line.split(',') + if len(parts) == 4: + try: + raw_x = float(parts[0]) + raw_y = float(parts[1]) + strength = float(parts[2]) + angle = float(parts[3]) + # 可自定义范围 + raw_x = clamp(raw_x, -15.0, 15.0) + raw_y = clamp(raw_y, -15.0, 15.0) + latest_data["X"] = raw_x + latest_data["Y"] = raw_y + latest_data["strength"] = strength + latest_data["angle"] = angle + + print(f"接收到声源: X={raw_x:.2f}, Y={raw_y:.2f}, 强度={strength:.2f}, 角度={angle:.2f}") + except ValueError: + print("TCP格式错误:", line) + else: + print("数据解析失败:", line) + except socket.timeout: + pass + except Exception as e: + print("TCP接收错误:", e) + time.sleep(0.1) + except Exception as e: + print(f"绑定或监听TCP端口 {TCP_PORT} 失败: {e}") + finally: + server_sock.close() + print("TCP服务器已关闭。") + +@app.route("/") +def index(): + return "后端已启动。可访问 /data 获取实时定位信息。" + +@app.route("/data") +def get_data(): + """ + 返回最新声源定位信息 + 例如: + { + "X": 1.23, + "Y": -0.45, + "strength": 2.5, + "angle": 90.0 + } + """ + return jsonify(latest_data) + +if __name__ == "__main__": + # 启动 TCP 后台线程 + t = threading.Thread(target=tcp_listener, daemon=True) + t.start() + + # 启动 Flask 服务 + app.run(host="0.0.0.0", port=5000, debug=False) \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/main.py b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/main.py new file mode 100644 index 0000000..6ad6595 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/main.py @@ -0,0 +1,259 @@ +# 声源定位+WiFi传输集成程序 +from fpioa_manager import fm +from Maix import GPIO, MIC_ARRAY as mic +from board import board_info +import network, socket, time +from machine import UART +import math + +#----------------------------- +# 1. WiFi和服务器配置 +#----------------------------- +wifi_ap_ssid = "junzekeji" # 你的WiFi SSID +wifi_ap_passwd = "234567890l" # 你的WiFi密码 +PC_IP = "192.168.32.6" # 运行sound_map.py的电脑IP +UDP_PORT = 12345 # 与sound_map.py里配置的端口一致 +TCP_PORT = 12345 # 替换你想要的端口 + +# 全局变量 +uart = None +wifi_en = None +nic = None +udp_sock = None +tcp_sock = None + +#----------------------------- +# 2. 引脚映射和WiFi使能 +#----------------------------- +def init_wifi_hardware(): + global wifi_en + # GPIOHS0 用于WiFi使能控制 + fm.register(8, fm.fpioa.GPIOHS0, force=True) + wifi_en = GPIO(GPIO.GPIOHS0, GPIO.OUT) + # 配置UART用于与ESP8285通信 + fm.register(board_info.WIFI_RX, fm.fpioa.UART2_TX, force=True) + fm.register(board_info.WIFI_TX, fm.fpioa.UART2_RX, force=True) + print("WiFi硬件引脚初始化完成。") + +def wifi_enable(en): + # 控制WiFi模块电源 + global wifi_en + if wifi_en: + wifi_en.value(en) + +#----------------------------- +# 3. 复位WiFi并连接到路由器 +#----------------------------- +def wifi_reset_and_connect(): + global uart, nic + # 复位WiFi模块 + wifi_enable(0) # 先关闭 + time.sleep_ms(200) + wifi_enable(1) # 再打开 + time.sleep(2) # 等待稳定 + + # 初始化UART,低波特率 + uart = UART(UART.UART2, 115200, timeout=1000, read_buf_len=4096) + _ = uart.read() # 清空缓存 + + # 提升波特率到921600 + uart.write("AT+UART_CUR=921600,8,1,0,0\r\n") + time.sleep_ms(100) + print("AT+UART_CUR响应:", uart.read()) + uart = UART(UART.UART2, 921600, timeout=1000, read_buf_len=4096) + + # 测试AT指令是否正常 + uart.write("AT\r\n") + time.sleep_ms(100) + at_response = uart.read() + print("AT响应:", at_response) + if not at_response or not at_response.endswith(b"OK\r\n"): + print("AT命令失败,WiFi重置失败。") + return False + + # 初始化网络对象 + try: + nic = network.ESP8285(uart) + except Exception as e: + print("ESP8285初始化失败:", e) + return False + + # 连接到WiFi网络 + print("尝试连接到WiFi: {}...".format(wifi_ap_ssid)) + try: + nic.connect(wifi_ap_ssid, wifi_ap_passwd) + attempts = 0 + while not nic.isconnected() and attempts < 20: # 最多等待20秒 + print("等待连接... {}/20".format(attempts + 1)) + time.sleep(1) + attempts += 1 + + if nic.isconnected(): + print("WiFi连接成功!") + print("IP信息:", nic.ifconfig()) + return True + else: + print("WiFi连接超时或失败。") + return False + except Exception as e: + print("连接WiFi时发生异常:", e) + return False + +#----------------------------- +# 4. 声源定位函数 +#----------------------------- +def get_mic_dir(): + AngleX = 0 + AngleY = 0 + AngleR = 0 + Angle = 0 + AngleAddPi = 0 + mic_list = [] + imga = mic.get_map() # 获取声音源分布图像 + b = mic.get_dir(imga) # 计算声源方向 + for i in range(len(b)): + if b[i] >= 2: + AngleX += b[i] * math.sin(i * math.pi / 6) + AngleY += b[i] * math.cos(i * math.pi / 6) + AngleX = round(AngleX, 6) + AngleY = round(AngleY, 6) + if AngleY < 0: + AngleAddPi = 180 + if AngleX < 0 and AngleY > 0: + AngleAddPi = 360 + if AngleX != 0 or AngleY != 0: + if AngleY == 0: + Angle = 90 if AngleX > 0 else 270 + else: + Angle = AngleAddPi + round(math.degrees(math.atan(AngleX / AngleY)), 4) + AngleR = round(math.sqrt(AngleY * AngleY + AngleX * AngleX), 4) + mic_list.append(AngleX) + mic_list.append(AngleY) + mic_list.append(AngleR) + mic_list.append(Angle) + mic.set_led(b, (0, 0, 255)) + + return mic_list + +#----------------------------- +# 5. 初始化TCP Socket +#----------------------------- +def setup_tcp_socket(): + global tcp_sock + try: + tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + tcp_sock.connect((PC_IP, TCP_PORT)) + print("TCP连接成功。") + return True + except Exception as e: + print("TCP连接失败:", e) + return False + +#----------------------------- +# 6. 主循环:连接WiFi、发送数据 +#----------------------------- +def main_loop(): + global nic, tcp_sock + + # 初始化麦克风阵列 + mic.init(i2s_d0=23, i2s_d1=22, i2s_d2=21, i2s_d3=20, + i2s_ws=19, i2s_sclk=18, + sk9822_dat=24, sk9822_clk=25) + print("麦克风阵列初始化完成。") + + # 初始化WiFi硬件 + init_wifi_hardware() + + # 不断尝试连接WiFi和设置TCP + while True: + if nic and nic.isconnected(): + if not tcp_sock: + if not setup_tcp_socket(): + print("TCP设置失败,2秒后重试...") + time.sleep(2) + nic.disconnect() + nic = None + continue + # 如果WiFi和TCP都已准备好,跳出循环 + break + else: + print("尝试连接WiFi...") + if wifi_reset_and_connect(): + if not setup_tcp_socket(): + print("TCP设置失败,断开WiFi并重试...") + nic.disconnect() + nic = None + time.sleep(2) + else: + print("WiFi连接失败,2秒后重试...") + time.sleep(2) + + print("WiFi和TCP准备就绪,开始发送声源数据到 {}:{}".format(PC_IP, TCP_PORT)) + + # 发送消息计数 + msg_count = 0 + + # 主循环:获取声源数据并发送 + while True: + # 检查WiFi连接状态 + if not nic or not nic.isconnected(): + print("WiFi连接断开,尝试重新连接...") + if tcp_sock: + tcp_sock.close() + tcp_sock = None + nic = None + # 重新启动连接流程 + main_loop() + return + + # 获取声源数据 + source_data = get_mic_dir() + if source_data: + # 解析数据: X, Y, 强度, 角度 + x, y, strength, angle = source_data + + # 打印数据用于调试 + print("麦克风定位: X={:.2f}, Y={:.2f}, 强度={:.2f}, 角度={:.2f}".format( + x, y, strength, angle)) + + # 格式化为CSV字符串发送 + data_string = "{:.4f},{:.4f},{:.4f},{:.4f}".format(x, y, strength, angle) + + try: + # 发送到PC + tcp_sock.send(data_string.encode('utf-8')) + msg_count += 1 + # 每50条显示一次发送状态 + if msg_count % 50 == 0: + print("已发送第 {} 条数据".format(msg_count)) + except Exception as e: + print("TCP发送失败:", e) + # 关闭并重新连接 + tcp_sock.close() + tcp_sock = None + nic.disconnect() + nic = None + print("将尝试重新建立连接...") + time.sleep(1) + main_loop() + return + + # 控制采样间隔 + time.sleep_ms(100) + +# 主程序入口 +if __name__ == "__main__": + try: + main_loop() + except KeyboardInterrupt: + print("用户中断程序。") + finally: + # 清理资源 + if tcp_sock: + tcp_sock.close() + print("TCP socket已关闭。") + if nic and nic.isconnected(): + nic.disconnect() + print("WiFi已断开。") + wifi_enable(0) # 关闭WiFi模块 + print("程序结束。") diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/.gitignore b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/.gitignore new file mode 100644 index 0000000..d6294d5 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/.gitignore @@ -0,0 +1,52 @@ +# Vue.js 项目的 .gitignore 文件 + +# 依赖目录 +node_modules/ + +# 构建输出目录 +/dist +/build + +# 本地环境配置文件 +.env.local +.env.*.local + +# 日志文件 +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# 编辑器目录和文件 +.idea/ +.vscode/ +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# 系统文件 +.DS_Store +Thumbs.db + +# 测试覆盖率报告 +/coverage + +# 特定于 Vue CLI 的文件 +.history/ +.firebase/ +.firebase.json +.firebaserc + +# 缓存目录 +.npm/ +.eslintcache +.stylelintcache +.history/ +.cache/ + +# 临时文件 +*.tmp +*.temp +*.bak diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/README.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/README.md new file mode 100644 index 0000000..d9f55cf --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/README.md @@ -0,0 +1,38 @@ +# 声源定位系统前端 + +基于 Vue.js 和 ECharts 实现的声源定位可视化系统,与 Flask 后端通信获取实时声源数据。 + +## 功能特点 + +- 实时显示声源位置 (X, Y 坐标) +- 可视化声源强度和方向 +- 支持开始/停止监听控制 +- 专业企业级 UI 设计 + +## 项目设置 + +### 安装依赖 +``` +npm install +``` + +### 开发环境运行 +``` +npm run serve +``` + +### 生产环境构建 +``` +npm run build +``` + +## 配置说明 + +后端 API 地址可在 `App.vue` 中的 `API_BASE_URL` 变量修改。 + +## 使用方法 + +1. 确保 Flask 后端已启动并在指定端口运行 +2. 启动前端应用 +3. 点击"开始监听"按钮开始获取实时数据 +4. 声源位置、强度和方向将在可视化图表中实时显示 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/index.html b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/index.html new file mode 100644 index 0000000..76d63b8 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + 声源定位系统 + + +
+ + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/package-lock.json b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/package-lock.json new file mode 100644 index 0000000..f80dd28 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/package-lock.json @@ -0,0 +1,19934 @@ +{ + "name": "sound-vue-frontend", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "sound-vue-frontend", + "version": "0.1.0", + "dependencies": { + "axios": "^1.3.4", + "core-js": "^3.8.3", + "echarts": "^5.4.1", + "element-plus": "^2.3.0", + "vue": "^3.2.13" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "eslint": "^7.32.0", + "eslint-plugin-vue": "^8.0.3" + } + }, + "node_modules/@achrinza/node-ipc": { + "version": "9.2.9", + "resolved": "https://registry.npmjs.org/@achrinza/node-ipc/-/node-ipc-9.2.9.tgz", + "integrity": "sha512-7s0VcTwiK/0tNOVdSX9FWMeFdOEcsAOz9HesBldXxFMaGvIak7KC2z9tV9EgsQXn6KUsWsfIkViMNuIo0GoZDQ==", + "dev": true, + "dependencies": { + "@node-ipc/js-queue": "2.0.3", + "event-pubsub": "4.3.0", + "js-message": "1.0.7" + }, + "engines": { + "node": "8 || 9 || 10 || 11 || 12 || 13 || 14 || 15 || 16 || 17 || 18 || 19 || 20 || 21 || 22" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz", + "integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", + "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helpers": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz", + "integrity": "sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==", + "dev": true, + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", + "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", + "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", + "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", + "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", + "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.27.1.tgz", + "integrity": "sha512-DTxe4LBPrtFdsWzgpmbBKevg3e9PBy+dXRt19kSbucbZvL2uqtdqwwpluL1jfxYE0wIDTFp1nTy/q6gNLsxXrg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-decorators": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz", + "integrity": "sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz", + "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.1.tgz", + "integrity": "sha512-QEcFlMl9nGTgh1rn2nIeU5bkfb9BAjaQcWbiP4LvKxUot52ABcTkpcyJ7f2Q2U2RuQ84BNLgts3jRme2dTx6Fw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", + "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz", + "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.1.tgz", + "integrity": "sha512-ttDCqhfvpE9emVkXbPD8vyxxh4TWYACVybGkDj+oReOGwnp066ITEivDlLwe0b1R0+evJ13IXQuLNB5w1fhC5Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.2.tgz", + "integrity": "sha512-AIUHD7xJ1mCrj3uPozvtngY3s0xpv7Nu7DoUSnzNY6Xam1Cy4rUznR//pvMHOhQ4AvbCexhbqXCtpxGHOGOO6g==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz", + "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.1.tgz", + "integrity": "sha512-B19lbbL7PMrKr52BNPjCqg1IyNUIjTcxKj8uX9zHO+PmWN93s19NDr/f69mIkEp2x9nmDJ08a7lgHaTTzvW7mw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.1.tgz", + "integrity": "sha512-TqGF3desVsTcp3WrJGj4HfKokfCXCLcHpt4PJF0D8/iT6LPd9RS82Upw3KPeyr6B22Lfd3DO8MVrmp0oRkUDdw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.2.tgz", + "integrity": "sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.27.1", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.27.1", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.27.2", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.27.1", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.40.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", + "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz", + "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz", + "integrity": "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.0.tgz", + "integrity": "sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==", + "dependencies": { + "@floating-ui/core": "^1.7.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==" + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@node-ipc/js-queue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@node-ipc/js-queue/-/js-queue-2.0.3.tgz", + "integrity": "sha512-fL1wpr8hhD5gT2dA1qifeVaoDFlQR5es8tFuKqjHX+kdOtdNHnxkVZbtIrR2rxnMFvehkjaZRNV2H/gPXlb0hw==", + "dev": true, + "dependencies": { + "easy-stack": "1.0.1" + }, + "engines": { + "node": ">=1.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.7", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "node_modules/@soda/friendly-errors-webpack-plugin": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz", + "integrity": "sha512-h2ooWqP8XuFqTXT+NyAFbrArzfQA7R6HTezADrvD9Re8fxMLTPPniLdqVTdDaO0eIoLaAwKT+d6w+5GeTk7Vbg==", + "dev": true, + "dependencies": { + "chalk": "^3.0.0", + "error-stack-parser": "^2.0.6", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@soda/get-current-script": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@soda/get-current-script/-/get-current-script-1.0.2.tgz", + "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", + "dev": true + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.12", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", + "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", + "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.16", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", + "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", + "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, + "node_modules/@types/node": { + "version": "22.15.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz", + "integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==", + "dev": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", + "integrity": "sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==", + "dev": true + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.4.0.tgz", + "integrity": "sha512-mCokbouEQ/ocRce/FpKCRItGo+013tHg7tixg3DUNS+6bmIchPt66012kBMm476vyEIJPafrvOf4E5OYj3shSw==", + "dev": true + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.4.0.tgz", + "integrity": "sha512-9zAHmwgMWlaN6qRKdrg1uKsBKHvnUU+Py+MOCTuYZBoZsopa90Di10QRjB+YPnVss0BZbG/H5XFwJY1fTxJWhA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.9", + "@babel/types": "^7.26.9", + "@vue/babel-helper-vue-transform-on": "1.4.0", + "@vue/babel-plugin-resolve-type": "1.4.0", + "@vue/shared": "^3.5.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.4.0.tgz", + "integrity": "sha512-4xqDRRbQQEWHQyjlYSgZsWj44KfiF6D+ktCuXyZ8EnVDYV3pztmXJDf1HveAjUAXxAnR8daCQT51RneWWxtTyQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/parser": "^7.26.9", + "@vue/compiler-sfc": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-plugin-transform-vue-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.4.0.tgz", + "integrity": "sha512-Fmastxw4MMx0vlgLS4XBX0XiBbUFzoMGeVXuMV08wyOfXdikAFqBTuYPR0tlk+XskL19EzHc39SgjrPGY23JnA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-preset-app": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-5.0.8.tgz", + "integrity": "sha512-yl+5qhpjd8e1G4cMXfORkkBlvtPCIgmRf3IYCWYDKIQ7m+PPa5iTm4feiNmCMD6yGqQWMhhK/7M3oWGL9boKwg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.16", + "@babel/helper-compilation-targets": "^7.12.16", + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-proposal-class-properties": "^7.12.13", + "@babel/plugin-proposal-decorators": "^7.12.13", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/plugin-transform-runtime": "^7.12.15", + "@babel/preset-env": "^7.12.16", + "@babel/runtime": "^7.12.13", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.1.2", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.8.3", + "core-js-compat": "^3.8.3", + "semver": "^7.3.4" + }, + "peerDependencies": { + "@babel/core": "*", + "core-js": "^3", + "vue": "^2 || ^3.2.13" + }, + "peerDependenciesMeta": { + "core-js": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-preset-app/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/babel-preset-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.4.0.tgz", + "integrity": "sha512-QmfRpssBOPZWL5xw7fOuHNifCQcNQC1PrOo/4fu6xlhlKJJKSA3HqX92Nvgyx8fqHZTUGMPHmFA+IDqwXlqkSA==", + "dev": true, + "dependencies": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "@vue/babel-sugar-composition-api-inject-h": "^1.4.0", + "@vue/babel-sugar-composition-api-render-instance": "^1.4.0", + "@vue/babel-sugar-functional-vue": "^1.4.0", + "@vue/babel-sugar-inject-h": "^1.4.0", + "@vue/babel-sugar-v-model": "^1.4.0", + "@vue/babel-sugar-v-on": "^1.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "vue": "*" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-sugar-composition-api-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.4.0.tgz", + "integrity": "sha512-VQq6zEddJHctnG4w3TfmlVp5FzDavUSut/DwR0xVoe/mJKXyMcsIibL42wPntozITEoY90aBV0/1d2KjxHU52g==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-composition-api-render-instance": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.4.0.tgz", + "integrity": "sha512-6ZDAzcxvy7VcnCjNdHJ59mwK02ZFuP5CnucloidqlZwVQv5CQLijc3lGpR7MD3TWFi78J7+a8J56YxbCtHgT9Q==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-functional-vue": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.4.0.tgz", + "integrity": "sha512-lTEB4WUFNzYt2In6JsoF9sAYVTo84wC4e+PoZWSgM6FUtqRJz7wMylaEhSRgG71YF+wfLD6cc9nqVeXN2rwBvw==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.4.0.tgz", + "integrity": "sha512-muwWrPKli77uO2fFM7eA3G1lAGnERuSz2NgAxuOLzrsTlQl8W4G+wwbM4nB6iewlKbwKRae3nL03UaF5ffAPMA==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-model": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.4.0.tgz", + "integrity": "sha512-0t4HGgXb7WHYLBciZzN5s0Hzqan4Ue+p/3FdQdcaHAb7s5D9WZFGoSxEZHrR1TFVZlAPu1bejTKGeAzaaG3NCQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/babel-sugar-v-on": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.4.0.tgz", + "integrity": "sha512-m+zud4wKLzSKgQrWwhqRObWzmTuyzl6vOP7024lrpeJM4x2UhQtRDLgYjXAw9xBXjCwS0pP9kXjg91F9ZNo9JA==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/cli-overlay": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.8.tgz", + "integrity": "sha512-KmtievE/B4kcXp6SuM2gzsnSd8WebkQpg3XaB6GmFh1BJGRqa1UiW9up7L/Q67uOdTigHxr5Ar2lZms4RcDjwQ==", + "dev": true + }, + "node_modules/@vue/cli-plugin-babel": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-babel/-/cli-plugin-babel-5.0.8.tgz", + "integrity": "sha512-a4qqkml3FAJ3auqB2kN2EMPocb/iu0ykeELwed+9B1c1nQ1HKgslKMHMPavYx3Cd/QAx2mBD4hwKBqZXEI/CsQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.16", + "@vue/babel-preset-app": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "babel-loader": "^8.2.2", + "thread-loader": "^3.0.0", + "webpack": "^5.54.0" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-plugin-eslint": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-5.0.8.tgz", + "integrity": "sha512-d11+I5ONYaAPW1KyZj9GlrV/E6HZePq5L5eAF5GgoVdu6sxr6bDgEoxzhcS1Pk2eh8rn1MxG/FyyR+eCBj/CNg==", + "dev": true, + "dependencies": { + "@vue/cli-shared-utils": "^5.0.8", + "eslint-webpack-plugin": "^3.1.0", + "globby": "^11.0.2", + "webpack": "^5.54.0", + "yorkie": "^2.0.0" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0", + "eslint": ">=7.5.0" + } + }, + "node_modules/@vue/cli-plugin-router": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-5.0.8.tgz", + "integrity": "sha512-Gmv4dsGdAsWPqVijz3Ux2OS2HkMrWi1ENj2cYL75nUeL+Xj5HEstSqdtfZ0b1q9NCce+BFB6QnHfTBXc/fCvMg==", + "dev": true, + "dependencies": { + "@vue/cli-shared-utils": "^5.0.8" + }, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-plugin-vuex": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.8.tgz", + "integrity": "sha512-HSYWPqrunRE5ZZs8kVwiY6oWcn95qf/OQabwLfprhdpFWAGtLStShjsGED2aDpSSeGAskQETrtR/5h7VqgIlBA==", + "dev": true, + "peerDependencies": { + "@vue/cli-service": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + } + }, + "node_modules/@vue/cli-service": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-5.0.8.tgz", + "integrity": "sha512-nV7tYQLe7YsTtzFrfOMIHc5N2hp5lHG2rpYr0aNja9rNljdgcPZLyQRb2YRivTHqTv7lI962UXFURcpStHgyFw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.12.16", + "@soda/friendly-errors-webpack-plugin": "^1.8.0", + "@soda/get-current-script": "^1.0.2", + "@types/minimist": "^1.2.0", + "@vue/cli-overlay": "^5.0.8", + "@vue/cli-plugin-router": "^5.0.8", + "@vue/cli-plugin-vuex": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "@vue/component-compiler-utils": "^3.3.0", + "@vue/vue-loader-v15": "npm:vue-loader@^15.9.7", + "@vue/web-component-wrapper": "^1.3.0", + "acorn": "^8.0.5", + "acorn-walk": "^8.0.2", + "address": "^1.1.2", + "autoprefixer": "^10.2.4", + "browserslist": "^4.16.3", + "case-sensitive-paths-webpack-plugin": "^2.3.0", + "cli-highlight": "^2.1.10", + "clipboardy": "^2.3.0", + "cliui": "^7.0.4", + "copy-webpack-plugin": "^9.0.1", + "css-loader": "^6.5.0", + "css-minimizer-webpack-plugin": "^3.0.2", + "cssnano": "^5.0.0", + "debug": "^4.1.1", + "default-gateway": "^6.0.3", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "hash-sum": "^2.0.0", + "html-webpack-plugin": "^5.1.0", + "is-file-esm": "^1.0.0", + "launch-editor-middleware": "^2.2.1", + "lodash.defaultsdeep": "^4.6.1", + "lodash.mapvalues": "^4.6.0", + "mini-css-extract-plugin": "^2.5.3", + "minimist": "^1.2.5", + "module-alias": "^2.2.2", + "portfinder": "^1.0.26", + "postcss": "^8.2.6", + "postcss-loader": "^6.1.1", + "progress-webpack-plugin": "^1.0.12", + "ssri": "^8.0.1", + "terser-webpack-plugin": "^5.1.1", + "thread-loader": "^3.0.0", + "vue-loader": "^17.0.0", + "vue-style-loader": "^4.1.3", + "webpack": "^5.54.0", + "webpack-bundle-analyzer": "^4.4.0", + "webpack-chain": "^6.5.1", + "webpack-dev-server": "^4.7.3", + "webpack-merge": "^5.7.3", + "webpack-virtual-modules": "^0.4.2", + "whatwg-fetch": "^3.6.2" + }, + "bin": { + "vue-cli-service": "bin/vue-cli-service.js" + }, + "engines": { + "node": "^12.0.0 || >= 14.0.0" + }, + "peerDependencies": { + "vue-template-compiler": "^2.0.0", + "webpack-sources": "*" + }, + "peerDependenciesMeta": { + "cache-loader": { + "optional": true + }, + "less-loader": { + "optional": true + }, + "pug-plain-loader": { + "optional": true + }, + "raw-loader": { + "optional": true + }, + "sass-loader": { + "optional": true + }, + "stylus-loader": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/@vue/cli-shared-utils": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.8.tgz", + "integrity": "sha512-uK2YB7bBVuQhjOJF+O52P9yFMXeJVj7ozqJkwYE9PlMHL1LMHjtCYm4cSdOebuPzyP+/9p0BimM/OqxsevIopQ==", + "dev": true, + "dependencies": { + "@achrinza/node-ipc": "^9.2.5", + "chalk": "^4.1.2", + "execa": "^1.0.0", + "joi": "^17.4.0", + "launch-editor": "^2.2.1", + "lru-cache": "^6.0.0", + "node-fetch": "^2.6.7", + "open": "^8.0.2", + "ora": "^5.3.0", + "read-pkg": "^5.1.1", + "semver": "^7.3.4", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vue/cli-shared-utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "dependencies": { + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/component-compiler-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", + "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", + "dev": true, + "dependencies": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "optionalDependencies": { + "prettier": "^1.18.2 || ^2.0.0" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "node_modules/@vue/component-compiler-utils/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/@vue/reactivity": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "dependencies": { + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "dependencies": { + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "vue": "3.5.13" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==" + }, + "node_modules/@vue/vue-loader-v15": { + "name": "vue-loader", + "version": "15.11.1", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.11.1.tgz", + "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==", + "dev": true, + "dependencies": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "peerDependencies": { + "css-loader": "*", + "webpack": "^3.0.0 || ^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "cache-loader": { + "optional": true + }, + "prettier": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/@vue/vue-loader-v15/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/@vue/web-component-wrapper": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz", + "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", + "dev": true + }, + "node_modules/@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "dependencies": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "dependencies": { + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", + "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.4", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", + "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.4" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", + "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001716", + "electron-to-chromium": "^1.5.149", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001718", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", + "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboardy": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz", + "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", + "dev": true, + "dependencies": { + "arch": "^2.1.1", + "execa": "^1.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog", + "dev": true, + "dependencies": { + "bluebird": "^3.1.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.1", + "globby": "^11.0.3", + "normalize-path": "^3.0.0", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz", + "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.42.0.tgz", + "integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.24.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dev": true, + "dependencies": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dev": true, + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/default-gateway/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-gateway/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/easy-stack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", + "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.152", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.152.tgz", + "integrity": "sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg==", + "dev": true + }, + "node_modules/element-plus": { + "version": "2.9.10", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.10.tgz", + "integrity": "sha512-W2v9jWnm1kl/zm4bSvCh8aFCVlxvhG3fmqiDZwyd6WQiWGE595J/mpjcCggEr+49QDgIymhXrpPMOPPSARUbng==", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.13", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-plugin-vue/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-pubsub": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", + "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/execa/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "dependencies": { + "ci-info": "^1.5.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-file-esm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-file-esm/-/is-file-esm-1.0.0.tgz", + "integrity": "sha512-rZlaNKb4Mr8WlRu2A9XdeoKgnO5aA53XdPHgCKVyCrQ/rWi89RET1+bq37Ru46obaQXeiX4vmFIm1vks41hoSA==", + "dev": true, + "dependencies": { + "read-pkg-up": "^7.0.1" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-message": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", + "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==", + "dev": true, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/launch-editor": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", + "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/launch-editor-middleware": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.10.0.tgz", + "integrity": "sha512-RzZu7MeVlE3p1H6Sadc2BhuDGAj7bkeDCBpNq/zSENP4ohJGhso00k5+iYaRwKshIpiOAhMmimce+5D389xmSg==", + "dev": true, + "dependencies": { + "launch-editor": "^2.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/loader-utils/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", + "dev": true + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "node_modules/lodash.mapvalues": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ==", + "dev": true, + "dependencies": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/module-alias": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==", + "dev": true + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/portfinder": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.37.tgz", + "integrity": "sha512-yuGIEjDAYnnOex9ddMnKZEMFE0CcGo6zbfzDklkmT1m5z734ss6JMzN9rNB3+RR7iS+F10D4/BVIaXOyh8PQKw==", + "dev": true, + "dependencies": { + "async": "^3.2.6", + "debug": "^4.3.6" + }, + "engines": { + "node": ">= 10.12" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dev": true, + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dev": true, + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dev": true, + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/progress-webpack-plugin": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/progress-webpack-plugin/-/progress-webpack-plugin-1.0.16.tgz", + "integrity": "sha512-sdiHuuKOzELcBANHfrupYo+r99iPRyOnw15qX+rNlVUqXGfjXdH4IgxriKwG1kNJwVswKQHMdj1hYZMcb9jFaA==", + "dev": true, + "dependencies": { + "chalk": "^2.1.0", + "figures": "^2.0.0", + "log-update": "^2.3.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "peerDependencies": { + "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/progress-webpack-plugin/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/progress-webpack-plugin/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/progress-webpack-plugin/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/progress-webpack-plugin/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress-webpack-plugin/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", + "dev": true + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.39.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.1.tgz", + "integrity": "sha512-Mm6+uad0ZuDtcV8/4uOZQDQ8RuiC5Pu+iZRedJtF7yA/27sPL7d++In/AJKpWZlU3SYMPPkVfwetn6sgZ66pUA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/thread-loader": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/thread-loader/-/thread-loader-3.0.4.tgz", + "integrity": "sha512-ByaL2TPb+m6yArpqQUZvP+5S1mZtXsEP7nWKKlAUTm7fCml8kB5s1uI3+eHRP2bk5mVYfRSBI7FFf+tWEyLZwA==", + "dev": true, + "dependencies": { + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.1.0", + "loader-utils": "^2.0.0", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.27.0 || ^5.0.0" + } + }, + "node_modules/thread-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/thread-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vue": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", + "dev": true + }, + "node_modules/vue-loader": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.4.2.tgz", + "integrity": "sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "watchpack": "^2.4.0" + }, + "peerDependencies": { + "webpack": "^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/vue-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/vue-style-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", + "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", + "dev": true, + "dependencies": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + } + }, + "node_modules/vue-style-loader/node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "node_modules/vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/webpack": { + "version": "5.99.8", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.8.tgz", + "integrity": "sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.2", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-chain": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-6.5.1.tgz", + "integrity": "sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz", + "integrity": "sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==", + "dev": true + }, + "node_modules/webpack/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yorkie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz", + "integrity": "sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "execa": "^0.8.0", + "is-ci": "^1.0.10", + "normalize-path": "^1.0.0", + "strip-indent": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/yorkie/node_modules/execa": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", + "integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/yorkie/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/yorkie/node_modules/normalize-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz", + "integrity": "sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yorkie/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/yorkie/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "dependencies": { + "tslib": "2.3.0" + } + } + }, + "dependencies": { + "@achrinza/node-ipc": { + "version": "9.2.9", + "resolved": "https://registry.npmjs.org/@achrinza/node-ipc/-/node-ipc-9.2.9.tgz", + "integrity": "sha512-7s0VcTwiK/0tNOVdSX9FWMeFdOEcsAOz9HesBldXxFMaGvIak7KC2z9tV9EgsQXn6KUsWsfIkViMNuIo0GoZDQ==", + "dev": true, + "requires": { + "@node-ipc/js-queue": "2.0.3", + "event-pubsub": "4.3.0", + "js-message": "1.0.7" + } + }, + "@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + } + }, + "@babel/compat-data": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz", + "integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==", + "dev": true + }, + "@babel/core": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", + "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helpers": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + } + }, + "@babel/generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", + "dev": true, + "requires": { + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz", + "integrity": "sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==", + "dev": true, + "requires": { + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", + "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "requires": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-module-transforms": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", + "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "requires": { + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" + }, + "@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==" + }, + "@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "dev": true, + "requires": { + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/helpers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", + "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", + "dev": true, + "requires": { + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", + "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", + "requires": { + "@babel/types": "^7.27.1" + } + }, + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + } + }, + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", + "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.27.1.tgz", + "integrity": "sha512-DTxe4LBPrtFdsWzgpmbBKevg3e9PBy+dXRt19kSbucbZvL2uqtdqwwpluL1jfxYE0wIDTFp1nTy/q6gNLsxXrg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-decorators": "^7.27.1" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "requires": {} + }, + "@babel/plugin-syntax-decorators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz", + "integrity": "sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz", + "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.1.tgz", + "integrity": "sha512-QEcFlMl9nGTgh1rn2nIeU5bkfb9BAjaQcWbiP4LvKxUot52ABcTkpcyJ7f2Q2U2RuQ84BNLgts3jRme2dTx6Fw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", + "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz", + "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.1.tgz", + "integrity": "sha512-ttDCqhfvpE9emVkXbPD8vyxxh4TWYACVybGkDj+oReOGwnp066ITEivDlLwe0b1R0+evJ13IXQuLNB5w1fhC5Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.2.tgz", + "integrity": "sha512-AIUHD7xJ1mCrj3uPozvtngY3s0xpv7Nu7DoUSnzNY6Xam1Cy4rUznR//pvMHOhQ4AvbCexhbqXCtpxGHOGOO6g==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz", + "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.1.tgz", + "integrity": "sha512-B19lbbL7PMrKr52BNPjCqg1IyNUIjTcxKj8uX9zHO+PmWN93s19NDr/f69mIkEp2x9nmDJ08a7lgHaTTzvW7mw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.1.tgz", + "integrity": "sha512-TqGF3desVsTcp3WrJGj4HfKokfCXCLcHpt4PJF0D8/iT6LPd9RS82Upw3KPeyr6B22Lfd3DO8MVrmp0oRkUDdw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + } + }, + "@babel/preset-env": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.2.tgz", + "integrity": "sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.27.1", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.27.1", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.27.2", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.27.1", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.40.0", + "semver": "^6.3.1" + } + }, + "@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "dev": true + }, + "@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + } + }, + "@babel/traverse": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", + "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", + "debug": "^4.3.1", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "requires": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + } + }, + "@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==" + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@element-plus/icons-vue": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz", + "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==", + "requires": {} + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@floating-ui/core": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz", + "integrity": "sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==", + "requires": { + "@floating-ui/utils": "^0.2.9" + } + }, + "@floating-ui/dom": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.0.tgz", + "integrity": "sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==", + "requires": { + "@floating-ui/core": "^1.7.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==" + }, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "@node-ipc/js-queue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@node-ipc/js-queue/-/js-queue-2.0.3.tgz", + "integrity": "sha512-fL1wpr8hhD5gT2dA1qifeVaoDFlQR5es8tFuKqjHX+kdOtdNHnxkVZbtIrR2rxnMFvehkjaZRNV2H/gPXlb0hw==", + "dev": true, + "requires": { + "easy-stack": "1.0.1" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true + }, + "@popperjs/core": { + "version": "npm:@sxzz/popperjs-es@2.11.7", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==" + }, + "@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "@soda/friendly-errors-webpack-plugin": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz", + "integrity": "sha512-h2ooWqP8XuFqTXT+NyAFbrArzfQA7R6HTezADrvD9Re8fxMLTPPniLdqVTdDaO0eIoLaAwKT+d6w+5GeTk7Vbg==", + "dev": true, + "requires": { + "chalk": "^3.0.0", + "error-stack-parser": "^2.0.6", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + } + }, + "@soda/get-current-script": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@soda/get-current-script/-/get-current-script-1.0.2.tgz", + "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", + "dev": true + }, + "@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true + }, + "@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/eslint": { + "version": "8.56.12", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", + "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true + }, + "@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + }, + "dependencies": { + "@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + } + } + }, + "@types/express-serve-static-core": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", + "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "@types/http-proxy": { + "version": "1.17.16", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", + "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "@types/lodash": { + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", + "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==" + }, + "@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "requires": { + "@types/lodash": "*" + } + }, + "@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, + "@types/node": { + "version": "22.15.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.17.tgz", + "integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==", + "dev": true, + "requires": { + "undici-types": "~6.21.0" + } + }, + "@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "@types/qs": { + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "requires": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" + }, + "@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", + "integrity": "sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==", + "dev": true + }, + "@vue/babel-helper-vue-transform-on": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.4.0.tgz", + "integrity": "sha512-mCokbouEQ/ocRce/FpKCRItGo+013tHg7tixg3DUNS+6bmIchPt66012kBMm476vyEIJPafrvOf4E5OYj3shSw==", + "dev": true + }, + "@vue/babel-plugin-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.4.0.tgz", + "integrity": "sha512-9zAHmwgMWlaN6qRKdrg1uKsBKHvnUU+Py+MOCTuYZBoZsopa90Di10QRjB+YPnVss0BZbG/H5XFwJY1fTxJWhA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.9", + "@babel/types": "^7.26.9", + "@vue/babel-helper-vue-transform-on": "1.4.0", + "@vue/babel-plugin-resolve-type": "1.4.0", + "@vue/shared": "^3.5.13" + } + }, + "@vue/babel-plugin-resolve-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.4.0.tgz", + "integrity": "sha512-4xqDRRbQQEWHQyjlYSgZsWj44KfiF6D+ktCuXyZ8EnVDYV3pztmXJDf1HveAjUAXxAnR8daCQT51RneWWxtTyQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.26.2", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/parser": "^7.26.9", + "@vue/compiler-sfc": "^3.5.13" + } + }, + "@vue/babel-plugin-transform-vue-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.4.0.tgz", + "integrity": "sha512-Fmastxw4MMx0vlgLS4XBX0XiBbUFzoMGeVXuMV08wyOfXdikAFqBTuYPR0tlk+XskL19EzHc39SgjrPGY23JnA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + } + }, + "@vue/babel-preset-app": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-5.0.8.tgz", + "integrity": "sha512-yl+5qhpjd8e1G4cMXfORkkBlvtPCIgmRf3IYCWYDKIQ7m+PPa5iTm4feiNmCMD6yGqQWMhhK/7M3oWGL9boKwg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.16", + "@babel/helper-compilation-targets": "^7.12.16", + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-proposal-class-properties": "^7.12.13", + "@babel/plugin-proposal-decorators": "^7.12.13", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/plugin-transform-runtime": "^7.12.15", + "@babel/preset-env": "^7.12.16", + "@babel/runtime": "^7.12.13", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.1.2", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.8.3", + "core-js-compat": "^3.8.3", + "semver": "^7.3.4" + }, + "dependencies": { + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "@vue/babel-preset-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.4.0.tgz", + "integrity": "sha512-QmfRpssBOPZWL5xw7fOuHNifCQcNQC1PrOo/4fu6xlhlKJJKSA3HqX92Nvgyx8fqHZTUGMPHmFA+IDqwXlqkSA==", + "dev": true, + "requires": { + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "@vue/babel-sugar-composition-api-inject-h": "^1.4.0", + "@vue/babel-sugar-composition-api-render-instance": "^1.4.0", + "@vue/babel-sugar-functional-vue": "^1.4.0", + "@vue/babel-sugar-inject-h": "^1.4.0", + "@vue/babel-sugar-v-model": "^1.4.0", + "@vue/babel-sugar-v-on": "^1.4.0" + } + }, + "@vue/babel-sugar-composition-api-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.4.0.tgz", + "integrity": "sha512-VQq6zEddJHctnG4w3TfmlVp5FzDavUSut/DwR0xVoe/mJKXyMcsIibL42wPntozITEoY90aBV0/1d2KjxHU52g==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-composition-api-render-instance": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.4.0.tgz", + "integrity": "sha512-6ZDAzcxvy7VcnCjNdHJ59mwK02ZFuP5CnucloidqlZwVQv5CQLijc3lGpR7MD3TWFi78J7+a8J56YxbCtHgT9Q==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-functional-vue": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.4.0.tgz", + "integrity": "sha512-lTEB4WUFNzYt2In6JsoF9sAYVTo84wC4e+PoZWSgM6FUtqRJz7wMylaEhSRgG71YF+wfLD6cc9nqVeXN2rwBvw==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.4.0.tgz", + "integrity": "sha512-muwWrPKli77uO2fFM7eA3G1lAGnERuSz2NgAxuOLzrsTlQl8W4G+wwbM4nB6iewlKbwKRae3nL03UaF5ffAPMA==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@vue/babel-sugar-v-model": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.4.0.tgz", + "integrity": "sha512-0t4HGgXb7WHYLBciZzN5s0Hzqan4Ue+p/3FdQdcaHAb7s5D9WZFGoSxEZHrR1TFVZlAPu1bejTKGeAzaaG3NCQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + } + }, + "@vue/babel-sugar-v-on": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.4.0.tgz", + "integrity": "sha512-m+zud4wKLzSKgQrWwhqRObWzmTuyzl6vOP7024lrpeJM4x2UhQtRDLgYjXAw9xBXjCwS0pP9kXjg91F9ZNo9JA==", + "dev": true, + "requires": { + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0" + } + }, + "@vue/cli-overlay": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.8.tgz", + "integrity": "sha512-KmtievE/B4kcXp6SuM2gzsnSd8WebkQpg3XaB6GmFh1BJGRqa1UiW9up7L/Q67uOdTigHxr5Ar2lZms4RcDjwQ==", + "dev": true + }, + "@vue/cli-plugin-babel": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-babel/-/cli-plugin-babel-5.0.8.tgz", + "integrity": "sha512-a4qqkml3FAJ3auqB2kN2EMPocb/iu0ykeELwed+9B1c1nQ1HKgslKMHMPavYx3Cd/QAx2mBD4hwKBqZXEI/CsQ==", + "dev": true, + "requires": { + "@babel/core": "^7.12.16", + "@vue/babel-preset-app": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "babel-loader": "^8.2.2", + "thread-loader": "^3.0.0", + "webpack": "^5.54.0" + } + }, + "@vue/cli-plugin-eslint": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-5.0.8.tgz", + "integrity": "sha512-d11+I5ONYaAPW1KyZj9GlrV/E6HZePq5L5eAF5GgoVdu6sxr6bDgEoxzhcS1Pk2eh8rn1MxG/FyyR+eCBj/CNg==", + "dev": true, + "requires": { + "@vue/cli-shared-utils": "^5.0.8", + "eslint-webpack-plugin": "^3.1.0", + "globby": "^11.0.2", + "webpack": "^5.54.0", + "yorkie": "^2.0.0" + } + }, + "@vue/cli-plugin-router": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-5.0.8.tgz", + "integrity": "sha512-Gmv4dsGdAsWPqVijz3Ux2OS2HkMrWi1ENj2cYL75nUeL+Xj5HEstSqdtfZ0b1q9NCce+BFB6QnHfTBXc/fCvMg==", + "dev": true, + "requires": { + "@vue/cli-shared-utils": "^5.0.8" + } + }, + "@vue/cli-plugin-vuex": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-5.0.8.tgz", + "integrity": "sha512-HSYWPqrunRE5ZZs8kVwiY6oWcn95qf/OQabwLfprhdpFWAGtLStShjsGED2aDpSSeGAskQETrtR/5h7VqgIlBA==", + "dev": true, + "requires": {} + }, + "@vue/cli-service": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-5.0.8.tgz", + "integrity": "sha512-nV7tYQLe7YsTtzFrfOMIHc5N2hp5lHG2rpYr0aNja9rNljdgcPZLyQRb2YRivTHqTv7lI962UXFURcpStHgyFw==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.12.16", + "@soda/friendly-errors-webpack-plugin": "^1.8.0", + "@soda/get-current-script": "^1.0.2", + "@types/minimist": "^1.2.0", + "@vue/cli-overlay": "^5.0.8", + "@vue/cli-plugin-router": "^5.0.8", + "@vue/cli-plugin-vuex": "^5.0.8", + "@vue/cli-shared-utils": "^5.0.8", + "@vue/component-compiler-utils": "^3.3.0", + "@vue/vue-loader-v15": "npm:vue-loader@^15.9.7", + "@vue/web-component-wrapper": "^1.3.0", + "acorn": "^8.0.5", + "acorn-walk": "^8.0.2", + "address": "^1.1.2", + "autoprefixer": "^10.2.4", + "browserslist": "^4.16.3", + "case-sensitive-paths-webpack-plugin": "^2.3.0", + "cli-highlight": "^2.1.10", + "clipboardy": "^2.3.0", + "cliui": "^7.0.4", + "copy-webpack-plugin": "^9.0.1", + "css-loader": "^6.5.0", + "css-minimizer-webpack-plugin": "^3.0.2", + "cssnano": "^5.0.0", + "debug": "^4.1.1", + "default-gateway": "^6.0.3", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "hash-sum": "^2.0.0", + "html-webpack-plugin": "^5.1.0", + "is-file-esm": "^1.0.0", + "launch-editor-middleware": "^2.2.1", + "lodash.defaultsdeep": "^4.6.1", + "lodash.mapvalues": "^4.6.0", + "mini-css-extract-plugin": "^2.5.3", + "minimist": "^1.2.5", + "module-alias": "^2.2.2", + "portfinder": "^1.0.26", + "postcss": "^8.2.6", + "postcss-loader": "^6.1.1", + "progress-webpack-plugin": "^1.0.12", + "ssri": "^8.0.1", + "terser-webpack-plugin": "^5.1.1", + "thread-loader": "^3.0.0", + "vue-loader": "^17.0.0", + "vue-style-loader": "^4.1.3", + "webpack": "^5.54.0", + "webpack-bundle-analyzer": "^4.4.0", + "webpack-chain": "^6.5.1", + "webpack-dev-server": "^4.7.3", + "webpack-merge": "^5.7.3", + "webpack-virtual-modules": "^0.4.2", + "whatwg-fetch": "^3.6.2" + } + }, + "@vue/cli-shared-utils": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-5.0.8.tgz", + "integrity": "sha512-uK2YB7bBVuQhjOJF+O52P9yFMXeJVj7ozqJkwYE9PlMHL1LMHjtCYm4cSdOebuPzyP+/9p0BimM/OqxsevIopQ==", + "dev": true, + "requires": { + "@achrinza/node-ipc": "^9.2.5", + "chalk": "^4.1.2", + "execa": "^1.0.0", + "joi": "^17.4.0", + "launch-editor": "^2.2.1", + "lru-cache": "^6.0.0", + "node-fetch": "^2.6.7", + "open": "^8.0.2", + "ora": "^5.3.0", + "read-pkg": "^5.1.1", + "semver": "^7.3.4", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@vue/compiler-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "requires": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "@vue/compiler-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "requires": { + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "@vue/compiler-sfc": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "requires": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" + } + }, + "@vue/compiler-ssr": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "requires": { + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "@vue/component-compiler-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", + "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", + "dev": true, + "requires": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "prettier": "^1.18.2 || ^2.0.0", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "requires": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + } + } + }, + "@vue/reactivity": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "requires": { + "@vue/shared": "3.5.13" + } + }, + "@vue/runtime-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "requires": { + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "@vue/runtime-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "requires": { + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" + } + }, + "@vue/server-renderer": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "requires": { + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "@vue/shared": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==" + }, + "@vue/vue-loader-v15": { + "version": "npm:vue-loader@15.11.1", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.11.1.tgz", + "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==", + "dev": true, + "requires": { + "@vue/component-compiler-utils": "^3.1.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + } + } + }, + "@vue/web-component-wrapper": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz", + "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", + "dev": true + }, + "@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "requires": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "dependencies": { + "vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "requires": {} + } + } + }, + "@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==" + }, + "@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "requires": { + "vue-demi": "*" + }, + "dependencies": { + "vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "requires": {} + } + } + }, + "@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "dependencies": { + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + } + } + }, + "acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "requires": { + "acorn": "^8.11.0" + } + }, + "address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true + }, + "async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "requires": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + } + }, + "axios": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", + "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.4", + "semver": "^6.3.1" + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", + "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.6.4" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "requires": { + "fill-range": "^7.1.1" + } + }, + "browserslist": { + "version": "4.24.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", + "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001716", + "electron-to-chromium": "^1.5.149", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + } + }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, + "call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001718", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", + "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", + "dev": true + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true + }, + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true + }, + "clipboardy": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz", + "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", + "dev": true, + "requires": { + "arch": "^2.1.1", + "execa": "^1.0.0", + "is-wsl": "^2.1.1" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true + }, + "consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "dev": true, + "requires": { + "bluebird": "^3.1.1" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "copy-webpack-plugin": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==", + "dev": true, + "requires": { + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.1", + "globby": "^11.0.3", + "normalize-path": "^3.0.0", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "core-js": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz", + "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==" + }, + "core-js-compat": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.42.0.tgz", + "integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==", + "dev": true, + "requires": { + "browserslist": "^4.24.4" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "requires": {} + }, + "css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "dependencies": { + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dev": true, + "requires": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dev": true, + "requires": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + } + }, + "cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dev": true, + "requires": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + } + }, + "cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "dev": true, + "requires": {} + }, + "csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + } + }, + "csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, + "debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "dev": true + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + }, + "dependencies": { + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + } + } + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "dev": true + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "easy-stack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", + "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==", + "dev": true + }, + "echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "requires": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.5.152", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.152.tgz", + "integrity": "sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg==", + "dev": true + }, + "element-plus": { + "version": "2.9.10", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.10.tgz", + "integrity": "sha512-W2v9jWnm1kl/zm4bSvCh8aFCVlxvhG3fmqiDZwyd6WQiWGE595J/mpjcCggEr+49QDgIymhXrpPMOPPSARUbng==", + "requires": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.13", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + } + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "requires": { + "stackframe": "^1.3.4" + } + }, + "es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true + }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-plugin-vue": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", + "dev": true, + "requires": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "dependencies": { + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "requires": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "event-pubsub": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", + "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true + }, + "fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + } + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==" + }, + "form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + } + } + }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "requires": { + "duplexer": "^0.1.2" + } + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "dev": true + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "requires": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + } + }, + "html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "dev": true + }, + "html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "dev": true, + "requires": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "requires": {} + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "requires": { + "ci-info": "^1.5.0" + } + }, + "is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "requires": { + "hasown": "^2.0.2" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-file-esm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-file-esm/-/is-file-esm-1.0.0.tgz", + "integrity": "sha512-rZlaNKb4Mr8WlRu2A9XdeoKgnO5aA53XdPHgCKVyCrQ/rWi89RET1+bq37Ru46obaQXeiX4vmFIm1vks41hoSA==", + "dev": true, + "requires": { + "read-pkg-up": "^7.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "js-message": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", + "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true + }, + "launch-editor": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", + "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", + "dev": true, + "requires": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "launch-editor-middleware": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.10.0.tgz", + "integrity": "sha512-RzZu7MeVlE3p1H6Sadc2BhuDGAj7bkeDCBpNq/zSENP4ohJGhso00k5+iYaRwKshIpiOAhMmimce+5D389xmSg==", + "dev": true, + "requires": { + "launch-editor": "^2.10.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "requires": {} + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "lodash.defaultsdeep": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", + "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "lodash.mapvalues": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", + "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + } + } + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", + "dev": true, + "requires": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "module-alias": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==", + "dev": true + }, + "mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true + }, + "normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "requires": { + "path-key": "^2.0.0" + }, + "dependencies": { + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + } + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "requires": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, + "optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + } + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "portfinder": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.37.tgz", + "integrity": "sha512-yuGIEjDAYnnOex9ddMnKZEMFE0CcGo6zbfzDklkmT1m5z734ss6JMzN9rNB3+RR7iS+F10D4/BVIaXOyh8PQKw==", + "dev": true, + "requires": { + "async": "^3.2.6", + "debug": "^4.3.6" + } + }, + "postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "requires": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + } + }, + "postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "dev": true, + "requires": {} + }, + "postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "dev": true, + "requires": {} + }, + "postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "dev": true, + "requires": {} + }, + "postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "dev": true, + "requires": {} + }, + "postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + } + }, + "postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dev": true, + "requires": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + } + } + }, + "postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^7.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + } + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "dev": true, + "requires": {} + }, + "postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dev": true, + "requires": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dev": true, + "requires": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + } + }, + "postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true + }, + "pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "progress-webpack-plugin": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/progress-webpack-plugin/-/progress-webpack-plugin-1.0.16.tgz", + "integrity": "sha512-sdiHuuKOzELcBANHfrupYo+r99iPRyOnw15qX+rNlVUqXGfjXdH4IgxriKwG1kNJwVswKQHMdj1hYZMcb9jFaA==", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "figures": "^2.0.0", + "log-update": "^2.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + } + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "requires": { + "side-channel": "^1.0.6" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, + "regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "requires": { + "jsesc": "~3.0.2" + }, + "dependencies": { + "jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true + }, + "renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "requires": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + }, + "reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "requires": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "requires": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + } + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true + }, + "side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + } + }, + "side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + } + }, + "side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "requires": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + } + }, + "side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "requires": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "requires": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "terser": { + "version": "5.39.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.1.tgz", + "integrity": "sha512-Mm6+uad0ZuDtcV8/4uOZQDQ8RuiC5Pu+iZRedJtF7yA/27sPL7d++In/AJKpWZlU3SYMPPkVfwetn6sgZ66pUA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "thread-loader": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/thread-loader/-/thread-loader-3.0.4.tgz", + "integrity": "sha512-ByaL2TPb+m6yArpqQUZvP+5S1mZtXsEP7nWKKlAUTm7fCml8kB5s1uI3+eHRP2bk5mVYfRSBI7FFf+tWEyLZwA==", + "dev": true, + "requires": { + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.1.0", + "loader-utils": "^2.0.0", + "neo-async": "^2.6.2", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "requires": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, + "vue": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "requires": { + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "dependencies": { + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true + } + } + }, + "vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", + "dev": true + }, + "vue-loader": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-17.4.2.tgz", + "integrity": "sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "watchpack": "^2.4.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "vue-style-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", + "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", + "dev": true, + "requires": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + }, + "dependencies": { + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", + "dev": true + } + } + }, + "vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", + "dev": true + }, + "watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "webpack": { + "version": "5.99.8", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.8.tgz", + "integrity": "sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.2", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "webpack-chain": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-6.5.1.tgz", + "integrity": "sha512-7doO/SRtLu8q5WM0s7vPKPWX580qhi0/yBHkOxNkv50f6qB76Zy9o2wRTrrPULqYTvQlVHuvbA8v+G5ayuUDsA==", + "dev": true, + "requires": { + "deepmerge": "^1.5.2", + "javascript-stringify": "^2.0.1" + } + }, + "webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dev": true, + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "dev": true, + "requires": {} + } + } + }, + "webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "webpack-virtual-modules": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz", + "integrity": "sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==", + "dev": true + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "requires": {} + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, + "yorkie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz", + "integrity": "sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==", + "dev": true, + "requires": { + "execa": "^0.8.0", + "is-ci": "^1.0.10", + "normalize-path": "^1.0.0", + "strip-indent": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", + "integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "normalize-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz", + "integrity": "sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + } + } + }, + "zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "requires": { + "tslib": "2.3.0" + } + } + } +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/package.json b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/package.json new file mode 100644 index 0000000..8d8a753 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/package.json @@ -0,0 +1,38 @@ +{ + "name": "sound-vue-frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "axios": "^1.3.4", + "core-js": "^3.8.3", + "echarts": "^5.4.1", + "element-plus": "^2.3.0", + "vue": "^3.2.13" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "eslint": "^7.32.0", + "eslint-plugin-vue": "^8.0.3" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/vue3-essential", + "eslint:recommended" + ], + "parserOptions": { + "ecmaVersion": 2020 + }, + "rules": {} + } +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/App.vue b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/App.vue new file mode 100644 index 0000000..0867817 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/App.vue @@ -0,0 +1,393 @@ + + + + + + diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/assets/main.css b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/assets/main.css new file mode 100644 index 0000000..d9adb15 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/assets/main.css @@ -0,0 +1,19 @@ +/* 基础样式重置 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + color: #2c3e50; + background-color: #f5f7fa; +} + +#app { + width: 100%; + min-height: 100vh; +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/components/SourceDataService.js b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/components/SourceDataService.js new file mode 100644 index 0000000..8ea1718 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/components/SourceDataService.js @@ -0,0 +1,11 @@ +// 声源数据接口服务 +import axios from 'axios'; + +const API_BASE_URL = 'http://127.0.0.1:5000'; // 根据实际后端地址进行配置 + +export default { + // 获取最新声源数据 + getSourceData() { + return axios.get(`${API_BASE_URL}/data`); + } +}; diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/main.js b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/main.js new file mode 100644 index 0000000..8c18c11 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/src/main.js @@ -0,0 +1,8 @@ +import { createApp } from 'vue' +import App from './App.vue' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' + +const app = createApp(App) +app.use(ElementPlus) +app.mount('#app') diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/vue.config.js b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/vue.config.js new file mode 100644 index 0000000..d840b2c --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/gold_eyes/src/sound-vue-frontend/vue.config.js @@ -0,0 +1,13 @@ +module.exports = { + devServer: { + proxy: { + '/api': { + target: 'http://localhost:5000', + changeOrigin: true, + pathRewrite: { + '^/api': '' + } + } + } + } +} diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/CMakeLists.txt b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/CMakeLists.txt new file mode 100644 index 0000000..b788c0c --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.10) +project(infrared_identification_system) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# 查找必要的包 +find_package(CURL REQUIRED) +find_package(OpenCV REQUIRED) +find_package(nlohmann_json 3.10.0 QUIET) +find_package(OpenSSL REQUIRED) + +# 如果没有找到JSON库,则提示用户安装 +if(NOT nlohmann_json_FOUND) + message(STATUS "nlohmann_json not found. Please install it using:") + message(STATUS " sudo apt-get install nlohmann-json3-dev") + message(FATAL_ERROR "nlohmann_json is required but not found.") +endif() + +# 包含目录 +include_directories(${CURL_INCLUDE_DIRS}) +include_directories(${OpenCV_INCLUDE_DIRS}) +include_directories(${OPENSSL_INCLUDE_DIR}) + +# 添加可执行文件 +add_executable(infrared_identifier + src/main.cpp + src/zhipu_api.cpp + src/image_processor.cpp +) + +# 链接库 +target_link_libraries(infrared_identifier + ${CURL_LIBRARIES} + ${OpenCV_LIBS} + nlohmann_json::nlohmann_json + ${OPENSSL_LIBRARIES} +) \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/README.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/README.md new file mode 100644 index 0000000..98e7aed --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/README.md @@ -0,0 +1,164 @@ +# 红外图像识别系统 + +这是一个基于C++开发的红外图像识别系统,该系统使用智谱AI API(基于GLM-4V-Plus-0111大型语言模型)来识别红外图像中的人员,并能将识别结果标记在图像上。 + +## 功能特点 + +- 加载和处理JPEG格式的红外图像 +- 对红外图像进行预处理以提高识别准确性 +- 调用智谱AI API进行图像内容分析和识别 +- 识别红外图像中的人员并提供精确坐标 +- 估计红外图像中人员与相机的距离 +- 提供详细的识别结果描述和置信度评估 +- 解析识别结果中的坐标和距离信息 +- 在图像上标记检测到的高置信度人员目标及其距离 +- 支持保存带有标记的识别结果图像 +- 支持设置置信度阈值筛选目标 +- 支持设置API请求超时时间 + +## 依赖项 + +- C++17或更高版本 +- CMake 3.10或更高版本 +- OpenCV库 +- libcurl库 +- nlohmann_json库 +- OpenSSL库 + +## 安装依赖 + +### 在Ubuntu/Debian上: + +```bash +# 安装编译工具 +sudo apt-get update +sudo apt-get install -y build-essential cmake + +# 安装libcurl +sudo apt-get install -y libcurl4-openssl-dev + +# 安装OpenCV +sudo apt-get install -y libopencv-dev + +# 安装nlohmann_json +sudo apt-get install -y nlohmann-json3-dev + +# 安装OpenSSL +sudo apt-get install -y libssl-dev +``` + +## 构建项目 + +1. 克隆本仓库: + +```bash +git clone <仓库URL> +cd infrared_identification_system +``` + +2. 创建构建目录并编译: + +```bash +mkdir build +cd build +cmake .. +make +``` + +## 使用方法 + +基本用法: + +```bash +./infrared_identifier <图像路径> [选项] +``` + +选项: +- `-p, --preprocess`:预处理图像后再进行识别 +- `-s, --save <路径>`:保存预处理后的图像到指定路径 +- `-d, --display`:显示预处理后的图像 +- `-m, --mark <路径>`:根据识别结果标记目标并保存到指定路径 +- `-c, --confidence <值>`:设置人员检测的置信度阈值(0.0-1.0),默认为0.7 +- `-t, --timeout <秒数>`:设置API请求超时时间(秒),默认为60秒 +- `-h, --help`:显示帮助信息 + +### 示例 + +1. 基本识别: + +```bash +./infrared_identifier /path/to/infrared_image.jpg +``` + +2. 预处理并显示图像: + +```bash +./infrared_identifier /path/to/infrared_image.jpg -p -d +``` + +3. 预处理并保存结果: + +```bash +./infrared_identifier /path/to/infrared_image.jpg -p -s processed_image.jpg +``` + +4. 识别并标记检测到的目标: + +```bash +./infrared_identifier /path/to/infrared_image.jpg -m marked_image.jpg +``` + +5. 设置置信度阈值并标记目标: + +```bash +./infrared_identifier /path/to/infrared_image.jpg -m marked_image.jpg -c 0.9 +``` + +6. 增加超时时间处理大型图像: + +```bash +./infrared_identifier /path/to/infrared_image.jpg -m marked_image.jpg -t 120 +``` + +7. 预处理、保存预处理图像、识别并标记目标: + +```bash +./infrared_identifier /path/to/infrared_image.jpg -p -s processed.jpg -m marked.jpg +``` + +## 标记功能说明 + +系统会向智谱AI发送格式化的提示词,要求大模型返回特定格式的坐标和距离信息。接收到返回结果后,系统会解析[坐标部分]中的内容,提取出每个检测目标的相对坐标、描述和距离估计,然后在图像上标记出这些位置。 + +坐标格式为:(x, y),其中x和y都是0到1之间的小数,表示相对位置: +- x=0表示图像最左边,x=1表示图像最右边 +- y=0表示图像最上边,y=1表示图像最下边 + +距离估计基于AI对热源强度和大小的分析,以米为单位。 + +标记效果: +- 每个人员目标使用醒目的红色十字记号、彩色方框和蓝色圆点组合标记 +- 每个标记处会显示序号和距离估计,便于区分多个目标 + +## 模型与API说明 + +本系统使用智谱AI的GLM-4V-Plus-0111模型进行图像识别,该模型具有更高的多模态理解能力,能够更准确地识别红外图像中的人员位置。 + +API密钥已内置在代码中,但建议根据安全需要调整为环境变量或配置文件方式存储。 + +## 版本历史 + +### v3.0 +- 新增距离估计功能,能够估计人员与相机的距离 +- 在标记图像上显示人员距离信息 +- 优化了AI提示词,使其能够提供更准确的距离估计 + +### v2.0 +- 升级到GLM-4V-Plus-0111模型,提高识别准确性 +- 添加置信度阈值设置功能 +- 添加API请求超时设置功能 +- 增强标记显示效果 +- 优化提示词,专注于人员检测 + +### v1.0 +- 初始版本,基本图像识别和标记功能 \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/image_processor.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/image_processor.cpp new file mode 100644 index 0000000..2ac168e --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/image_processor.cpp @@ -0,0 +1,286 @@ +#include "image_processor.h" +#include +#include + +// 图像处理器构造函数,初始化图像加载状态为false +ImageProcessor::ImageProcessor() : is_image_loaded_(false) { +} + +// 加载图像文件到处理器中 +// @param image_path 图像文件路径 +// @return 加载成功返回true,失败返回false +bool ImageProcessor::loadImage(const std::string& image_path) { + try { + // 使用OpenCV加载图像 + original_image_ = cv::imread(image_path, cv::IMREAD_UNCHANGED); + + if (original_image_.empty()) { + std::cerr << "无法加载图像: " << image_path << std::endl; + is_image_loaded_ = false; + return false; + } + + // 复制原始图像到处理图像 + original_image_.copyTo(processed_image_); + original_image_.copyTo(marked_image_); + is_image_loaded_ = true; + return true; + } + catch (const cv::Exception& e) { + std::cerr << "OpenCV错误: " << e.what() << std::endl; + is_image_loaded_ = false; + return false; + } +} + +// 获取当前处理后的图像 +// @return 如果图像已加载则返回处理后的图像,否则返回空矩阵 +cv::Mat ImageProcessor::getImage() const { + return is_image_loaded_ ? processed_image_ : cv::Mat(); +} + +// 对图像进行预处理,包括灰度转换、对比度增强、降噪等步骤 +// 专门针对红外图像优化,用于提高目标检测的准确性 +void ImageProcessor::preprocessImage() { + if (!is_image_loaded_) { + std::cerr << "未加载图像,无法进行预处理" << std::endl; + return; + } + + try { + // 红外图像预处理步骤 + + // 1. 转换为灰度图像(如果不是) + if (processed_image_.channels() > 1) { + cv::cvtColor(processed_image_, processed_image_, cv::COLOR_BGR2GRAY); + } + + // 2. 应用直方图均衡化来增强对比度 + cv::equalizeHist(processed_image_, processed_image_); + + // 3. 应用高斯模糊减少噪点 + cv::GaussianBlur(processed_image_, processed_image_, cv::Size(3, 3), 0); + + // 4. 应用自适应阈值处理以突出显示热点 + cv::Mat temp; + cv::adaptiveThreshold(processed_image_, temp, 255, + cv::ADAPTIVE_THRESH_GAUSSIAN_C, + cv::THRESH_BINARY_INV, 11, 2); + + // 5. 混合原始图像和阈值处理图像以保留细节 + cv::addWeighted(processed_image_, 0.7, temp, 0.3, 0, processed_image_); + + // 6. 应用CLAHE(对比度受限的自适应直方图均衡化) + cv::Ptr clahe = cv::createCLAHE(); + clahe->setClipLimit(4); + clahe->apply(processed_image_, processed_image_); + + // 复制处理后的图像到标记图像 + // 如果是灰度图像,转换为彩色以便标记 + if (processed_image_.channels() == 1) { + cv::cvtColor(processed_image_, marked_image_, cv::COLOR_GRAY2BGR); + } else { + processed_image_.copyTo(marked_image_); + } + } + catch (const cv::Exception& e) { + std::cerr << "预处理图像时出错: " << e.what() << std::endl; + } +} + +// 保存处理后的图像到指定路径 +// @param output_path 输出文件路径 +// @return 保存成功返回true,失败返回false +bool ImageProcessor::saveProcessedImage(const std::string& output_path) { + if (!is_image_loaded_) { + std::cerr << "未加载图像,无法保存" << std::endl; + return false; + } + + try { + return cv::imwrite(output_path, processed_image_); + } + catch (const cv::Exception& e) { + std::cerr << "保存图像时出错: " << e.what() << std::endl; + return false; + } +} + +// 在窗口中显示处理后的图像 +// @param window_name 窗口名称 +void ImageProcessor::displayImage(const std::string& window_name) { + if (!is_image_loaded_) { + std::cerr << "未加载图像,无法显示" << std::endl; + return; + } + + try { + cv::namedWindow(window_name, cv::WINDOW_NORMAL); + cv::imshow(window_name, processed_image_); + cv::waitKey(0); + cv::destroyWindow(window_name); + } + catch (const cv::Exception& e) { + std::cerr << "显示图像时出错: " << e.what() << std::endl; + } +} + +// 解析AI检测结果字符串,提取检测到的人员目标信息 +// @param result AI返回的检测结果字符串 +// @return 解析出的检测目标对象列表 +std::vector ImageProcessor::parseDetectionResult(const std::string& result) { + std::vector detected_objects; + + // 查找坐标部分 + size_t coords_pos = result.find("[坐标部分]"); + if (coords_pos == std::string::npos) { + std::cerr << "未找到坐标部分,无法解析" << std::endl; + return detected_objects; + } + + // 提取坐标部分的文本 + std::string coords_text = result.substr(coords_pos); + + // 使用正则表达式匹配坐标和距离 + // 更新正则表达式以更准确地匹配AI返回的格式 + std::regex coord_regex("人物(\\d+):\\(([0-9.]+),\\s*([0-9.]+)\\),([^,]*),距离:([0-9.]+)米"); + std::smatch matches; + std::string::const_iterator search_start(coords_text.cbegin()); + + while (std::regex_search(search_start, coords_text.cend(), matches, coord_regex)) { + // 尝试提取坐标和距离 + DetectedObject obj; + try { + obj.x = std::stof(matches[2].str()); + obj.y = std::stof(matches[3].str()); + obj.description = "人员" + matches[1].str() + ": " + matches[4].str(); + obj.type = "人员"; + + // 解析距离 - 现在匹配组索引变为5 + obj.distance = std::stof(matches[5].str()); + + // 设置距离描述 + if (obj.distance < 50.0f) { + obj.distanceDesc = "近距离目标"; + } else if (obj.distance < 150.0f) { + obj.distanceDesc = "中距离目标"; + } else { + obj.distanceDesc = "远距离目标"; + } + + // 根据描述判断置信度 + std::string desc = matches[4].str(); + std::transform(desc.begin(), desc.end(), desc.begin(), + [](unsigned char c){ return std::tolower(c); }); + + // 设置高置信度 - 针对确定是人员的描述 + if (desc.find("确定") != std::string::npos || + desc.find("明确") != std::string::npos) { + obj.confidence = 0.95f; + } else { + // 默认置信度 + obj.confidence = 0.8f; + } + + detected_objects.push_back(obj); + + std::cout << "检测到人员: " << obj.description << " 位置:(" << obj.x << "," << obj.y + << ") 置信度:" << obj.confidence; + + if (obj.distance > 0) { + std::cout << " 距离:" << obj.distance << "米 (" << obj.distanceDesc << ")" << std::endl; + } else { + std::cout << " 距离:未知" << std::endl; + } + } catch (const std::exception& e) { + std::cerr << "解析坐标或距离时出错: " << e.what() << std::endl; + } + + search_start = matches.suffix().first; + } + + return detected_objects; +} + +// 在图像上标记检测到的目标对象 +// @param objects 检测到的目标对象列表 +// @param confidence_threshold 置信度阈值,只标记高于此阈值的目标 +void ImageProcessor::markDetectedObjects(const std::vector& objects, float confidence_threshold) { + if (!is_image_loaded_) { + std::cerr << "未加载图像,无法标记目标" << std::endl; + return; + } + + // 确保标记图像是彩色图像 + if (marked_image_.channels() == 1) { + cv::cvtColor(marked_image_, marked_image_, cv::COLOR_GRAY2BGR); + } + + // 获取图像尺寸 + int width = marked_image_.cols; + int height = marked_image_.rows; + + int marked_count = 0; + + // 标记每个检测到的目标 + for (const auto& obj : objects) { + // 只处理人员且置信度高于阈值的目标 + if (obj.type == "人员" && obj.confidence >= confidence_threshold) { + marked_count++; + + // 计算像素坐标 + int x = static_cast(obj.x * width); + int y = static_cast(obj.y * height); + + // 绘制更醒目的标记 - 红色十字加方框 + int marker_size = std::min(width, height) / 15; // 根据图像尺寸自适应 + + // 画十字 + cv::line(marked_image_, cv::Point(x - marker_size, y), cv::Point(x + marker_size, y), cv::Scalar(0, 0, 255), 2); + cv::line(marked_image_, cv::Point(x, y - marker_size), cv::Point(x, y + marker_size), cv::Scalar(0, 0, 255), 2); + + // 画方框 + cv::rectangle(marked_image_, + cv::Point(x - marker_size, y - marker_size), + cv::Point(x + marker_size, y + marker_size), + cv::Scalar(0, 255, 255), 2); + + // 添加圆圈 + cv::circle(marked_image_, cv::Point(x, y), marker_size/3, cv::Scalar(255, 0, 0), -1); + + // 在图像上添加序号 + std::string label = std::to_string(marked_count); + int font_face = cv::FONT_HERSHEY_SIMPLEX; + double font_scale = 0.8; + int thickness = 2; + int baseline = 0; + cv::Size text_size = cv::getTextSize(label, font_face, font_scale, thickness, &baseline); + cv::putText(marked_image_, label, + cv::Point(x - text_size.width/2, y + text_size.height/2), + font_face, font_scale, cv::Scalar(255, 255, 255), thickness); + + // 移除距离标注部分 + } + } + + std::cout << "标记了 " << marked_count << " 个置信度≥" << confidence_threshold + << "的人员目标" << std::endl; +} + +// 保存标记了检测目标的图像到指定路径 +// @param output_path 输出文件路径 +// @return 保存成功返回true,失败返回false +bool ImageProcessor::saveMarkedImage(const std::string& output_path) { + if (!is_image_loaded_) { + std::cerr << "未加载图像,无法保存" << std::endl; + return false; + } + + try { + return cv::imwrite(output_path, marked_image_); + } + catch (const cv::Exception& e) { + std::cerr << "保存标记图像时出错: " << e.what() << std::endl; + return false; + } +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/image_processor.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/image_processor.h new file mode 100644 index 0000000..72fdb1f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/image_processor.h @@ -0,0 +1,54 @@ +#ifndef IMAGE_PROCESSOR_H +#define IMAGE_PROCESSOR_H + +#include +#include +#include + +struct DetectedObject { + float x; + float y; + std::string description; + std::string type; // 类型:人员、装备等 + float confidence; // 置信度:0-1之间 + float distance; // 距离:以米为单位 + std::string distanceDesc; // 距离描述:例如"近距离目标"、"中距离目标"等 +}; + +class ImageProcessor { +public: + // 构造函数 + ImageProcessor(); + + // 加载图像 + bool loadImage(const std::string& image_path); + + // 获取加载的图像 + cv::Mat getImage() const; + + // 预处理红外图像(增强对比度等) + void preprocessImage(); + + // 保存预处理后的图像 + bool saveProcessedImage(const std::string& output_path); + + // 显示图像(用于调试) + void displayImage(const std::string& window_name); + + // 解析检测结果并提取坐标 + std::vector parseDetectionResult(const std::string& result); + + // 标记检测到的目标 + void markDetectedObjects(const std::vector& objects, float confidence_threshold = 0.5); + + // 保存标记后的图像 + bool saveMarkedImage(const std::string& output_path); + +private: + cv::Mat original_image_; // 原始图像 + cv::Mat processed_image_; // 处理后的图像 + cv::Mat marked_image_; // 标记后的图像 + bool is_image_loaded_; // 标记图像是否已加载 +}; + +#endif // IMAGE_PROCESSOR_H \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/main.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/main.cpp new file mode 100644 index 0000000..53970fb --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/main.cpp @@ -0,0 +1,216 @@ +#include +#include +#include +#include "zhipu_api.h" +#include "image_processor.h" + +namespace fs = std::filesystem; + +void showUsage(const std::string& program_name) { + std::cout << "用法: " << program_name << " <图像路径> [选项]" << std::endl; + std::cout << "选项:" << std::endl; + std::cout << " -p, --preprocess 预处理图像后再进行识别" << std::endl; + std::cout << " -s, --save <路径> 保存预处理后的图像到指定路径" << std::endl; + std::cout << " -d, --display 显示预处理后的图像" << std::endl; + std::cout << " -m, --mark <路径> 根据识别结果标记目标并保存到指定路径" << std::endl; + std::cout << " -c, --confidence <值> 设置人员检测的置信度阈值(0.0-1.0),默认为0.7" << std::endl; + std::cout << " -t, --timeout <秒数> 设置API请求超时时间(秒),默认为60秒" << std::endl; + std::cout << " -h, --help 显示帮助信息" << std::endl; + std::cout << std::endl; + std::cout << "功能说明:" << std::endl; + std::cout << " 识别红外图像中的人员,并提供位置标记和距离估计" << std::endl; + std::cout << " 距离估计基于AI对热源强度和大小的分析,显示在标记图像中" << std::endl; +} + +int main(int argc, char* argv[]) { + // 参数检查 + if (argc < 2) { + showUsage(argv[0]); + return 1; + } + + // 解析命令行参数 + std::string image_path = argv[1]; + bool preprocess = false; + bool display = false; + std::string save_path = ""; + std::string mark_path = ""; + float confidence_threshold = 0.7f; // 默认置信度阈值 + long timeout_seconds = 60; // 默认超时时间为60秒 + + for (int i = 2; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "-p" || arg == "--preprocess") { + preprocess = true; + } + else if (arg == "-d" || arg == "--display") { + display = true; + } + else if (arg == "-s" || arg == "--save") { + if (i + 1 < argc) { + save_path = argv[++i]; + } + else { + std::cerr << "错误: 未指定保存路径" << std::endl; + return 1; + } + } + else if (arg == "-m" || arg == "--mark") { + if (i + 1 < argc) { + mark_path = argv[++i]; + } + else { + std::cerr << "错误: 未指定标记图像保存路径" << std::endl; + return 1; + } + } + else if (arg == "-c" || arg == "--confidence") { + if (i + 1 < argc) { + try { + confidence_threshold = std::stof(argv[++i]); + // 限制置信度在0-1范围内 + if (confidence_threshold < 0.0f || confidence_threshold > 1.0f) { + std::cerr << "警告: 置信度阈值必须在0.0-1.0范围内,已设置为: " + << confidence_threshold << std::endl; + } + } + catch (const std::exception& e) { + std::cerr << "错误: 无效的置信度阈值: " << argv[i] << std::endl; + return 1; + } + } + else { + std::cerr << "错误: 未指定置信度阈值" << std::endl; + return 1; + } + } + else if (arg == "-t" || arg == "--timeout") { + if (i + 1 < argc) { + try { + timeout_seconds = std::stol(argv[++i]); + if (timeout_seconds < 10) { + std::cerr << "警告: 超时时间太短,已设置为最小值10秒" << std::endl; + timeout_seconds = 10; + } else if (timeout_seconds > 300) { + std::cerr << "警告: 超时时间太长,已设置为最大值300秒" << std::endl; + timeout_seconds = 300; + } + } + catch (const std::exception& e) { + std::cerr << "错误: 无效的超时时间: " << argv[i] << std::endl; + return 1; + } + } + else { + std::cerr << "错误: 未指定超时时间" << std::endl; + return 1; + } + } + else if (arg == "-h" || arg == "--help") { + showUsage(argv[0]); + return 0; + } + else { + std::cerr << "错误: 未知选项 " << arg << std::endl; + showUsage(argv[0]); + return 1; + } + } + + // 检查图像文件是否存在 + if (!fs::exists(image_path)) { + std::cerr << "错误: 图像文件不存在: " << image_path << std::endl; + return 1; + } + + try { + // 初始化图像处理器 + ImageProcessor processor; + + // 加载图像 + if (!processor.loadImage(image_path)) { + std::cerr << "错误: 无法加载图像" << std::endl; + return 1; + } + + // 预处理图像(如果需要) + if (preprocess) { + std::cout << "正在预处理图像..." << std::endl; + processor.preprocessImage(); + + // 保存预处理后的图像(如果需要) + if (!save_path.empty()) { + if (processor.saveProcessedImage(save_path)) { + std::cout << "预处理后的图像已保存到: " << save_path << std::endl; + } + else { + std::cerr << "错误: 无法保存预处理后的图像" << std::endl; + } + } + + // 显示预处理后的图像(如果需要) + if (display) { + processor.displayImage("预处理后的红外图像"); + } + + // 如果进行了预处理并保存,使用预处理后的图像路径 + if (!save_path.empty()) { + image_path = save_path; + } + else { + // 未保存预处理后的图像,需要创建临时文件 + std::string temp_path = "temp_processed.jpg"; + processor.saveProcessedImage(temp_path); + image_path = temp_path; + } + } + + // 初始化智谱API + const std::string api_key = "3bbb7dee27ac40e38a9b2026065dfa09.oLgHTXxNnz4FM392"; + ZhipuAPI zhipu_api(api_key, timeout_seconds); + std::cout << "API超时时间已设置为: " << timeout_seconds << " 秒" << std::endl; + + // 识别图像 + std::cout << "正在分析红外图像..." << std::endl; + std::string result = zhipu_api.identifyObjectsInImage(image_path); + + // 打印结果 + std::cout << "\n==== 识别结果 ====\n" << std::endl; + std::cout << result << std::endl; + std::cout << "\n==================\n" << std::endl; + + // 如果需要标记图像 + if (!mark_path.empty()) { + std::cout << "正在标记检测到的人员目标 (置信度阈值: " << confidence_threshold << ")..." << std::endl; + + // 解析检测结果 + std::vector objects = processor.parseDetectionResult(result); + + if (objects.empty()) { + std::cout << "未检测到任何人员或无法解析坐标" << std::endl; + } else { + // 标记检测到的目标 + processor.markDetectedObjects(objects, confidence_threshold); + + // 保存标记后的图像 + if (processor.saveMarkedImage(mark_path)) { + std::cout << "标记后的图像已保存到: " << mark_path << std::endl; + } else { + std::cerr << "错误: 无法保存标记后的图像" << std::endl; + } + } + } + + // 删除临时文件 + if (preprocess && save_path.empty() && fs::exists("temp_processed.jpg")) { + fs::remove("temp_processed.jpg"); + } + + return 0; + } + catch (const std::exception& e) { + std::cerr << "发生异常: " << e.what() << std::endl; + return 1; + } +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/zhipu_api.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/zhipu_api.cpp new file mode 100644 index 0000000..d79ec13 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/zhipu_api.cpp @@ -0,0 +1,288 @@ +#include "zhipu_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 智谱AI API客户端实现文件 +// 提供图像分析、目标识别等功能 + +// CURL响应数据回调函数,用于接收HTTP响应内容 +// @param contents 响应数据指针 +// @param size 数据块大小 +// @param nmemb 数据块数量 +// @param s 存储响应数据的字符串指针 +// @return 实际处理的数据大小 +static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* s) { + size_t newLength = size * nmemb; + try { + s->append((char*)contents, newLength); + return newLength; + } + catch (std::bad_alloc& e) { + // 处理内存分配失败 + return 0; + } +} + +// 智谱API客户端构造函数 +// @param api_key API密钥 +// @param timeout_seconds 请求超时时间(秒) +ZhipuAPI::ZhipuAPI(const std::string& api_key, long timeout_seconds) : api_key_(api_key), timeout_seconds_(timeout_seconds) { + // 初始化curl全局环境 + curl_global_init(CURL_GLOBAL_ALL); +} + +// 设置API请求超时时间 +// @param timeout_seconds 超时时间(秒) +void ZhipuAPI::setTimeout(long timeout_seconds) { + timeout_seconds_ = timeout_seconds; + std::cout << "API请求超时时间已设置为: " << timeout_seconds_ << " 秒" << std::endl; +} + +// 分析图像并识别其中的人员目标 +// @param image_path 图像文件路径 +// @param context 额外的上下文信息 +// @return 智谱AI的JSON响应结果 +json ZhipuAPI::analyzeImage(const std::string& image_path, const std::string& context) { + try { + // 将图像转换为Base64编码以便传输 + std::string base64_image = imageToBase64(image_path); + + // 构建专门针对红外图像人员检测的提示词 + std::string prompt = "这是一张红外热成像照片,请严格标注出图像中所有人员的位置和估计距离。\n\n" + "红外照片中人员通常表现为较亮的热点区域。请仔细观察并只标注清晰可辨认的人员,不要标注其他热源或装备。\n\n" + "请提供极其精确的人员坐标位置,坐标格式为:(x, y),其中x和y都是从0到1的小数,表示相对位置。" + "x=0表示图像最左边,x=1表示图像最右边;y=0表示图像最上边,y=1表示图像最下边。\n\n" + "同时,请基于热源强度和大小估计每个人员与相机的距离(以米为单位)。\n\n" + "请以中心点为准精确定位每个人员的位置。在标注时,请确保:\n" + "1. 坐标点必须精确落在人员主体上\n" + "2. 不要标注模糊不清或可能不是人员的热源\n" + "3. 如果确定是人员,请在描述中标注为\"确定是人员\"\n" + "4. 提供距离估计,格式为\"距离:XX米\"\n\n"; + + // 添加上下文信息(如果有) + if (!context.empty()) { + prompt += "上下文信息:\n" + context + "\n\n"; + } + + // 指定输出格式要求 + prompt += "请按照以下格式输出:\n\n" + "[描述部分]\n" + "这里是对图像内容的整体描述,包括您观察到的人员数量。\n\n" + "[坐标部分]\n" + "人物1:(0.xx, 0.yy),确定是人员,距离:XX米\n" + "人物2:(0.xx, 0.yy),确定是人员,距离:XX米\n\n" + "注意:坐标部分必须严格按照格式输出,每行一个人员,包含精确坐标、简短描述和距离估计,用逗号分隔。" + "只标注您确定的人员,不要标注模糊或不确定的对象。"; + + // 构建符合智谱AI多模态API格式的请求JSON + json request_json = { + {"model", api_model_}, + {"messages", json::array({ + { + {"role", "user"}, + {"content", json::array({ + { + {"type", "text"}, + {"text", prompt} + }, + { + {"type", "image_url"}, + {"image_url", { + {"url", "data:image/jpeg;base64," + base64_image} + }} + } + })} + } + })} + }; + + // 发送HTTP请求并获取响应 + std::string response_str = sendRequest(request_json.dump()); + + // 解析JSON响应 + json response_json = json::parse(response_str); + return response_json; + } + catch (const std::exception& e) { + std::cerr << "分析图像时出错: " << e.what() << std::endl; + return json{{"error", e.what()}}; + } +} + +// 分析图像的重载版本,不包含额外上下文信息 +// @param image_path 图像文件路径 +// @return 智谱AI的JSON响应结果 +json ZhipuAPI::analyzeImage(const std::string& image_path) { + // 调用带context参数的版本,传递空字符串作为context + return analyzeImage(image_path, ""); +} + +// 识别图像中的对象并返回文本结果 +// @param image_path 图像文件路径 +// @param context 额外的上下文信息 +// @return 识别结果的文本描述 +std::string ZhipuAPI::identifyObjectsInImage(const std::string& image_path, const std::string& context) { + try { + json response = analyzeImage(image_path, context); + + // 从API响应中提取识别结果文本 + if (response.contains("choices") && response["choices"].is_array() && + !response["choices"].empty() && + response["choices"][0].contains("message") && + response["choices"][0]["message"].contains("content")) { + + return response["choices"][0]["message"]["content"]; + } + else if (response.contains("error")) { + // 处理API返回的错误信息 + std::string error_msg = "识别出错: "; + if (response["error"].is_string()) { + error_msg += response["error"].get(); + } else if (response["error"].is_object() && response["error"].contains("message")) { + error_msg += response["error"]["message"].get(); + } else { + error_msg += response.dump(); + } + return error_msg; + } + else { + return "无法从API响应中提取识别结果: " + response.dump(); + } + } + catch (const std::exception& e) { + return std::string("识别对象时出错: ") + e.what(); + } +} + +// 识别图像中对象的重载版本,不包含额外上下文信息 +// @param image_path 图像文件路径 +// @return 识别结果的文本描述 +std::string ZhipuAPI::identifyObjectsInImage(const std::string& image_path) { + // 调用带context参数的版本,传递空字符串作为context + return identifyObjectsInImage(image_path, ""); +} + +// 将图像文件转换为Base64编码字符串 +// @param image_path 图像文件路径 +// @return Base64编码的字符串 +std::string ZhipuAPI::imageToBase64(const std::string& image_path) { + // 以二进制模式打开文件并读取数据 + std::ifstream file(image_path, std::ios::binary); + if (!file) { + throw std::runtime_error("无法打开图像文件: " + image_path); + } + + // 获取文件大小 + file.seekg(0, std::ios::end); + size_t file_size = file.tellg(); + file.seekg(0, std::ios::beg); + + // 读取整个文件内容到缓冲区 + std::vector buffer(file_size); + file.read(buffer.data(), file_size); + file.close(); + + // Base64编码字符表 + static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string base64; + base64.reserve(((file_size + 2) / 3) * 4); + + // 每3个字节转换为4个Base64字符 + for (size_t i = 0; i < file_size; i += 3) { + // 存储3个输入字节和4个输出字符 + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + // 初始化数组为0 + char_array_3[0] = char_array_3[1] = char_array_3[2] = 0; + + // 读取最多3个字节 + for (size_t j = 0; j < 3 && i + j < file_size; j++) { + char_array_3[j] = buffer[i + j]; + } + + // 执行Base64编码转换 + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + // 将编码结果添加到输出字符串 + for (int j = 0; j < 4; j++) { + if (i + j * 3 / 4 < file_size) { + base64.push_back(base64_chars[char_array_4[j]]); + } else { + base64.push_back('='); // 填充字符 + } + } + } + + return base64; +} + +// 发送HTTP POST请求到智谱AI API +// @param payload JSON格式的请求数据 +// @return API响应的字符串 +std::string ZhipuAPI::sendRequest(const std::string& payload) { + CURL* curl = curl_easy_init(); + std::string response; + + if (curl) { + // 设置HTTP请求头 + struct curl_slist* headers = NULL; + headers = curl_slist_append(headers, "Content-Type: application/json"); + + // 设置API认证头 + headers = curl_slist_append(headers, ("Authorization: Bearer " + api_key_).c_str()); + + // 添加API名称头(如果设置了) + if (!api_name_.empty()) { + headers = curl_slist_append(headers, ("Api-Name: " + api_name_).c_str()); + } + + // 配置CURL选项 + curl_easy_setopt(curl, CURLOPT_URL, api_endpoint_.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_seconds_); // 使用设置的超时时间 + + // 启用详细调试输出 + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + // 执行HTTP请求 + CURLcode res = curl_easy_perform(curl); + + if (res != CURLE_OK) { + throw std::runtime_error(std::string("CURL请求失败: ") + curl_easy_strerror(res)); + } + + // 检查HTTP响应状态码 + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + if (http_code != 200) { + std::cerr << "API响应: " << response << std::endl; + throw std::runtime_error("HTTP错误码: " + std::to_string(http_code) + "\n响应: " + response); + } + + // 清理CURL资源 + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + } + else { + throw std::runtime_error("无法初始化CURL"); + } + + return response; +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/zhipu_api.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/zhipu_api.h new file mode 100644 index 0000000..63b4598 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/identification system/src/zhipu_api.h @@ -0,0 +1,48 @@ +#ifndef KIMI_API_H +#define KIMI_API_H + +#include +#include +#include + +using json = nlohmann::json; + +class ZhipuAPI { +public: + // 构造函数 + ZhipuAPI(const std::string& api_key, long timeout_seconds = 60); + + // 发送图像到智谱AI API进行分析 + // 返回JSON格式的响应 + json analyzeImage(const std::string& image_path); + + // 发送图像到智谱AI API进行分析,并提供额外的上下文信息 + // 返回JSON格式的响应 + json analyzeImage(const std::string& image_path, const std::string& context); + + // 从红外图像中识别人或装备 + // 返回识别结果的文本描述 + std::string identifyObjectsInImage(const std::string& image_path); + + // 从红外图像中识别人或装备,并提供额外的上下文信息 + // 返回识别结果的文本描述 + std::string identifyObjectsInImage(const std::string& image_path, const std::string& context); + + // 设置请求超时时间(秒) + void setTimeout(long timeout_seconds); + +private: + std::string api_key_; + const std::string api_endpoint_ = "https://open.bigmodel.cn/api/paas/v4/chat/completions"; + const std::string api_model_ = "glm-4v-plus-0111"; + const std::string api_name_ = "zwt"; // 智谱API名称 + long timeout_seconds_ = 60; // 默认超时时间为60秒 + + // 辅助函数:将图像转换为Base64编码 + std::string imageToBase64(const std::string& image_path); + + // 辅助函数:发送POST请求到智谱AI API + std::string sendRequest(const std::string& payload); +}; + +#endif // KIMI_API_H \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/CMakeLists.txt b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/CMakeLists.txt new file mode 100644 index 0000000..756c6b9 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.0) +project(move_control_tcp) + +# 设置C++标准 +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# 添加可执行文件 +add_executable(tcp_client tcp_client.cpp) + +# 链接库 +target_link_libraries(tcp_client) \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/README.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/README.md new file mode 100644 index 0000000..369b4f4 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/README.md @@ -0,0 +1,87 @@ +# 无人机TCP控制发送端 + +该程序实现了一个简单的TCP客户端,用于发送坐标指令控制无人机飞行。 + +## 功能特点 + +- 建立TCP客户端,连接到无人机控制服务器 +- 发送X、Y坐标控制无人机移动 +- 接收并显示服务器的确认响应 +- 简单的命令行界面 + +## 依赖项 + +- 标准C++库 +- 网络相关库 +- CMake (用于编译) + +## 编译说明 + +1. 使用提供的编译脚本: + +```bash +chmod +x compile.sh # 确保脚本有执行权限 +./compile.sh +``` + +2. 或者手动编译: + +```bash +mkdir -p build +cd build +cmake .. +make +``` + +## 使用方法 + +1. 编译程序后,使用以下命令运行: + +```bash +./build/tcp_client <服务器IP> <端口> +``` + +例如: + +```bash +./build/tcp_client 192.168.1.100 1234 +``` + +2. 程序启动后,按照提示输入坐标信息: + +``` +> 1.5,0.0 +``` + +3. 输入 `exit` 退出程序 + +## 坐标系说明 + +使用机体坐标系(相对于无人机当前位置): +- X轴:无人机前进方向,正值表示前进,负值表示后退 +- Y轴:无人机左侧方向,正值表示向左,负值表示向右 +- Z轴:由服务器固定为0,保持当前高度不变 + +## 通信协议 + +客户端发送格式: +``` +x,y +``` + +例如: +- `1.5,0.0` 表示前进1.5米 +- `0.0,2.0` 表示向左移动2米 +- `-1.0,-1.0` 表示向右后方移动 + +服务器响应格式: +``` +已接收坐标: x=X, y=Y +``` +或者错误消息。 + +## 注意事项 + +- 请确保服务器已启动并且可以连接 +- 建议使用小幅度的坐标值进行测试,确保无人机安全 +- 使用 Ctrl+C 可以安全退出程序 diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/compile.sh b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/compile.sh new file mode 100644 index 0000000..715b0c9 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/compile.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# 创建build目录 +mkdir -p build +cd build + +# 执行CMake和编译 +cmake .. +make + +echo "编译完成,执行方式:" +echo "./build/tcp_client <服务器IP> <端口>" +echo "例如: ./build/tcp_client 192.168.1.100 1234" \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/tcp_client.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/tcp_client.cpp new file mode 100644 index 0000000..0a704db --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/move_control_tcp/tcp_client.cpp @@ -0,0 +1,94 @@ +/** + * @file tcp_client.cpp + * @brief 简单的TCP客户端,发送XY坐标控制无人机飞行 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 + +// 全局变量 +int sock = 0; +bool running = true; + +// 信号处理函数 +void signalHandler(int signum) { + std::cout << "接收到信号 " << signum << ", 关闭连接..." << std::endl; + running = false; + close(sock); + exit(signum); +} + +int main(int argc, char *argv[]) { + // 检查命令行参数 + if (argc != 3) { + std::cerr << "用法: " << argv[0] << " <服务器IP> <端口>" << std::endl; + return -1; + } + + // 注册信号处理 + signal(SIGINT, signalHandler); + + struct sockaddr_in serv_addr; + char buffer[BUFFER_SIZE] = {0}; + + // 创建socket + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + std::cerr << "Socket创建失败" << std::endl; + return -1; + } + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(atoi(argv[2])); + + // 转换IP地址 + if (inet_pton(AF_INET, argv[1], &serv_addr.sin_addr) <= 0) { + std::cerr << "无效的地址或地址不支持" << std::endl; + return -1; + } + + // 连接服务器 + std::cout << "正在连接到服务器 " << argv[1] << ":" << argv[2] << std::endl; + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + std::cerr << "连接失败" << std::endl; + return -1; + } + + std::cout << "连接成功!" << std::endl; + std::cout << "输入格式: x,y (例如: 1.5,2.0 表示前进1.5米,向左2.0米)" << std::endl; + std::cout << "输入'exit'退出" << std::endl; + + // 主循环 + while (running) { + std::string input; + std::cout << "> "; + std::getline(std::cin, input); + + if (input == "exit") { + std::cout << "退出程序" << std::endl; + break; + } + + // 发送坐标 + send(sock, input.c_str(), input.length(), 0); + std::cout << "已发送: " << input << std::endl; + + // 接收服务器响应 + memset(buffer, 0, BUFFER_SIZE); + int valread = read(sock, buffer, BUFFER_SIZE); + buffer[valread] = '\0'; + std::cout << "服务器响应: " << buffer << std::endl; + } + + // 关闭连接 + close(sock); + + return 0; +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/CMakeLists.txt b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/CMakeLists.txt new file mode 100644 index 0000000..95fad34 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.10) +project(MAVLinkClient) + +# 设置C++标准 +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# 查找必要的包 +find_package(Threads REQUIRED) + +# 添加c_library_v2 MAVLink SDK头文件目录 +include_directories(${CMAKE_SOURCE_DIR}/c_library_v2) +include_directories(${CMAKE_SOURCE_DIR}/include) + +# 添加源文件 +set(SOURCES + src/mavlink_client.cpp + src/main.cpp +) + +# 创建可执行文件 +add_executable(mavlink_client ${SOURCES}) + +# 链接线程库 +target_link_libraries(mavlink_client Threads::Threads) + +# 添加编译选项 +target_compile_options(mavlink_client PRIVATE -Wall -Wextra) \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/README.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/README.md new file mode 100644 index 0000000..f8e1298 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/README.md @@ -0,0 +1,93 @@ +# MAVLink客户端 + +这是一个简单的MAVLink客户端应用程序,用于通过UDP连接到MAVLink兼容的无人机(如ArduPilot、PX4等)并显示其状态信息。 + +## 功能 + +- 连接到指定IP和端口的MAVLink设备 +- 接收和解析MAVLink消息 +- 显示无人机的以下状态信息: + - 心跳信息(系统类型、自动驾驶仪类型、系统模式等) + - 系统状态(电池信息、传感器健康状态等) + - 姿态信息(滚转角、俯仰角、偏航角) + - 位置信息(经纬度、高度、地面速度) + +## 依赖项 + +- C++17兼容的编译器 +- CMake (>= 3.10) +- MAVLink C库(c_library_v2) +- POSIX兼容的操作系统(Linux/Mac OS) + +## 构建 + +```bash +# 克隆仓库(如果尚未克隆) +git clone https://github.com/mavlink/c_library_v2.git + +# 创建构建目录 +mkdir build +cd build + +# 配置和构建 +cmake .. +make +``` + +## 使用方法 + +```bash +./mavlink_client <无人机IP> <端口> +``` + +例如: + +```bash +./mavlink_client 192.168.1.10 14550 +``` + +## 工作原理 + +1. 程序通过UDP套接字连接到指定的IP和端口 +2. 接收MAVLink消息并解析 +3. 向无人机请求数据流 +4. 通过回调函数显示无人机状态信息 + +## 示例输出 + +``` +------- 心跳消息 ------- +系统类型: 2 +自动驾驶仪类型: 3 +系统模式: 5 +系统状态: 4 +MAVLink版本: 2 + +------- 系统状态 ------- +电池电压: 12.60 V +电池电流: 5.20 A +电池剩余: 75 % +传感器存在: 0x1fff +传感器使能: 0x1fff +传感器健康: 0x1fff +CPU负载: 32.0 % + +------- 姿态信息 ------- +Roll: 1.50 度 +Pitch: -2.30 度 +Yaw: 175.60 度 + +------- 位置信息 ------- +纬度: 40.7128000 度 +经度: -74.0060000 度 +绝对高度: 35.20 米 +相对高度: 10.50 米 +地速 X: 1.25 m/s +地速 Y: 0.50 m/s +地速 Z: 0.10 m/s +``` + +## 注意事项 + +- 确保防火墙允许UDP通信 +- 如果使用模拟器,请确保模拟器配置为发送MAVLink数据到正确的IP和端口 \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/build.sh b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/build.sh new file mode 100644 index 0000000..e717605 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/build.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# 确保脚本在出错时停止执行 +set -e + +# 打印帮助信息 +print_help() { + echo "用法: $0 [选项]" + echo "选项:" + echo " --clean 清理构建目录" + echo " --help 显示帮助信息" + echo "示例:" + echo " $0 构建项目" + echo " $0 --clean 清理并重新构建项目" +} + +# 清理构建目录 +clean_build() { + echo "清理构建目录..." + rm -rf build +} + +# 构建项目 +build_project() { + # 创建构建目录 + mkdir -p build + cd build + + # 配置和构建 + cmake .. + make -j$(nproc) + + echo "" + echo "构建成功!" + echo "使用方法: ./mavlink_client <无人机IP> <端口>" + echo "例如: ./mavlink_client 192.168.1.10 14550" +} + +# 处理命令行参数 +if [ "$1" == "--help" ]; then + print_help + exit 0 +elif [ "$1" == "--clean" ]; then + clean_build +fi + +# 构建项目 +build_project \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/include/mavlink_client.h b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/include/mavlink_client.h new file mode 100644 index 0000000..7c8b843 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/include/mavlink_client.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +// MAVLink头文件 +#include "../c_library_v2/common/mavlink.h" + +// 定义无人机状态回调函数类型 +typedef std::function HeartbeatCallback; +typedef std::function SystemStatusCallback; +typedef std::function AttitudeCallback; +typedef std::function PositionCallback; +// 添加GPS状态回调函数类型 +typedef std::function GPSCallback; + +class MAVLinkClient { +public: + MAVLinkClient(); + ~MAVLinkClient(); + + // 连接到指定IP和端口的无人机 + bool connect(const std::string& ip, int port); + + // 断开连接 + void disconnect(); + + // 检查是否已连接 + bool isConnected() const; + + // 设置各种状态回调 + void setHeartbeatCallback(HeartbeatCallback callback); + void setSystemStatusCallback(SystemStatusCallback callback); + void setAttitudeCallback(AttitudeCallback callback); + void setPositionCallback(PositionCallback callback); + // 添加设置GPS回调的方法 + void setGPSCallback(GPSCallback callback); + + // 请求无人机数据 + void requestDataStream(); + + // 发送MAVLink命令 + bool sendCommand(uint16_t command, float param1, float param2, + float param3, float param4, float param5, + float param6, float param7); + +private: + // 接收消息线程函数 + void receiveThread(); + + // 处理接收到的MAVLink消息 + void handleMessage(const mavlink_message_t& message); + + // 发送MAVLink消息 + void sendMessage(const mavlink_message_t& message); + +private: + int _socket; + struct sockaddr_in _targetAddr; + bool _connected; + std::atomic _running; + std::thread _thread; + std::mutex _mutex; + + // 回调函数 + HeartbeatCallback _heartbeatCallback; + SystemStatusCallback _systemStatusCallback; + AttitudeCallback _attitudeCallback; + PositionCallback _positionCallback; + // 添加GPS回调函数 + GPSCallback _gpsCallback; + + // 消息计数器 + uint8_t _systemId; + uint8_t _componentId; + uint8_t _targetSystemId; + uint8_t _targetComponentId; + uint8_t _messageSequence; +}; \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/run.sh b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/run.sh new file mode 100644 index 0000000..4edc36f --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/run.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# 设置默认IP和端口 +DEFAULT_IP="192.168.1.10" +DEFAULT_PORT="14550" + +# 打印帮助信息 +print_help() { + echo "用法: $0 [选项]" + echo "选项:" + echo " --ip=IP 设置无人机IP地址 (默认: $DEFAULT_IP)" + echo " --port=PORT 设置无人机端口 (默认: $DEFAULT_PORT)" + echo " --help 显示帮助信息" + echo "示例:" + echo " $0 使用默认IP和端口运行" + echo " $0 --ip=192.168.4.1 --port=14551 使用指定IP和端口运行" +} + +# 初始化IP和端口为默认值 +IP=$DEFAULT_IP +PORT=$DEFAULT_PORT + +# 解析命令行参数 +for arg in "$@"; do + case $arg in + --ip=*) + IP="${arg#*=}" + ;; + --port=*) + PORT="${arg#*=}" + ;; + --help) + print_help + exit 0 + ;; + *) + echo "未知参数: $arg" + print_help + exit 1 + ;; + esac +done + +# 检查构建目录是否存在 +if [ ! -d "build" ]; then + echo "错误: 找不到构建目录。请先执行 ./build.sh 构建项目。" + exit 1 +fi + +# 检查可执行文件是否存在 +if [ ! -f "build/mavlink_client" ]; then + echo "错误: 找不到可执行文件。请先执行 ./build.sh 构建项目。" + exit 1 +fi + +# 运行客户端 +echo "运行MAVLink客户端,连接到 $IP:$PORT..." +echo "按 Ctrl+C 终止程序" +echo "" +build/mavlink_client $IP $PORT \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/src/main.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/src/main.cpp new file mode 100644 index 0000000..acfb11b --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/src/main.cpp @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include "../include/mavlink_client.h" + +// 全局变量,用于信号处理 +MAVLinkClient* g_client = nullptr; +bool g_running = true; + +// 信号处理函数 +void signalHandler(int signum) { + std::cout << "\n接收到信号 " << signum << ",准备退出..." << std::endl; + g_running = false; +} + +// 处理心跳消息回调 +void handleHeartbeat(const mavlink_heartbeat_t& heartbeat) { + std::cout << "------- 心跳消息 -------" << std::endl; + std::cout << "系统类型: " << static_cast(heartbeat.type) << std::endl; + std::cout << "自动驾驶仪类型: " << static_cast(heartbeat.autopilot) << std::endl; + + // 获取系统状态 + std::cout << "系统模式: " << static_cast(heartbeat.custom_mode) << std::endl; + std::cout << "系统状态: " << static_cast(heartbeat.system_status) << std::endl; + + // 解析MAVLink标志 + std::cout << "MAVLink版本: " << static_cast(heartbeat.mavlink_version) << std::endl; +} + +// 处理系统状态消息回调 +void handleSystemStatus(const mavlink_sys_status_t& status) { + std::cout << "------- 系统状态 -------" << std::endl; + + // 电池信息 + float voltage = status.voltage_battery / 1000.0f; // 转换为伏特 + float current = status.current_battery / 100.0f; // 转换为安培 + int remaining = status.battery_remaining; // 电池剩余百分比 + + std::cout << "电池电压: " << std::fixed << std::setprecision(2) << voltage << " V" << std::endl; + std::cout << "电池电流: " << std::fixed << std::setprecision(2) << current << " A" << std::endl; + std::cout << "电池剩余: " << remaining << " %" << std::endl; + + // 传感器健康状态 + std::cout << "传感器存在: 0x" << std::hex << status.onboard_control_sensors_present << std::endl; + std::cout << "传感器使能: 0x" << std::hex << status.onboard_control_sensors_enabled << std::endl; + std::cout << "传感器健康: 0x" << std::hex << status.onboard_control_sensors_health << std::dec << std::endl; + + // CPU负载 + std::cout << "CPU负载: " << static_cast(status.load) / 10.0f << " %" << std::endl; +} + +// 处理姿态消息回调 +void handleAttitude(const mavlink_attitude_t& attitude) { + // 将弧度转换为角度 + float roll = attitude.roll * 180.0f / M_PI; + float pitch = attitude.pitch * 180.0f / M_PI; + float yaw = attitude.yaw * 180.0f / M_PI; + + std::cout << "------- 姿态信息 -------" << std::endl; + std::cout << "Roll: " << std::fixed << std::setprecision(2) << roll << " 度" << std::endl; + std::cout << "Pitch: " << std::fixed << std::setprecision(2) << pitch << " 度" << std::endl; + std::cout << "Yaw: " << std::fixed << std::setprecision(2) << yaw << " 度" << std::endl; +} + +// 处理位置消息回调 +void handlePosition(const mavlink_global_position_int_t& position) { + // 转换为度数 + float latitude = position.lat / 1.0e7f; + float longitude = position.lon / 1.0e7f; + float altitude = position.alt / 1000.0f; // 转换为米 + float relative_altitude = position.relative_alt / 1000.0f; // 转换为米 + + std::cout << "------- 位置信息 -------" << std::endl; + std::cout << "纬度: " << std::fixed << std::setprecision(7) << latitude << " 度" << std::endl; + std::cout << "经度: " << std::fixed << std::setprecision(7) << longitude << " 度" << std::endl; + std::cout << "绝对高度: " << std::fixed << std::setprecision(2) << altitude << " 米" << std::endl; + std::cout << "相对高度: " << std::fixed << std::setprecision(2) << relative_altitude << " 米" << std::endl; + + // 地面速度 + float vx = position.vx / 100.0f; // 转换为米/秒 + float vy = position.vy / 100.0f; // 转换为米/秒 + float vz = position.vz / 100.0f; // 转换为米/秒 + + std::cout << "地速 X: " << std::fixed << std::setprecision(2) << vx << " m/s" << std::endl; + std::cout << "地速 Y: " << std::fixed << std::setprecision(2) << vy << " m/s" << std::endl; + std::cout << "地速 Z: " << std::fixed << std::setprecision(2) << vz << " m/s" << std::endl; +} + +int main(int argc, char* argv[]) { + // 注册信号处理 + signal(SIGINT, signalHandler); + + // 检查参数 + if (argc < 3) { + std::cout << "用法: " << argv[0] << " <无人机IP> <端口>" << std::endl; + std::cout << "示例: " << argv[0] << " 192.168.1.10 14550" << std::endl; + return 1; + } + + std::string ip = argv[1]; + int port = std::stoi(argv[2]); + + std::cout << "尝试连接到无人机: " << ip << ":" << port << std::endl; + + // 创建MAVLink客户端 + MAVLinkClient client; + g_client = &client; + + // 设置回调函数 + client.setHeartbeatCallback(handleHeartbeat); + client.setSystemStatusCallback(handleSystemStatus); + client.setAttitudeCallback(handleAttitude); + client.setPositionCallback(handlePosition); + + // 连接到无人机 + if (!client.connect(ip, port)) { + std::cerr << "连接失败!" << std::endl; + return 1; + } + + // 请求数据流 + client.requestDataStream(); + + std::cout << "已连接到无人机,按 Ctrl+C 退出。" << std::endl; + + // 主循环 + while (g_running) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + + // 断开连接 + client.disconnect(); + std::cout << "程序已退出" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/src/mavlink_client.cpp b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/src/mavlink_client.cpp new file mode 100644 index 0000000..9fa24d8 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/src/mavlink_client.cpp @@ -0,0 +1,361 @@ +#include "../include/mavlink_client.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MAVLinkClient::MAVLinkClient() + : _socket(-1) + , _connected(false) + , _running(false) + , _systemId(255) // QGC默认为255 + , _componentId(1) // 1表示地面站 + , _targetSystemId(1) // 目标系统ID,通常无人机为1 + , _targetComponentId(0) // 0表示广播到所有组件 + , _messageSequence(0) +{ +} + +MAVLinkClient::~MAVLinkClient() { + disconnect(); +} + +bool MAVLinkClient::connect(const std::string& ip, int port) { + // 如果已经连接,先断开 + if (_connected) { + disconnect(); + } + + // 创建TCP套接字 + _socket = socket(AF_INET, SOCK_STREAM, 0); + if (_socket < 0) { + std::cerr << "无法创建套接字: " << strerror(errno) << std::endl; + return false; + } + + // 设置目标地址 + memset(&_targetAddr, 0, sizeof(_targetAddr)); + _targetAddr.sin_family = AF_INET; + _targetAddr.sin_addr.s_addr = inet_addr(ip.c_str()); + _targetAddr.sin_port = htons(port); + + // 设置非阻塞模式用于超时处理 + int flags = fcntl(_socket, F_GETFL, 0); + fcntl(_socket, F_SETFL, flags | O_NONBLOCK); + + // 尝试建立TCP连接 + int result = ::connect(_socket, (struct sockaddr*)&_targetAddr, sizeof(_targetAddr)); + if (result < 0 && errno != EINPROGRESS) { + std::cerr << "无法连接到 " << ip << ":" << port << ": " << strerror(errno) << std::endl; + close(_socket); + _socket = -1; + return false; + } + + // 用select检查连接是否建立成功(设置超时) + fd_set write_fds; + struct timeval timeout; + + FD_ZERO(&write_fds); + FD_SET(_socket, &write_fds); + + timeout.tv_sec = 3; // 3秒超时 + timeout.tv_usec = 0; + + result = select(_socket + 1, NULL, &write_fds, NULL, &timeout); + + if (result <= 0) { + if (result == 0) { + std::cerr << "连接到 " << ip << ":" << port << " 超时" << std::endl; + } else { + std::cerr << "select错误: " << strerror(errno) << std::endl; + } + close(_socket); + _socket = -1; + return false; + } + + // 检查连接是否真的建立成功 + int error = 0; + socklen_t len = sizeof(error); + if (getsockopt(_socket, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error != 0) { + std::cerr << "连接失败: " << strerror(error) << std::endl; + close(_socket); + _socket = -1; + return false; + } + + // 恢复为阻塞模式 + fcntl(_socket, F_SETFL, flags); + + // 发送心跳包测试连接 + mavlink_message_t test_msg; + mavlink_heartbeat_t heartbeat; + + heartbeat.type = MAV_TYPE_GCS; + heartbeat.autopilot = MAV_AUTOPILOT_INVALID; + heartbeat.base_mode = 0; + heartbeat.custom_mode = 0; + heartbeat.system_status = MAV_STATE_STANDBY; + + mavlink_msg_heartbeat_encode(_systemId, _componentId, &test_msg, &heartbeat); + + // 序列化消息 + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + int length = mavlink_msg_to_send_buffer(buffer, &test_msg); + + // 使用TCP发送数据 + int sent = ::send(_socket, buffer, length, 0); + if (sent != length) { + std::cerr << "发送测试消息失败: " << strerror(errno) << std::endl; + close(_socket); + _socket = -1; + return false; + } + + // 启动接收线程 + _connected = true; + _running = true; + _thread = std::thread(&MAVLinkClient::receiveThread, this); + + std::cout << "已通过TCP连接到 " << ip << ":" << port << std::endl; + return true; +} + +void MAVLinkClient::disconnect() { + if (!_connected) { + return; + } + + // 停止接收线程 + _running = false; + if (_thread.joinable()) { + _thread.join(); + } + + // 关闭套接字 + if (_socket >= 0) { + close(_socket); + _socket = -1; + } + + _connected = false; + std::cout << "已断开连接" << std::endl; +} + +// 检查MAVLink客户端是否已连接 +bool MAVLinkClient::isConnected() const { + return _connected; +} + +// 设置心跳包回调函数,用于处理来自飞行器的心跳消息 +void MAVLinkClient::setHeartbeatCallback(HeartbeatCallback callback) { + std::lock_guard lock(_mutex); // 线程安全锁,防止并发访问 + _heartbeatCallback = callback; +} + +// 设置系统状态回调函数,用于处理飞行器系统状态信息 +void MAVLinkClient::setSystemStatusCallback(SystemStatusCallback callback) { + std::lock_guard lock(_mutex); // 线程安全锁,防止并发访问 + _systemStatusCallback = callback; +} + +// 设置姿态回调函数,用于处理飞行器的姿态数据(俯仰、横滚、偏航角) +void MAVLinkClient::setAttitudeCallback(AttitudeCallback callback) { + std::lock_guard lock(_mutex); // 线程安全锁,防止并发访问 + _attitudeCallback = callback; +} + +// 设置位置回调函数,用于处理飞行器的位置坐标信息 +void MAVLinkClient::setPositionCallback(PositionCallback callback) { + std::lock_guard lock(_mutex); // 线程安全锁,防止并发访问 + _positionCallback = callback; +} + +// 设置GPS回调函数,用于处理GPS定位和导航信息 +void MAVLinkClient::setGPSCallback(GPSCallback callback) { + std::lock_guard lock(_mutex); // 线程安全锁,防止并发访问 + _gpsCallback = callback; +} + +void MAVLinkClient::requestDataStream() { + if (!_connected) { + std::cerr << "请先连接到无人机" << std::endl; + return; + } + + // 构造请求数据流消息 + mavlink_message_t msg; + mavlink_request_data_stream_t stream; + + stream.target_system = _targetSystemId; + stream.target_component = _targetComponentId; + stream.req_stream_id = MAV_DATA_STREAM_ALL; // 请求所有数据 + stream.req_message_rate = 10; // 10Hz + stream.start_stop = 1; // 1表示开始发送 + + // 打包消息 + mavlink_msg_request_data_stream_encode(_systemId, _componentId, &msg, &stream); + + // 发送消息 + sendMessage(msg); + + std::cout << "已请求数据流" << std::endl; +} + +void MAVLinkClient::sendMessage(const mavlink_message_t& message) { + if (!_connected || _socket < 0) { + return; + } + + // 序列化MAVLink消息 + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + int length = mavlink_msg_to_send_buffer(buffer, &message); + + // 使用TCP发送消息 + send(_socket, buffer, length, 0); +} + +// 添加发送命令的方法 +bool MAVLinkClient::sendCommand(uint16_t command, float param1, float param2, + float param3, float param4, float param5, + float param6, float param7) { + if (!_connected || _socket < 0) { + std::cerr << "发送命令失败: 未连接到无人机" << std::endl; + return false; + } + + // 构造命令消息 + mavlink_message_t msg; + mavlink_command_long_t cmd; + + // 设置命令参数 + cmd.target_system = _targetSystemId; // 目标系统ID + cmd.target_component = _targetComponentId; // 目标组件ID + cmd.command = command; // 命令ID + cmd.confirmation = 0; // 确认次数,首次发送为0 + cmd.param1 = param1; + cmd.param2 = param2; + cmd.param3 = param3; + cmd.param4 = param4; + cmd.param5 = param5; + cmd.param6 = param6; + cmd.param7 = param7; + + // 打包消息 + mavlink_msg_command_long_encode(_systemId, _componentId, &msg, &cmd); + + // 发送消息 + sendMessage(msg); + + std::cout << "已发送命令 " << command << std::endl; + return true; +} + +void MAVLinkClient::receiveThread() { + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + + // 消息解析状态 + mavlink_status_t status; + mavlink_message_t message; + + while (_running) { + // 尝试从TCP连接接收数据 + int recvLen = recv(_socket, buffer, sizeof(buffer), 0); + + if (recvLen > 0) { + // 解析MAVLink消息 + for (int i = 0; i < recvLen; ++i) { + if (mavlink_parse_char(MAVLINK_COMM_0, buffer[i], &message, &status)) { + // 接收到完整消息,存储目标系统和组件ID + if (message.msgid == MAVLINK_MSG_ID_HEARTBEAT) { + _targetSystemId = message.sysid; + _targetComponentId = message.compid; + } + + // 处理消息 + handleMessage(message); + } + } + } else if (recvLen == 0) { + // 连接已关闭 + std::cerr << "TCP连接已关闭" << std::endl; + _connected = false; + break; + } else if (errno != EAGAIN && errno != EWOULDBLOCK) { + // 发生错误 + std::cerr << "接收数据错误: " << strerror(errno) << std::endl; + _connected = false; + break; + } + + // 短暂睡眠,减少CPU使用 + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +void MAVLinkClient::handleMessage(const mavlink_message_t& message) { + // 根据消息ID分发处理 + switch (message.msgid) { + case MAVLINK_MSG_ID_HEARTBEAT: { + mavlink_heartbeat_t heartbeat; + mavlink_msg_heartbeat_decode(&message, &heartbeat); + + std::lock_guard lock(_mutex); + if (_heartbeatCallback) { + _heartbeatCallback(heartbeat); + } + break; + } + + case MAVLINK_MSG_ID_SYS_STATUS: { + mavlink_sys_status_t sysStatus; + mavlink_msg_sys_status_decode(&message, &sysStatus); + + std::lock_guard lock(_mutex); + if (_systemStatusCallback) { + _systemStatusCallback(sysStatus); + } + break; + } + + case MAVLINK_MSG_ID_ATTITUDE: { + mavlink_attitude_t attitude; + mavlink_msg_attitude_decode(&message, &attitude); + + std::lock_guard lock(_mutex); + if (_attitudeCallback) { + _attitudeCallback(attitude); + } + break; + } + + case MAVLINK_MSG_ID_GLOBAL_POSITION_INT: { + mavlink_global_position_int_t position; + mavlink_msg_global_position_int_decode(&message, &position); + + std::lock_guard lock(_mutex); + if (_positionCallback) { + _positionCallback(position); + } + break; + } + + case MAVLINK_MSG_ID_GPS_RAW_INT: { + mavlink_gps_raw_int_t gps; + mavlink_msg_gps_raw_int_decode(&message, &gps); + + std::lock_guard lock(_mutex); + if (_gpsCallback) { + _gpsCallback(gps); + } + break; + } + } +} \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/使用说明.md b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/使用说明.md new file mode 100644 index 0000000..061f3d0 --- /dev/null +++ b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/demo/workproject/使用说明.md @@ -0,0 +1,138 @@ +# MAVLink无人机通信客户端 + +## 项目简介 + +这是一个基于MAVLink协议的UDP通信客户端,可以用来连接支持MAVLink协议的无人机(如基于ArduPilot或PX4飞控的无人机),并获取其状态信息。 + +项目使用C++编写,基于MAVLink C库(c_library_v2)实现与无人机的通信。 + +## 功能特点 + +- 通过UDP协议连接到支持MAVLink的无人机 +- 自动请求无人机数据流 +- 实时显示无人机关键状态信息: + - 心跳信息(系统类型、自动驾驶仪类型、系统模式等) + - 系统状态(电池电量、电流、电压等) + - 飞行姿态信息(滚转角、俯仰角、偏航角) + - 全球位置信息(经纬度、高度、地速等) +- 支持自定义回调函数处理MAVLink消息 + +## 项目结构 + +``` +workproject/ +├── build/ # 构建目录(运行build.sh后生成) +├── build.sh # 构建脚本 +├── c_library_v2/ # MAVLink SDK库 +├── CMakeLists.txt # CMake配置文件 +├── include/ # 头文件目录 +│ └── mavlink_client.h # MAVLink客户端类头文件 +├── README.md # 英文说明文件 +├── run.sh # 运行脚本 +├── src/ # 源代码目录 +│ ├── main.cpp # 主程序入口 +│ └── mavlink_client.cpp # MAVLink客户端类实现 +└── 使用说明.md # 中文说明文件(本文件) +``` + +## 环境要求 + +- Linux操作系统(已在Ubuntu 20.04/22.04上测试) +- C++17兼容的编译器(如GCC 9.0+) +- CMake 3.10或更高版本 +- 支持MAVLink协议的无人机或飞控模拟器 + +## 使用方法 + +### 构建项目 + +运行构建脚本来编译项目: + +```bash +./build.sh +``` + +如果需要清理构建目录后重新构建: + +```bash +./build.sh --clean +``` + +### 运行程序 + +使用运行脚本启动程序: + +```bash +./run.sh +``` + +默认连接到192.168.1.10:14550。如果需要连接到不同的IP和端口: + +```bash +./run.sh --ip=192.168.4.1 --port=14551 +``` + +获取帮助信息: + +```bash +./run.sh --help +``` + +### 手动运行 + +也可以直接运行编译后的可执行文件: + +```bash +./build/mavlink_client <无人机IP> <端口> +``` + +例如: + +```bash +./build/mavlink_client 192.168.1.10 14550 +``` + +## 连接无人机的常见方式 + +### 1. 直接连接到无人机的WiFi + +- 连接到无人机创建的WiFi热点 +- 默认IP通常为192.168.4.1或192.168.1.1 +- 常用端口:14550或14555 + +### 2. 通过地面站中继 + +- 无人机连接到地面站软件(如QGroundControl或Mission Planner) +- 地面站开启MAVLink UDP转发 +- 本程序连接到地面站转发的UDP端口(通常为localhost:14550) + +### 3. 连接到SITL模拟器 + +- 连接到软件在环仿真(SITL),如ArduPilot SITL或PX4 SITL +- 默认连接地址通常为localhost:14550 + +## 常见问题 + +1. **连接失败** + - 确认IP和端口正确 + - 检查无人机是否已开启 + - 确认网络连接正常 + - 确认防火墙未阻止UDP通信 + +2. **没有收到数据** + - 确认无人机已正确配置MAVLink数据流 + - 尝试重启无人机 + - 检查MAVLink协议版本兼容性 + +3. **编译错误** + - 确保安装了必要的开发工具(g++, cmake) + - 确保c_library_v2目录存在且包含正确的MAVLink库文件 + +## 开发者信息 + +如需修改程序,主要的类和文件是: + +- `mavlink_client.h`/`mavlink_client.cpp`: MAVLink通信客户端实现 +- `main.cpp`: 主程序入口和示例代码 + +要添加对新消息类型的支持,需要在MAVLinkClient类中添加相应的回调函数和处理逻辑。 \ No newline at end of file diff --git a/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/doc/ViewLinkSDK.chm b/src/声源定位代码/基于多模态的战场隐蔽威胁发现和定位系统总代码/Linux_SDK/doc/ViewLinkSDK.chm new file mode 100644 index 0000000000000000000000000000000000000000..8258f11b746d0df1e476646f8189a7c89f131027 GIT binary patch literal 655818 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

nlik3uiXB6YvpZ3xCi}0x4_y)psYoTL9 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

@N3Br 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�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 and VLK_SENSOR_VISIBLE1 for pParam->emTrackSensor + */ +VLK_API void VLK_CALL VLK_TrackTargetPositionEx(const VLK_TRACK_MODE_PARAM* pParam, int iX, int iY, int iVideoWidth, int iVideoHeight); + +/** @brief Disable track mode + */ +VLK_API void VLK_CALL VLK_DisableTrackMode(); + +/** @brief Focus in + * @param sSpeed the speed of focus in + * @details sSpeed must be a short number from VLK_MIN_ZOOM_SPEED to VLK_MAX_ZOOM_SPEED, the bigger the faster + * this function is available only when the Gimbal is in Manual focusing mode, call VLK_GetFocusMode to + * get current focus mode, call VLK_SetFocusMode to set focus mode + */ +VLK_API void VLK_CALL VLK_FocusIn(short sSpeed); + +/** @brief Focus out + * @param sSpeed the speed of focus out + * @details sSpeed must be a short number from VLK_MIN_ZOOM_SPEED to VLK_MAX_ZOOM_SPEED, the bigger the faster + * this function is available only when the Gimbal is in Manual focusing mode, call VLK_GetFocusMode to + * get current focus mode, call VLK_SetFocusMode to set focus mode + */ +VLK_API void VLK_CALL VLK_FocusOut(short sSpeed); + +/** @brief Stop focus + * @details once you call VLK_FocusIn or VLK_FocusOut, Camera will keep focusing until it reach the limitation or VLK_StopFocus is called + */ +VLK_API void VLK_CALL VLK_StopFocus(); + +/** @brief Move to home position + */ +VLK_API void VLK_CALL VLK_Home(); + +/** @brief Switch motor + * @param iOn turn on/turn off \n + * 1 turn on \n + * 0 turn off + */ +VLK_API void VLK_CALL VLK_SwitchMotor(int iOn); + +/** @brief Check motor status + * @return current motor status + * @retval 1 on + * @retval 0 off + */ +VLK_API int VLK_CALL VLK_IsMotorOn(); + +/** @brief Enable Gimbal follow drone + * @param iEnable enable or disable \n + * 1 enable \n + * 0 disable + */ +VLK_API void VLK_CALL VLK_EnableFollowMode(int iEnable); + +/** @brief Check follow mode + * @return current follow status + * @retval 1 enabled + * @retval 0 disabled + */ +VLK_API int VLK_CALL VLK_IsFollowMode(); + +/** @brief Turn to specific yaw and pitch + * @param dYaw specific yaw, must be a double value from VLK_YAW_MIN to VLK_YAW_MAX + * @param dPitch specific pitch, must be a double value from VLK_PITCH_MIN to VLK_PITCH_MAX + */ +VLK_API void VLK_CALL VLK_TurnTo(double dYaw, double dPitch); + +/** @brief Enable track + */ +VLK_API void VLK_CALL VLK_StartTrack(); + + +/** @brief Disable track + */ +VLK_API void VLK_CALL VLK_StopTrack(); + +/** @brief Check if track is enabled + * @return current track status + * @retval 1 enabled + * @retval 0 disabled + */ +VLK_API int VLK_CALL VLK_IsTracking(); + +/** @brief Set track template size + * @param emSize track template size enumeration + * @see VLK_TRACK_TEMPLATE_SIZE + */ +VLK_API void VLK_CALL VLK_SetTrackTemplateSize(VLK_TRACK_TEMPLATE_SIZE emSize); + +/** @brief Set image color + * @param emImgType image type enumeration + * @param iEnablePIP enable picture in picture \n + * 1 enable \n + * 0 disable + * @param emIRColor IR color enumeration + * @see VLK_IMAGE_TYPE + */ +VLK_API void VLK_CALL VLK_SetImageColor(VLK_IMAGE_TYPE emImgType, int iEnablePIP, VLK_IR_COLOR emIRColor); + +/** @brief Ask Gimbal take a photograph + * @details make sure there is SD card in the Gimbal + */ +VLK_API void VLK_CALL VLK_Photograph(); + +/** @brief Gimbal start or stop recording + * @param iOn \n + * 1 start recording \n + * 0 stop recording + * @details make sure there is SD card in the Gimbal + */ +VLK_API void VLK_CALL VLK_SwitchRecord(int iOn); + +/** @brief Check if Gimbal is recording + * @return flag of recording status + * @retval 1 recording + * @retval 0 not recording + * @details make sure there is SD card in the Gimbal + */ +VLK_API int VLK_CALL VLK_IsRecording(); + +/** @brief Enable defog + * @param iOn \n + * 1 defog is enabled \n + * 0 defog is disabled + */ +VLK_API void VLK_CALL VLK_SwitchDefog(int iOn); + +/** @brief Check if defog is enabled + * @return flag of defog status + * @retval 1 defog is enabled + * @retval 0 defog is disabled + */ +VLK_API int VLK_CALL VLK_IsDefogOn(); + +/** @brief Set record mode + * @param emMode record mode enumeration + * @details some models could not take photo while it is recording, + * they must be switched to a certain + * @see VLK_RECORD_MODE + */ +VLK_API void VLK_CALL VLK_SetRecordMode(VLK_RECORD_MODE emMode); + +/** @brief Get current record mode + * @return record mode enumeration + * @see VLK_RECORD_MODE + */ +VLK_API int VLK_CALL VLK_GetRecordMode(); + +/** @brief Set focus mode ( manual focus or automatic focus) + * @param focus mode enumeration + * @see VLK_FOCUS_MODE + */ +VLK_API void VLK_CALL VLK_SetFocusMode(VLK_FOCUS_MODE emMode); + +/** @brief Get current focus mode ( manual focus or automatic focus) + * @return focus mode enumeration + * @see VLK_FOCUS_MODE + */ +VLK_API int VLK_CALL VLK_GetFocusMode(); + +/** @brief Zoom to a specific magnification + * @param fMag specific magnification + * @details the camera will reach the limitation if the specific magnification over it's capability + */ +VLK_API void VLK_CALL VLK_ZoomTo(float fMag); + +/** @brief IR digital zoom in + * @param sSpeed deprecated, pass 0 + * @details zoom in x1 then stop automatically + */ +VLK_API void VLK_CALL VLK_IRDigitalZoomIn(short sSpeed); + +/** @brief IR digital zoom out + * @param sSpeed deprecated, pass 0 + * @details zoom out x1 then stop automatically + */ +VLK_API void VLK_CALL VLK_IRDigitalZoomOut(short sSpeed); + +/** @brief Switch EO digital zoom status + * @param iOn \n + * 1 enable \n + * 0 disable + */ +VLK_API void VLK_CALL VLK_SwitchEODigitalZoom(int iOn); + +/** @brief Enter S-BUS mode + * @deprecated + */ +VLK_API void VLK_CALL VLK_EnterSBUSMode(); + +/** @brief Exit S-BUS mode + * @deprecated + */ +VLK_API void VLK_CALL VLK_ExitSBUSMode(); + +/** @brief Query device configuration + * @details this function is asynchronous, configuration data will be passed back throw VLK_DevStatus_CB + * @see VLK_DevStatus_CB + */ +VLK_API void VLK_CALL VLK_QueryDevConfiguration(); + +/** @brief Set OSD + * @param pParam OSG configuration + * @details we don't provide VLK_GetOSD because OSD is included in device configuration + * @see VLK_OSD_PARAM + */ +VLK_API void VLK_CALL VLK_SetOSD(const VLK_OSD_PARAM* pParam); + +/** @brief Set wireless control channels map + * @param pChnlsMap wireless control channels map configuration + * @details we don't provide VLK_GetWirelessCtrlChnlMap because channels map is included in device configuration + * @see VLK_CHANNELS_MAP + */ +VLK_API void VLK_CALL VLK_SetWirelessCtrlChnlMap(const VLK_CHANNELS_MAP* pChnlsMap); + +/** @brief Send extent command + * @param szCmd command data pointer + * @param iLen command data length + * @details for some seldom-used Gimbal control command which we didn't provide specific interface, + * you should call this function to send command data directly + */ +VLK_API void VLK_CALL VLK_SendExtentCmd(const char* szCmd, int iLen); + + +/** @name Laser Control functions + * @{ + */ + +/** @brief Switch laser status + * @param iOn \n + * 1 turn on \n + * 0 turn off + * @details make sure your device has laser capability + */ +VLK_API void VLK_CALL VLK_SwitchLaser(int iOn); + +/** @brief Laser single ranging + */ +VLK_API void VLK_CALL VLK_LaserSingle(); + + +/** @brief Laser zoom in + * @param sSpeed deprecated, pass 0 + */ +VLK_API void VLK_CALL VLK_LaserZoomIn(short sSpeed); + +/** @brief Laser zoom out + * @param sSpeed deprecated, pass 0 + */ +VLK_API void VLK_CALL VLK_LaserZoomOut(short sSpeed); + +/** @brief Laser stop zoom + */ +VLK_API void VLK_CALL VLK_LaserStopZoom(); + +/** @brief Set laser zoom mode + * @param emMode laser zoom mode enumeration + */ +VLK_API void VLK_CALL VLK_SetLaserZoomMode(VLK_LASER_ZOOM_MODE emMode); +/** @} Laser Control functions */ + +#ifdef __cplusplus +} +#endif + +#endif //__VIEW_LINK_H__

RCskWJR87$#^`ZQJX$6b66Y2U_~^ntwMbw3W6`t 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�U$ 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