diff --git a/.github/ISSUE_TEMPLATE/camera_support_request.yml b/.github/DISCUSSION_TEMPLATE/camera-support.yml
similarity index 93%
rename from .github/ISSUE_TEMPLATE/camera_support_request.yml
rename to .github/DISCUSSION_TEMPLATE/camera-support.yml
index 7640d26ec..1e199295c 100644
--- a/.github/ISSUE_TEMPLATE/camera_support_request.yml
+++ b/.github/DISCUSSION_TEMPLATE/camera-support.yml
@@ -1,8 +1,5 @@
-name: Camera Support Request
-description: Support for setting up cameras in Frigate
title: "[Camera Support]: "
labels: ["support", "triage"]
-assignees: []
body:
- type: textarea
id: description
@@ -14,7 +11,7 @@ body:
id: version
attributes:
label: Version
- description: Visible on the Debug page in the Web UI
+ description: Visible on the System page in the Web UI
validations:
required: true
- type: textarea
diff --git a/.github/ISSUE_TEMPLATE/config_support_request.yml b/.github/DISCUSSION_TEMPLATE/config-support.yml
similarity index 92%
rename from .github/ISSUE_TEMPLATE/config_support_request.yml
rename to .github/DISCUSSION_TEMPLATE/config-support.yml
index cb95f6fa9..5a49292fc 100644
--- a/.github/ISSUE_TEMPLATE/config_support_request.yml
+++ b/.github/DISCUSSION_TEMPLATE/config-support.yml
@@ -1,8 +1,5 @@
-name: Config Support Request
-description: Support for Frigate configuration
title: "[Config Support]: "
labels: ["support", "triage"]
-assignees: []
body:
- type: textarea
id: description
@@ -14,7 +11,7 @@ body:
id: version
attributes:
label: Version
- description: Visible on the Debug page in the Web UI
+ description: Visible on the System page in the Web UI
validations:
required: true
- type: textarea
diff --git a/.github/ISSUE_TEMPLATE/detector_support_request.yml b/.github/DISCUSSION_TEMPLATE/detector-support.yml
similarity index 90%
rename from .github/ISSUE_TEMPLATE/detector_support_request.yml
rename to .github/DISCUSSION_TEMPLATE/detector-support.yml
index 3f5b34935..4ac95754b 100644
--- a/.github/ISSUE_TEMPLATE/detector_support_request.yml
+++ b/.github/DISCUSSION_TEMPLATE/detector-support.yml
@@ -1,8 +1,5 @@
-name: Detector Support Request
-description: Support for setting up object detector in Frigate (Coral, OpenVINO, TensorRT, etc.)
title: "[Detector Support]: "
labels: ["support", "triage"]
-assignees: []
body:
- type: textarea
id: description
@@ -14,7 +11,7 @@ body:
id: version
attributes:
label: Version
- description: Visible on the Debug page in the Web UI
+ description: Visible on the System page in the Web UI
validations:
required: true
- type: textarea
diff --git a/.github/ISSUE_TEMPLATE/general_support_request.yml b/.github/DISCUSSION_TEMPLATE/general-support.yml
similarity index 93%
rename from .github/ISSUE_TEMPLATE/general_support_request.yml
rename to .github/DISCUSSION_TEMPLATE/general-support.yml
index 7138cd844..7c8d534cc 100644
--- a/.github/ISSUE_TEMPLATE/general_support_request.yml
+++ b/.github/DISCUSSION_TEMPLATE/general-support.yml
@@ -1,8 +1,5 @@
-name: General Support Request
-description: General support request for Frigate
title: "[Support]: "
labels: ["support", "triage"]
-assignees: []
body:
- type: textarea
id: description
@@ -14,7 +11,7 @@ body:
id: version
attributes:
label: Version
- description: Visible on the Debug page in the Web UI
+ description: Visible on the System page in the Web UI
validations:
required: true
- type: textarea
diff --git a/.github/ISSUE_TEMPLATE/hwaccel_support_request.yml b/.github/DISCUSSION_TEMPLATE/hardware-acceleration-support.yml
similarity index 92%
rename from .github/ISSUE_TEMPLATE/hwaccel_support_request.yml
rename to .github/DISCUSSION_TEMPLATE/hardware-acceleration-support.yml
index 82c64c4c3..43960c537 100644
--- a/.github/ISSUE_TEMPLATE/hwaccel_support_request.yml
+++ b/.github/DISCUSSION_TEMPLATE/hardware-acceleration-support.yml
@@ -1,8 +1,5 @@
-name: Hardware Acceleration Support Request
-description: Support for setting up GPU hardware acceleration in Frigate
title: "[HW Accel Support]: "
labels: ["support", "triage"]
-assignees: []
body:
- type: textarea
id: description
@@ -14,7 +11,7 @@ body:
id: version
attributes:
label: Version
- description: Visible on the Debug page in the Web UI
+ description: Visible on the System page in the Web UI
validations:
required: true
- type: textarea
diff --git a/.github/DISCUSSION_TEMPLATE/question.yml b/.github/DISCUSSION_TEMPLATE/question.yml
new file mode 100644
index 000000000..41339e609
--- /dev/null
+++ b/.github/DISCUSSION_TEMPLATE/question.yml
@@ -0,0 +1,9 @@
+title: "[Question]: "
+labels: ["question"]
+body:
+ - type: textarea
+ id: description
+ attributes:
+ label: "What is your question:"
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 3ba13e0ce..7ae5ad8ea 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1 +1,5 @@
blank_issues_enabled: false
+contact_links:
+ - name: Frigate Support
+ url: https://github.com/blakeblackshear/frigate/discussions/new/choose
+ about: Get support for setting up or troubelshooting Frigate.
diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml
index c96102edb..88ceab935 100644
--- a/.github/actions/setup/action.yml
+++ b/.github/actions/setup/action.yml
@@ -11,11 +11,22 @@ outputs:
runs:
using: "composite"
steps:
- - name: Remove unnecessary files
- run: |
- sudo rm -rf /usr/share/dotnet
- sudo rm -rf /usr/local/lib/android
- sudo rm -rf /opt/ghc
+ # Stop docker so we can mount more space at /var/lib/docker
+ - name: Stop docker
+ run: sudo systemctl stop docker
+ shell: bash
+ # This creates a virtual volume at /var/lib/docker to maximize the size
+ # As of 2/14/2024, this results in 97G for docker images
+ - name: Maximize build space
+ uses: easimon/maximize-build-space@master
+ with:
+ remove-dotnet: 'true'
+ remove-android: 'true'
+ remove-haskell: 'true'
+ remove-codeql: 'true'
+ build-mount-path: '/var/lib/docker'
+ - name: Start docker
+ run: sudo systemctl start docker
shell: bash
- id: lowercaseRepo
uses: ASzc/change-string-case-action@v5
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c6fad8817..f2cdc91a0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -47,6 +47,57 @@ jobs:
tensorrt.tags=${{ steps.setup.outputs.image-name }}-tensorrt
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64,mode=max
+ - name: AMD/ROCm general build
+ env:
+ AMDGPU: gfx
+ HSA_OVERRIDE: 0
+ uses: docker/bake-action@v3
+ with:
+ push: true
+ targets: rocm
+ files: docker/rocm/rocm.hcl
+ set: |
+ rocm.tags=${{ steps.setup.outputs.image-name }}-rocm
+ *.cache-from=type=gha
+ - name: AMD/ROCm gfx900
+ env:
+ AMDGPU: gfx900
+ HSA_OVERRIDE: 1
+ HSA_OVERRIDE_GFX_VERSION: 9.0.0
+ uses: docker/bake-action@v3
+ with:
+ push: true
+ targets: rocm
+ files: docker/rocm/rocm.hcl
+ set: |
+ rocm.tags=${{ steps.setup.outputs.image-name }}-rocm-gfx900
+ *.cache-from=type=gha
+ - name: AMD/ROCm gfx1030
+ env:
+ AMDGPU: gfx1030
+ HSA_OVERRIDE: 1
+ HSA_OVERRIDE_GFX_VERSION: 10.3.0
+ uses: docker/bake-action@v3
+ with:
+ push: true
+ targets: rocm
+ files: docker/rocm/rocm.hcl
+ set: |
+ rocm.tags=${{ steps.setup.outputs.image-name }}-rocm-gfx1030
+ *.cache-from=type=gha
+ - name: AMD/ROCm gfx1100
+ env:
+ AMDGPU: gfx1100
+ HSA_OVERRIDE: 1
+ HSA_OVERRIDE_GFX_VERSION: 11.0.0
+ uses: docker/bake-action@v3
+ with:
+ push: true
+ targets: rocm
+ files: docker/rocm/rocm.hcl
+ set: |
+ rocm.tags=${{ steps.setup.outputs.image-name }}-rocm-gfx1100
+ *.cache-from=type=gha
arm64_build:
runs-on: ubuntu-latest
name: ARM Build
diff --git a/CODEOWNERS b/CODEOWNERS
index 48b26a359..edae5de84 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -2,5 +2,5 @@
/docker/tensorrt/ @madsciencetist @NateMeyer
/docker/tensorrt/*arm64* @madsciencetist
/docker/tensorrt/*jetson* @madsciencetist
-
/docker/rockchip/ @MarcA711
+/docker/rocm/ @harakas
diff --git a/docker/main/Dockerfile b/docker/main/Dockerfile
index be10657fe..3354a21cc 100644
--- a/docker/main/Dockerfile
+++ b/docker/main/Dockerfile
@@ -196,6 +196,8 @@ EXPOSE 8555/tcp 8555/udp
# Configure logging to prepend timestamps, log to stdout, keep 0 archives and rotate on 10MB
ENV S6_LOGGING_SCRIPT="T 1 n0 s10000000 T"
+# Do not fail on long-running download scripts
+ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0
ENTRYPOINT ["/init"]
CMD []
diff --git a/docker/main/requirements-wheels.txt b/docker/main/requirements-wheels.txt
index 5c98571be..1bbf2fab6 100644
--- a/docker/main/requirements-wheels.txt
+++ b/docker/main/requirements-wheels.txt
@@ -1,20 +1,22 @@
click == 8.1.*
Flask == 2.3.*
imutils == 0.5.*
+markupsafe == 2.1.*
matplotlib == 3.7.*
mypy == 1.6.1
numpy == 1.23.*
onvif_zeep == 0.2.12
opencv-python-headless == 4.7.0.*
-paho-mqtt == 1.6.*
+paho-mqtt == 2.0.*
pandas == 2.1.4
peewee == 3.17.*
peewee_migrate == 1.12.*
psutil == 5.9.*
-pydantic == 1.10.*
+pydantic == 2.6.*
git+https://github.com/fbcotter/py3nvml#egg=py3nvml
PyYAML == 6.0.*
pytz == 2023.3.post1
+pyzmq == 25.1.*
ruamel.yaml == 0.18.*
tzlocal == 5.2
types-PyYAML == 6.0.*
@@ -25,6 +27,7 @@ norfair == 2.2.*
setproctitle == 1.3.*
ws4py == 0.5.*
unidecode == 1.3.*
+onnxruntime == 1.16.*
# Openvino Library - Custom built with MYRIAD support
openvino @ https://github.com/NateMeyer/openvino-wheels/releases/download/multi-arch_2022.3.1/openvino-2022.3.1-1-cp39-cp39-manylinux_2_31_x86_64.whl; platform_machine == 'x86_64'
openvino @ https://github.com/NateMeyer/openvino-wheels/releases/download/multi-arch_2022.3.1/openvino-2022.3.1-1-cp39-cp39-linux_aarch64.whl; platform_machine == 'aarch64'
diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/dependencies.d/base b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/dependencies.d/base
new file mode 100644
index 000000000..e69de29bb
diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/run
new file mode 100755
index 000000000..c1d03a71d
--- /dev/null
+++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/run
@@ -0,0 +1,35 @@
+#!/command/with-contenv bash
+# shellcheck shell=bash
+# Download yolov8 models when DOWNLOAD_YOLOV8=1 environment variable is set
+
+set -o errexit -o nounset -o pipefail
+
+MODEL_CACHE_DIR=${MODEL_CACHE_DIR:-"/config/model_cache"}
+DOWNLOAD_YOLOV8=${DOWNLOAD_YOLOV8:-"0"}
+YOLOV8_DIR="$MODEL_CACHE_DIR/yolov8"
+YOLOV8_URL=https://github.com/harakas/models/releases/download/yolov8.1-1.1/yolov8.small.models.tar.gz
+YOLOV8_DIGEST=304186b299560fbacc28eac9b9ea02cc2289fe30eb2c0df30109a2529423695c
+
+if [ "$DOWNLOAD_YOLOV8" = "1" ]; then
+ echo "download-models: DOWNLOAD_YOLOV8=${DOWNLOAD_YOLOV8}, running download"
+ if ! test -f "${YOLOV8_DIR}/model.fetched"; then
+ mkdir -p $YOLOV8_DIR
+ TMP_FILE="${YOLOV8_DIR}/download.tar.gz"
+ curl --no-progress-meter -L --max-filesize 500M --insecure --output $TMP_FILE "${YOLOV8_URL}"
+ digest=$(sha256sum $TMP_FILE | awk '{print $1}')
+ if [ "$digest" = "$YOLOV8_DIGEST" ]; then
+ echo "download-models: Extracting downloaded file"
+ cd $YOLOV8_DIR
+ tar zxf $TMP_FILE
+ rm $TMP_FILE
+ touch model.fetched
+ echo "download-models: Yolov8 download done, files placed into ${YOLOV8_DIR}"
+ else
+ echo "download-models: Downloaded file digest does not match: got $digest, expected $YOLOV8_DIGEST"
+ rm $TMP_FILE
+ fi
+ else
+ echo "download-models: ${YOLOV8_DIR}/model.fetched already present"
+ fi
+fi
+
diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/type b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/type
new file mode 100644
index 000000000..bdd22a185
--- /dev/null
+++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/type
@@ -0,0 +1 @@
+oneshot
diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/up b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/up
new file mode 100644
index 000000000..8daf1e9de
--- /dev/null
+++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/download-models/up
@@ -0,0 +1 @@
+/etc/s6-overlay/s6-rc.d/download-models/run
diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/dependencies.d/download-models b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/dependencies.d/download-models
new file mode 100644
index 000000000..e69de29bb
diff --git a/docker/main/rootfs/usr/local/go2rtc/create_config.py b/docker/main/rootfs/usr/local/go2rtc/create_config.py
index 51d75f0e0..0e2ae7648 100644
--- a/docker/main/rootfs/usr/local/go2rtc/create_config.py
+++ b/docker/main/rootfs/usr/local/go2rtc/create_config.py
@@ -109,9 +109,9 @@ if int(os.environ["LIBAVFORMAT_VERSION_MAJOR"]) < 59:
"rtsp": "-fflags nobuffer -flags low_delay -stimeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}"
}
elif go2rtc_config["ffmpeg"].get("rtsp") is None:
- go2rtc_config["ffmpeg"][
- "rtsp"
- ] = "-fflags nobuffer -flags low_delay -stimeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}"
+ go2rtc_config["ffmpeg"]["rtsp"] = (
+ "-fflags nobuffer -flags low_delay -stimeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}"
+ )
# add hardware acceleration presets for rockchip devices
# may be removed if frigate uses a go2rtc version that includes these presets
diff --git a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf
index 24c294725..c55a58562 100644
--- a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf
+++ b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf
@@ -10,6 +10,8 @@ events {
}
http {
+ map_hash_bucket_size 256;
+
include mime.types;
default_type application/octet-stream;
diff --git a/docker/rockchip/Dockerfile b/docker/rockchip/Dockerfile
index b27e4f223..65e712b71 100644
--- a/docker/rockchip/Dockerfile
+++ b/docker/rockchip/Dockerfile
@@ -9,7 +9,7 @@ COPY docker/rockchip/requirements-wheels-rk.txt /requirements-wheels-rk.txt
RUN sed -i "/https:\/\//d" /requirements-wheels.txt
RUN pip3 wheel --wheel-dir=/rk-wheels -c /requirements-wheels.txt -r /requirements-wheels-rk.txt
-FROM deps AS rk-deps
+FROM deps AS rk-frigate
ARG TARGETARCH
RUN --mount=type=bind,from=rk-wheels,source=/rk-wheels,target=/deps/rk-wheels \
@@ -28,5 +28,5 @@ ADD https://github.com/MarcA711/rknn-models/releases/download/v1.5.2-rk3588/yolo
RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffmpeg
RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffprobe
-ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.0-1/ffmpeg /usr/lib/btbn-ffmpeg/bin/
-ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.0-1/ffprobe /usr/lib/btbn-ffmpeg/bin/
+ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.1-1/ffmpeg /usr/lib/btbn-ffmpeg/bin/
+ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.1-1/ffprobe /usr/lib/btbn-ffmpeg/bin/
diff --git a/docker/rockchip/rk.hcl b/docker/rockchip/rk.hcl
index 513fefa25..9424b46e7 100644
--- a/docker/rockchip/rk.hcl
+++ b/docker/rockchip/rk.hcl
@@ -1,9 +1,3 @@
-target wget {
- dockerfile = "docker/main/Dockerfile"
- platforms = ["linux/arm64"]
- target = "wget"
-}
-
target wheels {
dockerfile = "docker/main/Dockerfile"
platforms = ["linux/arm64"]
@@ -25,7 +19,6 @@ target rootfs {
target rk {
dockerfile = "docker/rockchip/Dockerfile"
contexts = {
- wget = "target:wget",
wheels = "target:wheels",
deps = "target:deps",
rootfs = "target:rootfs"
diff --git a/docker/rocm/Dockerfile b/docker/rocm/Dockerfile
new file mode 100644
index 000000000..d13bcaead
--- /dev/null
+++ b/docker/rocm/Dockerfile
@@ -0,0 +1,106 @@
+# syntax=docker/dockerfile:1.4
+
+# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
+ARG DEBIAN_FRONTEND=noninteractive
+ARG ROCM=5.7.3
+ARG AMDGPU=gfx900
+ARG HSA_OVERRIDE_GFX_VERSION
+ARG HSA_OVERRIDE
+
+#######################################################################
+FROM ubuntu:focal as rocm
+
+ARG ROCM
+
+RUN apt-get update && apt-get -y upgrade
+RUN apt-get -y install gnupg wget
+
+RUN mkdir --parents --mode=0755 /etc/apt/keyrings
+
+RUN wget https://repo.radeon.com/rocm/rocm.gpg.key -O - | gpg --dearmor | tee /etc/apt/keyrings/rocm.gpg > /dev/null
+COPY docker/rocm/rocm.list /etc/apt/sources.list.d/
+COPY docker/rocm/rocm-pin-600 /etc/apt/preferences.d/
+
+RUN apt-get update
+
+RUN apt-get -y install --no-install-recommends migraphx
+RUN apt-get -y install --no-install-recommends migraphx-dev
+
+RUN mkdir -p /opt/rocm-dist/opt/rocm-$ROCM/lib
+RUN cd /opt/rocm-$ROCM/lib && cp -dpr libMIOpen*.so* libamd*.so* libhip*.so* libhsa*.so* libmigraphx*.so* librocm*.so* librocblas*.so* /opt/rocm-dist/opt/rocm-$ROCM/lib/
+RUN cd /opt/rocm-dist/opt/ && ln -s rocm-$ROCM rocm
+
+RUN mkdir -p /opt/rocm-dist/etc/ld.so.conf.d/
+RUN echo /opt/rocm/lib|tee /opt/rocm-dist/etc/ld.so.conf.d/rocm.conf
+
+#######################################################################
+FROM --platform=linux/amd64 debian:11 as debian-base
+
+RUN apt-get update && apt-get -y upgrade
+RUN apt-get -y install --no-install-recommends libelf1 libdrm2 libdrm-amdgpu1 libnuma1 kmod
+
+RUN apt-get -y install python3
+
+#######################################################################
+# ROCm does not come with migraphx wrappers for python 3.9, so we build it here
+FROM debian-base as debian-build
+
+ARG ROCM
+
+COPY --from=rocm /opt/rocm-$ROCM /opt/rocm-$ROCM
+RUN ln -s /opt/rocm-$ROCM /opt/rocm
+
+RUN apt-get -y install g++ cmake
+RUN apt-get -y install python3-pybind11 python3.9-distutils python3-dev
+
+WORKDIR /opt/build
+
+COPY docker/rocm/migraphx .
+
+RUN mkdir build && cd build && cmake .. && make install
+
+#######################################################################
+FROM deps AS deps-prelim
+
+# need this to install libnuma1
+RUN apt-get update
+# no ugprade?!?!
+RUN apt-get -y install libnuma1
+
+WORKDIR /opt/frigate/
+COPY --from=rootfs / /
+COPY docker/rocm/rootfs/ /
+
+#######################################################################
+FROM scratch AS rocm-dist
+
+ARG ROCM
+ARG AMDGPU
+
+COPY --from=rocm /opt/rocm-$ROCM/bin/rocminfo /opt/rocm-$ROCM/bin/migraphx-driver /opt/rocm-$ROCM/bin/
+COPY --from=rocm /opt/rocm-$ROCM/share/miopen/db/*$AMDGPU* /opt/rocm-$ROCM/share/miopen/db/
+COPY --from=rocm /opt/rocm-$ROCM/lib/rocblas/library/*$AMDGPU* /opt/rocm-$ROCM/lib/rocblas/library/
+COPY --from=rocm /opt/rocm-dist/ /
+COPY --from=debian-build /opt/rocm/lib/migraphx.cpython-39-x86_64-linux-gnu.so /opt/rocm-$ROCM/lib/
+
+#######################################################################
+FROM deps-prelim AS rocm-prelim-hsa-override0
+
+ENV HSA_ENABLE_SDMA=0
+
+COPY --from=rocm-dist / /
+
+RUN ldconfig
+
+#######################################################################
+FROM rocm-prelim-hsa-override0 as rocm-prelim-hsa-override1
+
+ARG HSA_OVERRIDE_GFX_VERSION
+ENV HSA_OVERRIDE_GFX_VERSION=$HSA_OVERRIDE_GFX_VERSION
+
+#######################################################################
+FROM rocm-prelim-hsa-override$HSA_OVERRIDE as rocm-deps
+
+# Request yolov8 download at startup
+ENV DOWNLOAD_YOLOV8=1
+
diff --git a/docker/rocm/migraphx/CMakeLists.txt b/docker/rocm/migraphx/CMakeLists.txt
new file mode 100644
index 000000000..271dd094b
--- /dev/null
+++ b/docker/rocm/migraphx/CMakeLists.txt
@@ -0,0 +1,26 @@
+
+cmake_minimum_required(VERSION 3.1)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release)
+endif()
+
+SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+project(migraphx_py)
+
+include_directories(/opt/rocm/include)
+
+find_package(pybind11 REQUIRED)
+pybind11_add_module(migraphx migraphx_py.cpp)
+
+target_link_libraries(migraphx PRIVATE /opt/rocm/lib/libmigraphx.so /opt/rocm/lib/libmigraphx_tf.so /opt/rocm/lib/libmigraphx_onnx.so)
+
+install(TARGETS migraphx
+ COMPONENT python
+ LIBRARY DESTINATION /opt/rocm/lib
+)
diff --git a/docker/rocm/migraphx/migraphx_py.cpp b/docker/rocm/migraphx/migraphx_py.cpp
new file mode 100644
index 000000000..894c9d186
--- /dev/null
+++ b/docker/rocm/migraphx/migraphx_py.cpp
@@ -0,0 +1,582 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2022 Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_GPU
+#include
+#endif
+
+using half = half_float::half;
+namespace py = pybind11;
+
+#ifdef __clang__
+#define MIGRAPHX_PUSH_UNUSED_WARNING \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wused-but-marked-unused\"")
+#define MIGRAPHX_POP_WARNING _Pragma("clang diagnostic pop")
+#else
+#define MIGRAPHX_PUSH_UNUSED_WARNING
+#define MIGRAPHX_POP_WARNING
+#endif
+#define MIGRAPHX_PYBIND11_MODULE(...) \
+ MIGRAPHX_PUSH_UNUSED_WARNING \
+ PYBIND11_MODULE(__VA_ARGS__) \
+ MIGRAPHX_POP_WARNING
+
+#define MIGRAPHX_PYTHON_GENERATE_SHAPE_ENUM(x, t) .value(#x, migraphx::shape::type_t::x)
+namespace migraphx {
+
+migraphx::value to_value(py::kwargs kwargs);
+migraphx::value to_value(py::list lst);
+
+template
+void visit_py(T x, F f)
+{
+ if(py::isinstance(x))
+ {
+ f(to_value(x.template cast()));
+ }
+ else if(py::isinstance(x))
+ {
+ f(to_value(x.template cast()));
+ }
+ else if(py::isinstance(x))
+ {
+ f(x.template cast());
+ }
+ else if(py::isinstance(x) or py::hasattr(x, "__index__"))
+ {
+ f(x.template cast());
+ }
+ else if(py::isinstance(x))
+ {
+ f(x.template cast());
+ }
+ else if(py::isinstance(x))
+ {
+ f(x.template cast());
+ }
+ else if(py::isinstance(x))
+ {
+ f(migraphx::to_value(x.template cast()));
+ }
+ else
+ {
+ MIGRAPHX_THROW("VISIT_PY: Unsupported data type!");
+ }
+}
+
+migraphx::value to_value(py::list lst)
+{
+ migraphx::value v = migraphx::value::array{};
+ for(auto val : lst)
+ {
+ visit_py(val, [&](auto py_val) { v.push_back(py_val); });
+ }
+
+ return v;
+}
+
+migraphx::value to_value(py::kwargs kwargs)
+{
+ migraphx::value v = migraphx::value::object{};
+
+ for(auto arg : kwargs)
+ {
+ auto&& key = py::str(arg.first);
+ auto&& val = arg.second;
+ visit_py(val, [&](auto py_val) { v[key] = py_val; });
+ }
+ return v;
+}
+} // namespace migraphx
+
+namespace pybind11 {
+namespace detail {
+
+template <>
+struct npy_format_descriptor
+{
+ static std::string format()
+ {
+ // following: https://docs.python.org/3/library/struct.html#format-characters
+ return "e";
+ }
+ static constexpr auto name() { return _("half"); }
+};
+
+} // namespace detail
+} // namespace pybind11
+
+template
+void visit_type(const migraphx::shape& s, F f)
+{
+ s.visit_type(f);
+}
+
+template
+void visit(const migraphx::raw_data& x, F f)
+{
+ x.visit(f);
+}
+
+template
+void visit_types(F f)
+{
+ migraphx::shape::visit_types(f);
+}
+
+template
+py::buffer_info to_buffer_info(T& x)
+{
+ migraphx::shape s = x.get_shape();
+ assert(s.type() != migraphx::shape::tuple_type);
+ if(s.dynamic())
+ MIGRAPHX_THROW("MIGRAPHX PYTHON: dynamic shape argument passed to to_buffer_info");
+ auto strides = s.strides();
+ std::transform(
+ strides.begin(), strides.end(), strides.begin(), [&](auto i) { return i * s.type_size(); });
+ py::buffer_info b;
+ visit_type(s, [&](auto as) {
+ // migraphx use int8_t data to store bool type, we need to
+ // explicitly specify the data type as bool for python
+ if(s.type() == migraphx::shape::bool_type)
+ {
+ b = py::buffer_info(x.data(),
+ as.size(),
+ py::format_descriptor::format(),
+ s.ndim(),
+ s.lens(),
+ strides);
+ }
+ else
+ {
+ b = py::buffer_info(x.data(),
+ as.size(),
+ py::format_descriptor::format(),
+ s.ndim(),
+ s.lens(),
+ strides);
+ }
+ });
+ return b;
+}
+
+migraphx::shape to_shape(const py::buffer_info& info)
+{
+ migraphx::shape::type_t t;
+ std::size_t n = 0;
+ visit_types([&](auto as) {
+ if(info.format == py::format_descriptor::format() or
+ (info.format == "l" and py::format_descriptor::format() == "q") or
+ (info.format == "L" and py::format_descriptor::format() == "Q"))
+ {
+ t = as.type_enum();
+ n = sizeof(as());
+ }
+ else if(info.format == "?" and py::format_descriptor::format() == "b")
+ {
+ t = migraphx::shape::bool_type;
+ n = sizeof(bool);
+ }
+ });
+
+ if(n == 0)
+ {
+ MIGRAPHX_THROW("MIGRAPHX PYTHON: Unsupported data type " + info.format);
+ }
+
+ auto strides = info.strides;
+ std::transform(strides.begin(), strides.end(), strides.begin(), [&](auto i) -> std::size_t {
+ return n > 0 ? i / n : 0;
+ });
+
+ // scalar support
+ if(info.shape.empty())
+ {
+ return migraphx::shape{t};
+ }
+ else
+ {
+ return migraphx::shape{t, info.shape, strides};
+ }
+}
+
+MIGRAPHX_PYBIND11_MODULE(migraphx, m)
+{
+ py::class_ shape_cls(m, "shape");
+ shape_cls
+ .def(py::init([](py::kwargs kwargs) {
+ auto v = migraphx::to_value(kwargs);
+ auto t = migraphx::shape::parse_type(v.get("type", "float"));
+ if(v.contains("dyn_dims"))
+ {
+ auto dyn_dims =
+ migraphx::from_value>(
+ v.at("dyn_dims"));
+ return migraphx::shape(t, dyn_dims);
+ }
+ auto lens = v.get("lens", {1});
+ if(v.contains("strides"))
+ return migraphx::shape(t, lens, v.at("strides").to_vector());
+ else
+ return migraphx::shape(t, lens);
+ }))
+ .def("type", &migraphx::shape::type)
+ .def("lens", &migraphx::shape::lens)
+ .def("strides", &migraphx::shape::strides)
+ .def("ndim", &migraphx::shape::ndim)
+ .def("elements", &migraphx::shape::elements)
+ .def("bytes", &migraphx::shape::bytes)
+ .def("type_string", &migraphx::shape::type_string)
+ .def("type_size", &migraphx::shape::type_size)
+ .def("dyn_dims", &migraphx::shape::dyn_dims)
+ .def("packed", &migraphx::shape::packed)
+ .def("transposed", &migraphx::shape::transposed)
+ .def("broadcasted", &migraphx::shape::broadcasted)
+ .def("standard", &migraphx::shape::standard)
+ .def("scalar", &migraphx::shape::scalar)
+ .def("dynamic", &migraphx::shape::dynamic)
+ .def("__eq__", std::equal_to{})
+ .def("__ne__", std::not_equal_to{})
+ .def("__repr__", [](const migraphx::shape& s) { return migraphx::to_string(s); });
+
+ py::enum_(shape_cls, "type_t")
+ MIGRAPHX_SHAPE_VISIT_TYPES(MIGRAPHX_PYTHON_GENERATE_SHAPE_ENUM);
+
+ py::class_(shape_cls, "dynamic_dimension")
+ .def(py::init<>())
+ .def(py::init())
+ .def(py::init>())
+ .def_readwrite("min", &migraphx::shape::dynamic_dimension::min)
+ .def_readwrite("max", &migraphx::shape::dynamic_dimension::max)
+ .def_readwrite("optimals", &migraphx::shape::dynamic_dimension::optimals)
+ .def("is_fixed", &migraphx::shape::dynamic_dimension::is_fixed);
+
+ py::class_(m, "argument", py::buffer_protocol())
+ .def_buffer([](migraphx::argument& x) -> py::buffer_info { return to_buffer_info(x); })
+ .def(py::init([](py::buffer b) {
+ py::buffer_info info = b.request();
+ return migraphx::argument(to_shape(info), info.ptr);
+ }))
+ .def("get_shape", &migraphx::argument::get_shape)
+ .def("data_ptr",
+ [](migraphx::argument& x) { return reinterpret_cast(x.data()); })
+ .def("tolist",
+ [](migraphx::argument& x) {
+ py::list l{x.get_shape().elements()};
+ visit(x, [&](auto data) { l = py::cast(data.to_vector()); });
+ return l;
+ })
+ .def("__eq__", std::equal_to{})
+ .def("__ne__", std::not_equal_to{})
+ .def("__repr__", [](const migraphx::argument& x) { return migraphx::to_string(x); });
+
+ py::class_(m, "target");
+
+ py::class_(m, "instruction_ref")
+ .def("shape", [](migraphx::instruction_ref i) { return i->get_shape(); })
+ .def("op", [](migraphx::instruction_ref i) { return i->get_operator(); });
+
+ py::class_>(m, "module")
+ .def("print", [](const migraphx::module& mm) { std::cout << mm << std::endl; })
+ .def(
+ "add_instruction",
+ [](migraphx::module& mm,
+ const migraphx::operation& op,
+ std::vector& args,
+ std::vector& mod_args) {
+ return mm.add_instruction(op, args, mod_args);
+ },
+ py::arg("op"),
+ py::arg("args"),
+ py::arg("mod_args") = std::vector{})
+ .def(
+ "add_literal",
+ [](migraphx::module& mm, py::buffer data) {
+ py::buffer_info info = data.request();
+ auto literal_shape = to_shape(info);
+ return mm.add_literal(literal_shape, reinterpret_cast(info.ptr));
+ },
+ py::arg("data"))
+ .def(
+ "add_parameter",
+ [](migraphx::module& mm, const std::string& name, const migraphx::shape shape) {
+ return mm.add_parameter(name, shape);
+ },
+ py::arg("name"),
+ py::arg("shape"))
+ .def(
+ "add_return",
+ [](migraphx::module& mm, std::vector& args) {
+ return mm.add_return(args);
+ },
+ py::arg("args"))
+ .def("__repr__", [](const migraphx::module& mm) { return migraphx::to_string(mm); });
+
+ py::class_(m, "program")
+ .def(py::init([]() { return migraphx::program(); }))
+ .def("get_parameter_names", &migraphx::program::get_parameter_names)
+ .def("get_parameter_shapes", &migraphx::program::get_parameter_shapes)
+ .def("get_output_shapes", &migraphx::program::get_output_shapes)
+ .def("is_compiled", &migraphx::program::is_compiled)
+ .def(
+ "compile",
+ [](migraphx::program& p,
+ const migraphx::target& t,
+ bool offload_copy,
+ bool fast_math,
+ bool exhaustive_tune) {
+ migraphx::compile_options options;
+ options.offload_copy = offload_copy;
+ options.fast_math = fast_math;
+ options.exhaustive_tune = exhaustive_tune;
+ p.compile(t, options);
+ },
+ py::arg("t"),
+ py::arg("offload_copy") = true,
+ py::arg("fast_math") = true,
+ py::arg("exhaustive_tune") = false)
+ .def("get_main_module", [](const migraphx::program& p) { return p.get_main_module(); })
+ .def(
+ "create_module",
+ [](migraphx::program& p, const std::string& name) { return p.create_module(name); },
+ py::arg("name"))
+ .def("run",
+ [](migraphx::program& p, py::dict params) {
+ migraphx::parameter_map pm;
+ for(auto x : params)
+ {
+ std::string key = x.first.cast();
+ py::buffer b = x.second.cast();
+ py::buffer_info info = b.request();
+ pm[key] = migraphx::argument(to_shape(info), info.ptr);
+ }
+ return p.eval(pm);
+ })
+ .def("run_async",
+ [](migraphx::program& p,
+ py::dict params,
+ std::uintptr_t stream,
+ std::string stream_name) {
+ migraphx::parameter_map pm;
+ for(auto x : params)
+ {
+ std::string key = x.first.cast();
+ py::buffer b = x.second.cast();
+ py::buffer_info info = b.request();
+ pm[key] = migraphx::argument(to_shape(info), info.ptr);
+ }
+ migraphx::execution_environment exec_env{
+ migraphx::any_ptr(reinterpret_cast(stream), stream_name), true};
+ return p.eval(pm, exec_env);
+ })
+ .def("sort", &migraphx::program::sort)
+ .def("print", [](const migraphx::program& p) { std::cout << p << std::endl; })
+ .def("__eq__", std::equal_to{})
+ .def("__ne__", std::not_equal_to{})
+ .def("__repr__", [](const migraphx::program& p) { return migraphx::to_string(p); });
+
+ py::class_ op(m, "op");
+ op.def(py::init([](const std::string& name, py::kwargs kwargs) {
+ migraphx::value v = migraphx::value::object{};
+ if(kwargs)
+ {
+ v = migraphx::to_value(kwargs);
+ }
+ return migraphx::make_op(name, v);
+ }))
+ .def("name", &migraphx::operation::name);
+
+ py::enum_(op, "pooling_mode")
+ .value("average", migraphx::op::pooling_mode::average)
+ .value("max", migraphx::op::pooling_mode::max)
+ .value("lpnorm", migraphx::op::pooling_mode::lpnorm);
+
+ py::enum_(op, "rnn_direction")
+ .value("forward", migraphx::op::rnn_direction::forward)
+ .value("reverse", migraphx::op::rnn_direction::reverse)
+ .value("bidirectional", migraphx::op::rnn_direction::bidirectional);
+
+ m.def(
+ "argument_from_pointer",
+ [](const migraphx::shape shape, const int64_t address) {
+ return migraphx::argument(shape, reinterpret_cast(address));
+ },
+ py::arg("shape"),
+ py::arg("address"));
+
+ m.def(
+ "parse_tf",
+ [](const std::string& filename,
+ bool is_nhwc,
+ unsigned int batch_size,
+ std::unordered_map> map_input_dims,
+ std::vector output_names) {
+ return migraphx::parse_tf(
+ filename, migraphx::tf_options{is_nhwc, batch_size, map_input_dims, output_names});
+ },
+ "Parse tf protobuf (default format is nhwc)",
+ py::arg("filename"),
+ py::arg("is_nhwc") = true,
+ py::arg("batch_size") = 1,
+ py::arg("map_input_dims") = std::unordered_map>(),
+ py::arg("output_names") = std::vector());
+
+ m.def(
+ "parse_onnx",
+ [](const std::string& filename,
+ unsigned int default_dim_value,
+ migraphx::shape::dynamic_dimension default_dyn_dim_value,
+ std::unordered_map> map_input_dims,
+ std::unordered_map>
+ map_dyn_input_dims,
+ bool skip_unknown_operators,
+ bool print_program_on_error,
+ int64_t max_loop_iterations) {
+ migraphx::onnx_options options;
+ options.default_dim_value = default_dim_value;
+ options.default_dyn_dim_value = default_dyn_dim_value;
+ options.map_input_dims = map_input_dims;
+ options.map_dyn_input_dims = map_dyn_input_dims;
+ options.skip_unknown_operators = skip_unknown_operators;
+ options.print_program_on_error = print_program_on_error;
+ options.max_loop_iterations = max_loop_iterations;
+ return migraphx::parse_onnx(filename, options);
+ },
+ "Parse onnx file",
+ py::arg("filename"),
+ py::arg("default_dim_value") = 0,
+ py::arg("default_dyn_dim_value") = migraphx::shape::dynamic_dimension{1, 1},
+ py::arg("map_input_dims") = std::unordered_map>(),
+ py::arg("map_dyn_input_dims") =
+ std::unordered_map>(),
+ py::arg("skip_unknown_operators") = false,
+ py::arg("print_program_on_error") = false,
+ py::arg("max_loop_iterations") = 10);
+
+ m.def(
+ "parse_onnx_buffer",
+ [](const std::string& onnx_buffer,
+ unsigned int default_dim_value,
+ migraphx::shape::dynamic_dimension default_dyn_dim_value,
+ std::unordered_map> map_input_dims,
+ std::unordered_map>
+ map_dyn_input_dims,
+ bool skip_unknown_operators,
+ bool print_program_on_error) {
+ migraphx::onnx_options options;
+ options.default_dim_value = default_dim_value;
+ options.default_dyn_dim_value = default_dyn_dim_value;
+ options.map_input_dims = map_input_dims;
+ options.map_dyn_input_dims = map_dyn_input_dims;
+ options.skip_unknown_operators = skip_unknown_operators;
+ options.print_program_on_error = print_program_on_error;
+ return migraphx::parse_onnx_buffer(onnx_buffer, options);
+ },
+ "Parse onnx file",
+ py::arg("filename"),
+ py::arg("default_dim_value") = 0,
+ py::arg("default_dyn_dim_value") = migraphx::shape::dynamic_dimension{1, 1},
+ py::arg("map_input_dims") = std::unordered_map>(),
+ py::arg("map_dyn_input_dims") =
+ std::unordered_map>(),
+ py::arg("skip_unknown_operators") = false,
+ py::arg("print_program_on_error") = false);
+
+ m.def(
+ "load",
+ [](const std::string& name, const std::string& format) {
+ migraphx::file_options options;
+ options.format = format;
+ return migraphx::load(name, options);
+ },
+ "Load MIGraphX program",
+ py::arg("filename"),
+ py::arg("format") = "msgpack");
+
+ m.def(
+ "save",
+ [](const migraphx::program& p, const std::string& name, const std::string& format) {
+ migraphx::file_options options;
+ options.format = format;
+ return migraphx::save(p, name, options);
+ },
+ "Save MIGraphX program",
+ py::arg("p"),
+ py::arg("filename"),
+ py::arg("format") = "msgpack");
+
+ m.def("get_target", &migraphx::make_target);
+ m.def("create_argument", [](const migraphx::shape& s, const std::vector& values) {
+ if(values.size() != s.elements())
+ MIGRAPHX_THROW("Values and shape elements do not match");
+ migraphx::argument a{s};
+ a.fill(values.begin(), values.end());
+ return a;
+ });
+ m.def("generate_argument", &migraphx::generate_argument, py::arg("s"), py::arg("seed") = 0);
+ m.def("fill_argument", &migraphx::fill_argument, py::arg("s"), py::arg("value"));
+ m.def("quantize_fp16",
+ &migraphx::quantize_fp16,
+ py::arg("prog"),
+ py::arg("ins_names") = std::vector{"all"});
+ m.def("quantize_int8",
+ &migraphx::quantize_int8,
+ py::arg("prog"),
+ py::arg("t"),
+ py::arg("calibration") = std::vector{},
+ py::arg("ins_names") = std::vector{"dot", "convolution"});
+
+#ifdef HAVE_GPU
+ m.def("allocate_gpu", &migraphx::gpu::allocate_gpu, py::arg("s"), py::arg("host") = false);
+ m.def("to_gpu", &migraphx::gpu::to_gpu, py::arg("arg"), py::arg("host") = false);
+ m.def("from_gpu", &migraphx::gpu::from_gpu);
+ m.def("gpu_sync", [] { migraphx::gpu::gpu_sync(); });
+#endif
+
+#ifdef VERSION_INFO
+ m.attr("__version__") = VERSION_INFO;
+#else
+ m.attr("__version__") = "dev";
+#endif
+}
diff --git a/docker/rocm/rocm-pin-600 b/docker/rocm/rocm-pin-600
new file mode 100644
index 000000000..88348a5c1
--- /dev/null
+++ b/docker/rocm/rocm-pin-600
@@ -0,0 +1,3 @@
+Package: *
+Pin: release o=repo.radeon.com
+Pin-Priority: 600
diff --git a/docker/rocm/rocm.hcl b/docker/rocm/rocm.hcl
new file mode 100644
index 000000000..33a2d2323
--- /dev/null
+++ b/docker/rocm/rocm.hcl
@@ -0,0 +1,38 @@
+variable "AMDGPU" {
+ default = "gfx900"
+}
+variable "ROCM" {
+ default = "5.7.3"
+}
+variable "HSA_OVERRIDE_GFX_VERSION" {
+ default = ""
+}
+variable "HSA_OVERRIDE" {
+ default = "1"
+}
+target deps {
+ dockerfile = "docker/main/Dockerfile"
+ platforms = ["linux/amd64"]
+ target = "deps"
+}
+
+target rootfs {
+ dockerfile = "docker/main/Dockerfile"
+ platforms = ["linux/amd64"]
+ target = "rootfs"
+}
+
+target rocm {
+ dockerfile = "docker/rocm/Dockerfile"
+ contexts = {
+ deps = "target:deps",
+ rootfs = "target:rootfs"
+ }
+ platforms = ["linux/amd64"]
+ args = {
+ AMDGPU = AMDGPU,
+ ROCM = ROCM,
+ HSA_OVERRIDE_GFX_VERSION = HSA_OVERRIDE_GFX_VERSION,
+ HSA_OVERRIDE = HSA_OVERRIDE
+ }
+}
diff --git a/docker/rocm/rocm.list b/docker/rocm/rocm.list
new file mode 100644
index 000000000..0915b4094
--- /dev/null
+++ b/docker/rocm/rocm.list
@@ -0,0 +1 @@
+deb [arch=amd64 signed-by=/etc/apt/keyrings/rocm.gpg] https://repo.radeon.com/rocm/apt/5.7.3 focal main
diff --git a/docker/rocm/rocm.mk b/docker/rocm/rocm.mk
new file mode 100644
index 000000000..2d3d034ee
--- /dev/null
+++ b/docker/rocm/rocm.mk
@@ -0,0 +1,17 @@
+BOARDS += rocm
+
+# AMD/ROCm is chunky so we build couple of smaller images for specific chipsets
+ROCM_CHIPSETS:=gfx900:9.0.0 gfx1030:10.3.0 gfx1100:11.0.0
+
+local-rocm: version
+ $(foreach chipset,$(ROCM_CHIPSETS),AMDGPU=$(word 1,$(subst :, ,$(chipset))) HSA_OVERRIDE_GFX_VERSION=$(word 2,$(subst :, ,$(chipset))) HSA_OVERRIDE=1 docker buildx bake --load --file=docker/rocm/rocm.hcl --set rocm.tags=frigate:latest-rocm-$(word 1,$(subst :, ,$(chipset))) rocm;)
+ unset HSA_OVERRIDE_GFX_VERSION && HSA_OVERRIDE=0 AMDGPU=gfx docker buildx bake --load --file=docker/rocm/rocm.hcl --set rocm.tags=frigate:latest-rocm rocm
+
+build-rocm: version
+ $(foreach chipset,$(ROCM_CHIPSETS),AMDGPU=$(word 1,$(subst :, ,$(chipset))) HSA_OVERRIDE_GFX_VERSION=$(word 2,$(subst :, ,$(chipset))) HSA_OVERRIDE=1 docker buildx bake --file=docker/rocm/rocm.hcl --set rocm.tags=$(IMAGE_REPO):${GITHUB_REF_NAME}-$(COMMIT_HASH)-rocm-$(chipset) rocm;)
+ unset HSA_OVERRIDE_GFX_VERSION && HSA_OVERRIDE=0 AMDGPU=gfx docker buildx bake --file=docker/rocm/rocm.hcl --set rocm.tags=$(IMAGE_REPO):${GITHUB_REF_NAME}-$(COMMIT_HASH)-rocm rocm
+
+push-rocm: build-rocm
+ $(foreach chipset,$(ROCM_CHIPSETS),AMDGPU=$(word 1,$(subst :, ,$(chipset))) HSA_OVERRIDE_GFX_VERSION=$(word 2,$(subst :, ,$(chipset))) HSA_OVERRIDE=1 docker buildx bake --push --file=docker/rocm/rocm.hcl --set rocm.tags=$(IMAGE_REPO):${GITHUB_REF_NAME}-$(COMMIT_HASH)-rocm-$(chipset) rocm;)
+ unset HSA_OVERRIDE_GFX_VERSION && HSA_OVERRIDE=0 AMDGPU=gfx docker buildx bake --push --file=docker/rocm/rocm.hcl --set rocm.tags=$(IMAGE_REPO):${GITHUB_REF_NAME}-$(COMMIT_HASH)-rocm rocm
+
diff --git a/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/dependencies.d/download-models b/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/dependencies.d/download-models
new file mode 100644
index 000000000..e69de29bb
diff --git a/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/run b/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/run
new file mode 100755
index 000000000..f7b084ad7
--- /dev/null
+++ b/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/run
@@ -0,0 +1,20 @@
+#!/command/with-contenv bash
+# shellcheck shell=bash
+# Compile YoloV8 ONNX files into ROCm MIGraphX files
+
+OVERRIDE=$(cd /opt/frigate && python3 -c 'import frigate.detectors.plugins.rocm as rocm; print(rocm.auto_override_gfx_version())')
+
+if ! test -z "$OVERRIDE"; then
+ echo "Using HSA_OVERRIDE_GFX_VERSION=${OVERRIDE}"
+ export HSA_OVERRIDE_GFX_VERSION=$OVERRIDE
+fi
+
+for onnx in /config/model_cache/yolov8/*.onnx
+do
+ mxr="${onnx%.onnx}.mxr"
+ if ! test -f $mxr; then
+ echo "processing $onnx into $mxr"
+ /opt/rocm/bin/migraphx-driver compile $onnx --optimize --gpu --enable-offload-copy --binary -o $mxr
+ fi
+done
+
diff --git a/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/type b/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/type
new file mode 100644
index 000000000..bdd22a185
--- /dev/null
+++ b/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/type
@@ -0,0 +1 @@
+oneshot
diff --git a/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/up b/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/up
new file mode 100644
index 000000000..8fdcef491
--- /dev/null
+++ b/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/compile-rocm-models/up
@@ -0,0 +1 @@
+/etc/s6-overlay/s6-rc.d/compile-rocm-models/run
diff --git a/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/frigate/dependencies.d/compile-rocm-models b/docker/rocm/rootfs/etc/s6-overlay/s6-rc.d/frigate/dependencies.d/compile-rocm-models
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/docs/configuration/birdseye.md b/docs/docs/configuration/birdseye.md
index 6471bf4e3..8edf50583 100644
--- a/docs/docs/configuration/birdseye.md
+++ b/docs/docs/configuration/birdseye.md
@@ -1,6 +1,8 @@
# Birdseye
-Birdseye allows a heads-up view of your cameras to see what is going on around your property / space without having to watch all cameras that may have nothing happening. Birdseye allows specific modes that intelligently show and disappear based on what you care about.
+Birdseye allows a heads-up view of your cameras to see what is going on around your property / space without having to watch all cameras that may have nothing happening. Birdseye allows specific modes that intelligently show and disappear based on what you care about.
+
+## Birdseye Behavior
### Birdseye Modes
@@ -34,6 +36,29 @@ cameras:
enabled: False
```
+### Birdseye Inactivity
+
+By default birdseye shows all cameras that have had the configured activity in the last 30 seconds, this can be configured:
+
+```yaml
+birdseye:
+ enabled: True
+ inactivity_threshold: 15
+```
+
+## Birdseye Layout
+
+### Birdseye Dimensions
+
+The resolution and aspect ratio of birdseye can be configured. Resolution will increase the quality but does not affect the layout. Changing the aspect ratio of birdseye does affect how cameras are laid out.
+
+```yaml
+birdseye:
+ enabled: True
+ width: 1280
+ height: 720
+```
+
### Sorting cameras in the Birdseye view
It is possible to override the order of cameras that are being shown in the Birdseye view.
@@ -55,3 +80,27 @@ cameras:
```
*Note*: Cameras are sorted by default using their name to ensure a constant view inside Birdseye.
+
+### Birdseye Cameras
+
+It is possible to limit the number of cameras shown on birdseye at one time. When this is enabled, birdseye will show the cameras with most recent activity. There is a cooldown to ensure that cameras do not switch too frequently.
+
+For example, this can be configured to only show the most recently active camera.
+
+```yaml
+birdseye:
+ enabled: True
+ layout:
+ max_cameras: 1
+```
+
+### Birdseye Scaling
+
+By default birdseye tries to fit 2 cameras in each row and then double in size until a suitable layout is found. The scaling can be configured with a value between 1.0 and 5.0 depending on use case.
+
+```yaml
+birdseye:
+ enabled: True
+ layout:
+ scaling_factor: 3.0
+```
diff --git a/docs/docs/configuration/camera_specific.md b/docs/docs/configuration/camera_specific.md
index 9e2213d5f..8440c6fe5 100644
--- a/docs/docs/configuration/camera_specific.md
+++ b/docs/docs/configuration/camera_specific.md
@@ -101,7 +101,7 @@ If available, recommended settings are:
According to [this discussion](https://github.com/blakeblackshear/frigate/issues/3235#issuecomment-1135876973), the http video streams seem to be the most reliable for Reolink.
-Cameras connected via a Reolink NVR can be connected with the http stream, use `channel[0..15]` in the stream url for the additional channels.
+Cameras connected via a Reolink NVR can be connected with the http stream, use `channel[0..15]` in the stream url for the additional channels.
The setup of main stream can be also done via RTSP, but isn't always reliable on all hardware versions. The example configuration is working with the oldest HW version RLN16-410 device with multiple types of cameras.
:::caution
diff --git a/docs/docs/configuration/hardware_acceleration.md b/docs/docs/configuration/hardware_acceleration.md
index 4b3444d30..72a1634ac 100644
--- a/docs/docs/configuration/hardware_acceleration.md
+++ b/docs/docs/configuration/hardware_acceleration.md
@@ -13,8 +13,8 @@ Depending on your system, these parameters may not be compatible. More informati
## Raspberry Pi 3/4
-Ensure you increase the allocated RAM for your GPU to at least 128 (raspi-config > Performance Options > GPU Memory).
-**NOTICE**: If you are using the addon, you may need to turn off `Protection mode` for hardware acceleration.
+Ensure you increase the allocated RAM for your GPU to at least 128 (`raspi-config` > Performance Options > GPU Memory).
+If you are using the HA addon, you may need to use the full access variant and turn off `Protection mode` for hardware acceleration.
```yaml
# if you want to decode a h264 stream
@@ -28,16 +28,39 @@ ffmpeg:
:::note
-If running Frigate in docker, you either need to run in priviliged mode or be sure to map the /dev/video1x devices to Frigate
+If running Frigate in Docker, you either need to run in privileged mode or
+map the `/dev/video*` devices to Frigate. With Docker compose add:
```yaml
-docker run -d \
---name frigate \
-...
---device /dev/video10 \
-ghcr.io/blakeblackshear/frigate:stable
+services:
+ frigate:
+ ...
+ devices:
+ - /dev/video11:/dev/video11
```
+Or with `docker run`:
+
+```bash
+docker run -d \
+ --name frigate \
+ ...
+ --device /dev/video11 \
+ ghcr.io/blakeblackshear/frigate:stable
+```
+
+`/dev/video11` is the correct device (on Raspberry Pi 4B). You can check
+by running the following and looking for `H264`:
+
+```bash
+for d in /dev/video*; do
+ echo -e "---\n$d"
+ v4l2-ctl --list-formats-ext -d $d
+done
+```
+
+Or map in all the `/dev/video*` devices.
+
:::
## Intel-based CPUs
diff --git a/docs/docs/configuration/index.md b/docs/docs/configuration/index.md
index 53993af67..dda399444 100644
--- a/docs/docs/configuration/index.md
+++ b/docs/docs/configuration/index.md
@@ -25,7 +25,7 @@ cameras:
## VSCode Configuration Schema
-VSCode (and VSCode addon) supports the JSON schemas which will automatically validate the config. This can be added by adding `# yaml-language-server: $schema=http://frigate_host:5000/api/config/schema.json` to the top of the config file. `frigate_host` being the IP address of Frigate or `ccab4aaf-frigate` if running in the addon.
+VSCode supports JSON schemas for automatically validating configuration files. You can enable this feature by adding `# yaml-language-server: $schema=http://frigate_host:5000/api/config/schema.json` to the beginning of the configuration file. Replace `frigate_host` with the IP address or hostname of your Frigate server. If you're using both VSCode and Frigate as an add-on, you should use `ccab4aaf-frigate` instead. Make sure to expose port `5000` for the Web Interface when accessing the config from VSCode on another machine.
## Environment Variable Substitution
diff --git a/docs/docs/configuration/motion_detection.md b/docs/docs/configuration/motion_detection.md
index f3d1d7692..4981dbbb5 100644
--- a/docs/docs/configuration/motion_detection.md
+++ b/docs/docs/configuration/motion_detection.md
@@ -17,7 +17,7 @@ Before tuning motion it is important to understand the goal. In an optimal confi
## Create Motion Masks
-First, mask areas with regular motion not caused by the objects you want to detect. The best way to find candidates for motion masks is by watching the debug stream with motion boxes enabled. Good use cases for motion masks are timestamps or tree limbs and large bushes that regularly move due to wind. When possible, avoid creating motion masks that would block motion detection for objects you want to track **even if they are in locations where you don't want events**. Motion masks should not be used to avoid detecting objects in specific areas. More details can be found [in the masks docs.](/configuration/masks.md).
+First, mask areas with regular motion not caused by the objects you want to detect. The best way to find candidates for motion masks is by watching the debug stream with motion boxes enabled. Good use cases for motion masks are timestamps or tree limbs and large bushes that regularly move due to wind. When possible, avoid creating motion masks that would block motion detection for objects you want to track **even if they are in locations where you don't want events**. Motion masks should not be used to avoid detecting objects in specific areas. More details can be found [in the masks docs.](/configuration/masks.md).
## Prepare For Testing
@@ -37,7 +37,7 @@ Remember that motion detection is just used to determine when object detection s
### Threshold
-The threshold value dictates how much of a change in a pixels luminance is required to be considered motion.
+The threshold value dictates how much of a change in a pixels luminance is required to be considered motion.
```yaml
# default threshold value
@@ -69,7 +69,7 @@ motion:
Once the threshold calculation is run, the pixels that have changed are grouped together. The contour area value is used to decide which groups of changed pixels qualify as motion. Smaller values are more sensitive meaning people that are far away, small animals, etc. are more likely to be detected as motion, but it also means that small changes in shadows, leaves, etc. are detected as motion. Higher values are less sensitive meaning these things won't be detected as motion but with the risk that desired motion won't be detected until closer to the camera.
-Watching the motion boxes in the debug view, adjust the contour area until there are no motion boxes smaller than the smallest you'd expect frigate to detect something moving.
+Watching the motion boxes in the debug view, adjust the contour area until there are no motion boxes smaller than the smallest you'd expect frigate to detect something moving.
### Improve Contrast
@@ -77,7 +77,7 @@ At this point if motion is working as desired there is no reason to continue wit
## Tuning Motion Detection During The Night
-Once daytime motion detection is tuned, there is a chance that the settings will work well for motion detection during the night as well. If this is the case then the preferred settings can be written to the config file and left alone.
+Once daytime motion detection is tuned, there is a chance that the settings will work well for motion detection during the night as well. If this is the case then the preferred settings can be written to the config file and left alone.
However, if the preferred day settings do not work well at night it is recommended to use HomeAssistant or some other solution to automate changing the settings. That way completely separate sets of motion settings can be used for optimal day and night motion detection.
diff --git a/docs/docs/configuration/object_detectors.md b/docs/docs/configuration/object_detectors.md
index 89734efb9..754cf4eaf 100644
--- a/docs/docs/configuration/object_detectors.md
+++ b/docs/docs/configuration/object_detectors.md
@@ -11,6 +11,12 @@ Frigate provides the following builtin detector types: `cpu`, `edgetpu`, `openvi
The CPU detector type runs a TensorFlow Lite model utilizing the CPU without hardware acceleration. It is recommended to use a hardware accelerated detector type instead for better performance. To configure a CPU based detector, set the `"type"` attribute to `"cpu"`.
+:::tip
+
+If you do not have GPU or Edge TPU hardware, using the [OpenVINO Detector](#openvino-detector) is often more efficient than using the CPU detector.
+
+:::
+
The number of threads used by the interpreter can be specified using the `"num_threads"` attribute, and defaults to `3.`
A TensorFlow Lite model is provided in the container at `/cpu_model.tflite` and is used by this detector type by default. To provide your own model, bind mount the file into the container and provide the path with `model.path`.
@@ -29,17 +35,17 @@ detectors:
When using CPU detectors, you can add one CPU detector per camera. Adding more detectors than the number of cameras should not improve performance.
-## Edge-TPU Detector
+## Edge TPU Detector
-The EdgeTPU detector type runs a TensorFlow Lite model utilizing the Google Coral delegate for hardware acceleration. To configure an EdgeTPU detector, set the `"type"` attribute to `"edgetpu"`.
+The Edge TPU detector type runs a TensorFlow Lite model utilizing the Google Coral delegate for hardware acceleration. To configure an Edge TPU detector, set the `"type"` attribute to `"edgetpu"`.
-The EdgeTPU device can be specified using the `"device"` attribute according to the [Documentation for the TensorFlow Lite Python API](https://coral.ai/docs/edgetpu/multiple-edgetpu/#using-the-tensorflow-lite-python-api). If not set, the delegate will use the first device it finds.
+The Edge TPU device can be specified using the `"device"` attribute according to the [Documentation for the TensorFlow Lite Python API](https://coral.ai/docs/edgetpu/multiple-edgetpu/#using-the-tensorflow-lite-python-api). If not set, the delegate will use the first device it finds.
A TensorFlow Lite model is provided in the container at `/edgetpu_model.tflite` and is used by this detector type by default. To provide your own model, bind mount the file into the container and provide the path with `model.path`.
:::tip
-See [common Edge-TPU troubleshooting steps](/troubleshooting/edgetpu) if the EdgeTPu is not detected.
+See [common Edge TPU troubleshooting steps](/troubleshooting/edgetpu) if the Edge TPU is not detected.
:::
@@ -99,13 +105,65 @@ detectors:
device: pci
```
+### Yolov8 On Coral
+
+It is possible to use the [ultralytics yolov8](https://github.com/ultralytics/ultralytics) pretrained models with the Google Coral processors.
+
+#### Setup
+
+You need to download yolov8 model files suitable for the EdgeTPU. Frigate can do this automatically with the `DOWNLOAD_YOLOV8={0 | 1}` environment variable either from the command line
+
+```bash
+$ docker run ... -e DOWNLOAD_YOLOV8=1 \
+ ...
+```
+
+or when using docker compose:
+
+```yaml
+services:
+ frigate:
+...
+ environment:
+ DOWNLOAD_YOLOV8: "1"
+```
+
+When this variable is set then frigate will at startup fetch [yolov8.small.models.tar.gz](https://github.com/harakas/models/releases/download/yolov8.1-1.1/yolov8.small.models.tar.gz) and extract it into the `/config/model_cache/yolov8/` directory.
+
+The following files suitable for the EdgeTPU detector will be available under `/config/model_cache/yolov8/`:
+
+- `yolov8[ns]_320x320_edgetpu.tflite` -- nano (n) and small (s) sized models that have been trained using the coco dataset (90 classes)
+- `yolov8[ns]-oiv7_320x320_edgetpu.tflite` -- model files that have been trained using the google open images v7 dataset (601 classes)
+- `labels.txt` and `labels-frigate.txt` -- full and aggregated labels for the coco dataset models
+- `labels-oiv7.txt` and `labels-oiv7-frigate.txt` -- labels for the oiv7 dataset models
+
+The aggregated label files contain renamed labels leaving only `person`, `vehicle`, `animal` and `bird` classes. The oiv7 trained models contain 601 classes and so are difficult to configure manually -- using aggregate labels is recommended.
+
+Larger models (of `m` and `l` size and also at `640x640` resolution) can be found at https://github.com/harakas/models/releases/tag/yolov8.1-1.1/ but have to be installed manually.
+
+The oiv7 models have been trained using a larger google open images v7 dataset. They also contain a lot more detection classes (over 600) so using aggregate label files is recommended. The large number of classes leads to lower baseline for detection probability values and also for higher resource consumption (they are slower to evaluate).
+
+#### Configuration
+
+```yaml
+model:
+ labelmap_path: /config/model_cache/yolov8/labels.txt
+ model_type: yolov8
+detectors:
+ coral:
+ type: edgetpu
+ device: usb
+ model:
+ path: /config/model_cache/yolov8/yolov8n_320x320_edgetpu.tflite
+```
+
## OpenVINO Detector
-The OpenVINO detector type runs an OpenVINO IR model on Intel CPU, GPU and VPU hardware. To configure an OpenVINO detector, set the `"type"` attribute to `"openvino"`.
+The OpenVINO detector type runs an OpenVINO IR model on AMD and Intel CPUs, Intel GPUs and Intel VPU hardware. To configure an OpenVINO detector, set the `"type"` attribute to `"openvino"`.
The OpenVINO device to be used is specified using the `"device"` attribute according to the naming conventions in the [Device Documentation](https://docs.openvino.ai/latest/openvino_docs_OV_UG_Working_with_devices.html). Other supported devices could be `AUTO`, `CPU`, `GPU`, `MYRIAD`, etc. If not specified, the default OpenVINO device will be selected by the `AUTO` plugin.
-OpenVINO is supported on 6th Gen Intel platforms (Skylake) and newer. A supported Intel platform is required to use the `GPU` device with OpenVINO. The `MYRIAD` device may be run on any platform, including Arm devices. For detailed system requirements, see [OpenVINO System Requirements](https://www.intel.com/content/www/us/en/developer/tools/openvino-toolkit/system-requirements.html)
+OpenVINO is supported on 6th Gen Intel platforms (Skylake) and newer. It will also run on AMD CPUs despite having no official support for it. A supported Intel platform is required to use the `GPU` device with OpenVINO. The `MYRIAD` device may be run on any platform, including Arm devices. For detailed system requirements, see [OpenVINO System Requirements](https://www.intel.com/content/www/us/en/developer/tools/openvino-toolkit/system-requirements.html)
An OpenVINO model is provided in the container at `/openvino-model/ssdlite_mobilenet_v2.xml` and is used by this detector type by default. The model comes from Intel's Open Model Zoo [SSDLite MobileNet V2](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/ssdlite_mobilenet_v2) and is converted to an FP16 precision IR model. Use the model configuration shown below when using the OpenVINO detector with the default model.
@@ -125,7 +183,7 @@ model:
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
```
-This detector also supports some YOLO variants: YOLOX, YOLOv5, and YOLOv8 specifically. Other YOLO variants are not officially supported/tested. Frigate does not come with any yolo models preloaded, so you will need to supply your own models. This detector has been verified to work with the [yolox_tiny](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/yolox-tiny) model from Intel's Open Model Zoo. You can follow [these instructions](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/yolox-tiny#download-a-model-and-convert-it-into-openvino-ir-format) to retrieve the OpenVINO-compatible `yolox_tiny` model. Make sure that the model input dimensions match the `width` and `height` parameters, and `model_type` is set accordingly. See [Full Configuration Reference](/configuration/index.md#full-configuration-reference) for a list of possible `model_type` options. Below is an example of how `yolox_tiny` can be used in Frigate:
+This detector also supports some YOLO variants: YOLOX, YOLOv5, and YOLOv8 specifically. Other YOLO variants are not officially supported/tested. Frigate does not come with any yolo models preloaded, so you will need to supply your own models. This detector has been verified to work with the [yolox_tiny](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/yolox-tiny) model from Intel's Open Model Zoo. You can follow [these instructions](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/yolox-tiny#download-a-model-and-convert-it-into-openvino-ir-format) to retrieve the OpenVINO-compatible `yolox_tiny` model. Make sure that the model input dimensions match the `width` and `height` parameters, and `model_type` is set accordingly. See [Full Configuration Reference](/configuration/reference.md) for a list of possible `model_type` options. Below is an example of how `yolox_tiny` can be used in Frigate:
```yaml
detectors:
@@ -146,7 +204,7 @@ model:
### Intel NCS2 VPU and Myriad X Setup
-Intel produces a neural net inference accelleration chip called Myriad X. This chip was sold in their Neural Compute Stick 2 (NCS2) which has been discontinued. If intending to use the MYRIAD device for accelleration, additional setup is required to pass through the USB device. The host needs a udev rule installed to handle the NCS2 device.
+Intel produces a neural net inference acceleration chip called Myriad X. This chip was sold in their Neural Compute Stick 2 (NCS2) which has been discontinued. If intending to use the MYRIAD device for acceleration, additional setup is required to pass through the USB device. The host needs a udev rule installed to handle the NCS2 device.
```bash
sudo usermod -a -G users "$(whoami)"
@@ -176,7 +234,7 @@ volumes:
## NVidia TensorRT Detector
-NVidia GPUs may be used for object detection using the TensorRT libraries. Due to the size of the additional libraries, this detector is only provided in images with the `-tensorrt` tag suffix, e.g. `ghcr.io/blakeblackshear/frigate:stable-tensorrt`. This detector is designed to work with Yolo models for object detection.
+Nvidia GPUs may be used for object detection using the TensorRT libraries. Due to the size of the additional libraries, this detector is only provided in images with the `-tensorrt` tag suffix, e.g. `ghcr.io/blakeblackshear/frigate:stable-tensorrt`. This detector is designed to work with Yolo models for object detection.
### Minimum Hardware Support
@@ -345,7 +403,7 @@ model: # required
Explanation for rknn specific options:
-- **core mask** controls which cores of your NPU should be used. This option applies only to SoCs with a multicore NPU (at the time of writing this in only the RK3588/S). The easiest way is to pass the value as a binary number. To do so, use the prefix `0b` and write a `0` to disable a core and a `1` to enable a core, whereas the last digit coresponds to core0, the second last to core1, etc. You also have to use the cores in ascending order (so you can't use core0 and core2; but you can use core0 and core1). Enabling more cores can reduce the inference speed, especially when using bigger models (see section below). Examples:
+- **core mask** controls which cores of your NPU should be used. This option applies only to SoCs with a multicore NPU (at the time of writing this in only the RK3588/S). The easiest way is to pass the value as a binary number. To do so, use the prefix `0b` and write a `0` to disable a core and a `1` to enable a core, whereas the last digit corresponds to core0, the second last to core1, etc. You also have to use the cores in ascending order (so you can't use core0 and core2; but you can use core0 and core1). Enabling more cores can reduce the inference speed, especially when using bigger models (see section below). Examples:
- `core_mask: 0b000` or just `core_mask: 0` let the NPU decide which cores should be used. Default and recommended value.
- `core_mask: 0b001` use only core0.
- `core_mask: 0b011` use core0 and core1.
@@ -397,3 +455,157 @@ detectors:
```
:::
+
+## AMD/ROCm GPU detector
+
+### Setup
+
+The `rocm` detector supports running [ultralytics](https://github.com/ultralytics/ultralytics) yolov8 models on AMD GPUs and iGPUs. Use a frigate docker image with `-rocm` suffix, for example `ghcr.io/blakeblackshear/frigate:stable-rocm`.
+
+As the ROCm software stack is quite bloated, there are also smaller versions for specific GPU chipsets:
+
+- `ghcr.io/blakeblackshear/frigate:stable-rocm-gfx900`
+- `ghcr.io/blakeblackshear/frigate:stable-rocm-gfx1030`
+- `ghcr.io/blakeblackshear/frigate:stable-rocm-gfx1100`
+
+### Docker settings for GPU access
+
+ROCm needs access to the `/dev/kfd` and `/dev/dri` devices. When docker or frigate is not run under root then also `video` (and possibly `render` and `ssl/_ssl`) groups should be added.
+
+When running docker directly the following flags should be added for device access:
+
+```bash
+$ docker run --device=/dev/kfd --device=/dev/dri \
+ ...
+```
+
+When using docker compose:
+
+```yaml
+services:
+ frigate:
+...
+ devices:
+ - /dev/dri
+ - /dev/kfd
+...
+```
+
+For reference on recommended settings see [running ROCm/pytorch in Docker](https://rocm.docs.amd.com/projects/install-on-linux/en/develop/how-to/3rd-party/pytorch-install.html#using-docker-with-pytorch-pre-installed).
+
+### Docker settings for overriding the GPU chipset
+
+Your GPU or iGPU might work just fine without any special configuration but in many cases they need manual settings. AMD/ROCm software stack comes with a limited set of GPU drivers and for newer or missing models you will have to override the chipset version to an older/generic version to get things working.
+
+Also AMD/ROCm does not "officially" support integrated GPUs. It still does work with most of them just fine but requires special settings. One has to configure the `HSA_OVERRIDE_GFX_VERSION` environment variable. See the [ROCm bug report](https://github.com/ROCm/ROCm/issues/1743) for context and examples.
+
+For chipset specific frigate rocm builds this variable is already set automatically.
+
+For the general rocm frigate build there is some automatic detection:
+
+ - gfx90c -> 9.0.0
+ - gfx1031 -> 10.3.0
+ - gfx1103 -> 11.0.0
+
+If you have something else you might need to override the `HSA_OVERRIDE_GFX_VERSION` at Docker launch. Suppose the version you want is `9.0.0`, then you should configure it from command line as:
+
+```bash
+$ docker run -e HSA_OVERRIDE_GFX_VERSION=9.0.0 \
+ ...
+```
+
+When using docker compose:
+
+```yaml
+services:
+ frigate:
+...
+ environment:
+ HSA_OVERRIDE_GFX_VERSION: "9.0.0"
+```
+
+Figuring out what version you need can be complicated as you can't tell the chipset name and driver from the AMD brand name.
+
+ - first make sure that rocm environment is running properly by running `/opt/rocm/bin/rocminfo` in the frigate container -- it should list both the CPU and the GPU with their properties
+ - find the chipset version you have (gfxNNN) from the output of the `rocminfo` (see below)
+ - use a search engine to query what `HSA_OVERRIDE_GFX_VERSION` you need for the given gfx name ("gfxNNN ROCm HSA_OVERRIDE_GFX_VERSION")
+ - override the `HSA_OVERRIDE_GFX_VERSION` with relevant value
+ - if things are not working check the frigate docker logs
+
+#### Figuring out if AMD/ROCm is working and found your GPU
+
+```bash
+$ docker exec -it frigate /opt/rocm/bin/rocminfo
+```
+
+#### Figuring out your AMD GPU chipset version:
+
+We unset the `HSA_OVERRIDE_GFX_VERSION` to prevent an existing override from messing up the result:
+
+```bash
+$ docker exec -it frigate /bin/bash -c '(unset HSA_OVERRIDE_GFX_VERSION && /opt/rocm/bin/rocminfo |grep gfx)'
+```
+
+### Yolov8 model download and available files
+
+The ROCm specific frigate docker containers automatically download yolov8 files from https://github.com/harakas/models/releases/tag/yolov8.1-1.1/ at startup --
+they fetch [yolov8.small.models.tar.gz](https://github.com/harakas/models/releases/download/yolov8.1-1.1/yolov8.small.models.tar.gz)
+and uncompresses it into the `/config/model_cache/yolov8/` directory. After that the model files are compiled for your GPU chipset.
+
+Both the download and compilation can take couple of minutes during which frigate will not be responsive. See docker logs for how it is progressing.
+
+Automatic model download can be configured with the `DOWNLOAD_YOLOV8=1/0` environment variable either from the command line
+
+```bash
+$ docker run ... -e DOWNLOAD_YOLOV8=1 \
+ ...
+```
+
+or when using docker compose:
+
+```yaml
+services:
+ frigate:
+...
+ environment:
+ DOWNLOAD_YOLOV8: "1"
+```
+
+Download can be triggered also in regular frigate builds using that environment variable. The following files will be available under `/config/model_cache/yolov8/`:
+
+- `yolov8[ns]_320x320.onnx` -- nano (n) and small (s) sized floating point model files usable by the `rocm` and `onnx` detectors that have been trained using the coco dataset (90 classes)
+- `yolov8[ns]-oiv7_320x320.onnx` -- floating point model files usable by the `rocm` and `onnx` detectors that have been trained using the google open images v7 dataset (601 classes)
+- `labels.txt` and `labels-frigate.txt` -- full and aggregated labels for the coco dataset models
+- `labels-oiv7.txt` and `labels-oiv7-frigate.txt` -- labels for the oiv7 dataset models
+
+The aggregated label files contain renamed labels leaving only `person`, `vehicle`, `animal` and `bird` classes. The oiv7 trained models contain 601 classes and so are difficult to configure manually -- using aggregate labels is recommended.
+
+Larger models (of `m` and `l` size and also at `640x640` resolution) can be found at https://github.com/harakas/models/releases/tag/yolov8.1-1.1/ but have to be installed manually.
+
+The oiv7 models have been trained using a larger google open images v7 dataset. They also contain a lot more detection classes (over 600) so using aggregate label files is recommended. The large number of classes leads to lower baseline for detection probability values and also for higher resource consumption (they are slower to evaluate).
+
+The `rocm` builds precompile the `onnx` files for your chipset into `mxr` files. If you change your hardware or GPU or have compiled the wrong versions you need to delete the cached `.mxr` files under `/config/model_cache/yolov8/`.
+
+### Frigate configuration
+
+You also need to modify the frigate configuration to specify the detector, labels and model file. Here is an example configuration running `yolov8s`:
+
+```yaml
+model:
+ labelmap_path: /config/model_cache/yolov8/labels.txt
+ model_type: yolov8
+detectors:
+ rocm:
+ type: rocm
+ model:
+ path: /config/model_cache/yolov8/yolov8s_320x320.onnx
+```
+
+Other settings available for the rocm detector
+
+- `conserve_cpu: True` -- run ROCm/HIP synchronization in blocking mode saving CPU (at small loss of latency and maximum throughput)
+- `auto_override_gfx: True` -- enable or disable automatic gfx driver detection
+
+### Expected performance
+
+On an AMD Ryzen 3 5400U with integrated GPU (gfx90c) the yolov8n runs in around 9ms per image (about 110 detections per second) and 18ms (55 detections per second) for yolov8s (at 320x320 detector resolution).
\ No newline at end of file
diff --git a/docs/docs/configuration/objects.mdx b/docs/docs/configuration/objects.mdx
index 81e74e2fe..1a93f9704 100644
--- a/docs/docs/configuration/objects.mdx
+++ b/docs/docs/configuration/objects.mdx
@@ -10,7 +10,7 @@ Frigate includes the object models listed below from the Google Coral test data.
Please note:
- `car` is listed twice because `truck` has been renamed to `car` by default. These object types are frequently confused.
-- `person` is the only tracked object by default. See the [full configuration reference](index.md#full-configuration-reference) for an example of expanding the list of tracked objects.
+- `person` is the only tracked object by default. See the [full configuration reference](reference.md) for an example of expanding the list of tracked objects.
{labels.split("\n").map((label) => (
diff --git a/docs/docs/configuration/record.md b/docs/docs/configuration/record.md
index 1cf1df559..32b8613f3 100644
--- a/docs/docs/configuration/record.md
+++ b/docs/docs/configuration/record.md
@@ -36,7 +36,7 @@ record:
enabled: True
retain:
days: 3
- mode: all
+ mode: motion
events:
retain:
default: 30
@@ -161,6 +161,25 @@ Using Frigate UI, HomeAssistant, or MQTT, cameras can be automated to only recor
The export page in the Frigate WebUI allows for exporting real time clips with a designated start and stop time as well as exporting a time-lapse for a designated start and stop time. These exports can take a while so it is important to leave the file until it is no longer in progress.
+### Time-lapse export
+
+When exporting a time-lapse the default speed-up is 25x with 30 FPS. This means that every 25 seconds of (real-time) recording is condensed into 1 second of time-lapse video (always without audio) with a smoothness of 30 FPS.
+To configure the speed-up factor, the frame rate and further custom settings, the configuration parameter `timelapse_args` can be used. The below configuration example would change the time-lapse speed to 60x (for fitting 1 hour of recording into 1 minute of time-lapse) with 25 FPS:
+
+```yaml
+record:
+ enabled: True
+ export:
+ timelapse_args: "-vf setpts=PTS/60 -r 25"
+```
+
+:::tip
+
+When using `hwaccel_args` globally hardware encoding is used for time lapse generation. The encoder determines its own behavior so the resulting file size may be undesirably large.
+To reduce the output file size the ffmpeg parameter `-qp n` can be utilized (where `n` stands for the value of the quantisation parameter). The value can be adjusted to get an acceptable tradeoff between quality and file size for the given scenario.
+
+:::
+
## Syncing Recordings With Disk
In some cases the recordings files may be deleted but Frigate will not know this has happened. Recordings sync can be enabled which will tell Frigate to check the file system and delete any db entries for files which don't exist.
diff --git a/docs/docs/configuration/reference.md b/docs/docs/configuration/reference.md
index 1565258d0..2ba42224d 100644
--- a/docs/docs/configuration/reference.md
+++ b/docs/docs/configuration/reference.md
@@ -145,6 +145,14 @@ birdseye:
# motion - cameras are included if motion was detected in the last 30 seconds
# continuous - all cameras are included always
mode: objects
+ # Optional: Threshold for camera activity to stop showing camera (default: shown below)
+ inactivity_threshold: 30
+ # Optional: Configure the birdseye layout
+ layout:
+ # Optional: Scaling factor for the layout calculator (default: shown below)
+ scaling_factor: 2.0
+ # Optional: Maximum number of cameras to show at one time, showing the most recent (default: show all cameras)
+ max_cameras: 1
# Optional: ffmpeg configuration
# More information about presets at https://docs.frigate.video/configuration/ffmpeg_presets
diff --git a/docs/docs/development/contributing.md b/docs/docs/development/contributing.md
index bc08afbc9..572b9768c 100644
--- a/docs/docs/development/contributing.md
+++ b/docs/docs/development/contributing.md
@@ -155,6 +155,12 @@ cd web && npm install
cd web && npm run dev
```
+##### 3a. Run the development server against a non-local instance
+
+To run the development server against a non-local instance, you will need to
+replace the `localhost` values in `vite.config.ts` with the IP address of the
+non-local backend server.
+
#### 4. Making changes
The Web UI is built using [Vite](https://vitejs.dev/), [Preact](https://preactjs.com), and [Tailwind CSS](https://tailwindcss.com).
diff --git a/docs/docs/frigate/hardware.md b/docs/docs/frigate/hardware.md
index e0285f408..399984a8a 100644
--- a/docs/docs/frigate/hardware.md
+++ b/docs/docs/frigate/hardware.md
@@ -40,14 +40,15 @@ The USB version is compatible with the widest variety of hardware and does not r
The PCIe and M.2 versions require installation of a driver on the host. Follow the instructions for your version from https://coral.ai
-A single Coral can handle many cameras and will be sufficient for the majority of users. You can calculate the maximum performance of your Coral based on the inference speed reported by Frigate. With an inference speed of 10, your Coral will top out at `1000/10=100`, or 100 frames per second. If your detection fps is regularly getting close to that, you should first consider tuning motion masks. If those are already properly configured, a second Coral may be needed.
+A single Coral can handle many cameras using the default model and will be sufficient for the majority of users. You can calculate the maximum performance of your Coral based on the inference speed reported by Frigate. With an inference speed of 10, your Coral will top out at `1000/10=100`, or 100 frames per second. If your detection fps is regularly getting close to that, you should first consider tuning motion masks. If those are already properly configured, a second Coral may be needed.
-### OpenVino
+### OpenVINO
The OpenVINO detector type is able to run on:
- 6th Gen Intel Platforms and newer that have an iGPU
- x86 & Arm64 hosts with VPU Hardware (ex: Intel NCS2)
+- Most modern AMD CPUs (though this is officially not supported by Intel)
More information is available [in the detector docs](/configuration/object_detectors#openvino-detector)
@@ -105,6 +106,12 @@ Frigate supports SBCs with the following Rockchip SoCs:
Using the yolov8n model and an Orange Pi 5 Plus with RK3588 SoC inference speeds vary between 20 - 25 ms.
+#### AMD GPUs and iGPUs
+
+With the [rocm](../configuration/object_detectors.md#amdrocm-gpu-detector) detector Frigate can take advantage of many AMD GPUs and iGPUs.
+
+An AMD Ryzen mini PC with AMD Ryzen 3 5400U iGPU takes about 9 ms to evaluate yolov8n.
+
## What does Frigate use the CPU for and what does it use a detector for? (ELI5 Version)
This is taken from a [user question on reddit](https://www.reddit.com/r/homeassistant/comments/q8mgau/comment/hgqbxh5/?utm_source=share&utm_medium=web2x&context=3). Modified slightly for clarity.
diff --git a/docs/docs/frigate/installation.md b/docs/docs/frigate/installation.md
index c12e3de3a..f07f8f687 100644
--- a/docs/docs/frigate/installation.md
+++ b/docs/docs/frigate/installation.md
@@ -49,7 +49,7 @@ services:
:::caution
-Users of the Snapcraft build of Docker cannot use storage locations outside your $HOME folder.
+Users of the Snapcraft build of Docker cannot use storage locations outside your $HOME folder.
:::
@@ -98,9 +98,10 @@ services:
image: ghcr.io/blakeblackshear/frigate:stable
shm_size: "64mb" # update for your cameras based on calculation above
devices:
- - /dev/bus/usb:/dev/bus/usb # passes the USB Coral, needs to be modified for other versions
- - /dev/apex_0:/dev/apex_0 # passes a PCIe Coral, follow driver instructions here https://coral.ai/docs/m2/get-started/#2a-on-linux
- - /dev/dri/renderD128 # for intel hwaccel, needs to be updated for your hardware
+ - /dev/bus/usb:/dev/bus/usb # Passes the USB Coral, needs to be modified for other versions
+ - /dev/apex_0:/dev/apex_0 # Passes a PCIe Coral, follow driver instructions here https://coral.ai/docs/m2/get-started/#2a-on-linux
+ - /dev/video11:/dev/video11 # For Raspberry Pi 4B
+ - /dev/dri/renderD128:/dev/dri/renderD128 # For intel hwaccel, needs to be updated for your hardware
volumes:
- /etc/localtime:/etc/localtime:ro
- /path/to/your/config:/config
@@ -150,6 +151,10 @@ The community supported docker image tags for the current stable version are:
- `stable-tensorrt-jp5` - Frigate build optimized for nvidia Jetson devices running Jetpack 5
- `stable-tensorrt-jp4` - Frigate build optimized for nvidia Jetson devices running Jetpack 4.6
- `stable-rk` - Frigate build for SBCs with Rockchip SoC
+- `stable-rocm` - Frigate build for [AMD GPUs and iGPUs](../configuration/object_detectors.md#amdrocm-gpu-detector), all drivers
+ - `stable-rocm-gfx900` - AMD gfx900 driver only
+ - `stable-rocm-gfx1030` - AMD gfx1030 driver only
+ - `stable-rocm-gfx1100` - AMD gfx1100 driver only
## Home Assistant Addon
diff --git a/docs/docs/guides/getting_started.md b/docs/docs/guides/getting_started.md
index 5975da354..7cf9e2790 100644
--- a/docs/docs/guides/getting_started.md
+++ b/docs/docs/guides/getting_started.md
@@ -237,7 +237,7 @@ cameras:
More details on available detectors can be found [here](../configuration/object_detectors.md).
-Restart Frigate and you should start seeing detections for `person`. If you want to track other objects, they will need to be added according to the [configuration file reference](../configuration/index.md#full-configuration-reference).
+Restart Frigate and you should start seeing detections for `person`. If you want to track other objects, they will need to be added according to the [configuration file reference](../configuration/reference.md).
### Step 5: Setup motion masks
@@ -305,7 +305,7 @@ cameras:
If you don't have separate streams for detect and record, you would just add the record role to the list on the first input.
-By default, Frigate will retain video of all events for 10 days. The full set of options for recording can be found [here](../configuration/index.md#full-configuration-reference).
+By default, Frigate will retain video of all events for 10 days. The full set of options for recording can be found [here](../configuration/reference.md).
#### Snapshots
@@ -325,7 +325,7 @@ cameras:
motion: ...
```
-By default, Frigate will retain snapshots of all events for 10 days. The full set of options for snapshots can be found [here](../configuration/index.md#full-configuration-reference).
+By default, Frigate will retain snapshots of all events for 10 days. The full set of options for snapshots can be found [here](../configuration/reference.md).
### Step 7: Complete config
diff --git a/docs/docs/guides/ha_network_storage.md b/docs/docs/guides/ha_network_storage.md
index b248cae4a..18f39d4f1 100644
--- a/docs/docs/guides/ha_network_storage.md
+++ b/docs/docs/guides/ha_network_storage.md
@@ -3,7 +3,7 @@ id: ha_network_storage
title: Home Assistant network storage
---
-As of Home Asisstant Core 2023.6, Network Mounted Storage is supported for addons.
+As of Home Assistant Core 2023.6, Network Mounted Storage is supported for addons.
## Setting Up Remote Storage For Frigate
diff --git a/docs/docs/guides/reverse_proxy.md b/docs/docs/guides/reverse_proxy.md
index 479df53e8..798df37bf 100644
--- a/docs/docs/guides/reverse_proxy.md
+++ b/docs/docs/guides/reverse_proxy.md
@@ -87,7 +87,7 @@ There are many ways to authenticate a website but a straightforward approach is
## Nginx Reverse Proxy
-This method shows a working example for subdomain type reverse proxy with SSL enabled.
+This method shows a working example for subdomain type reverse proxy with SSL enabled.
### Setup server and port to reverse proxy
@@ -123,7 +123,7 @@ This section points to your SSL files, the example below shows locations to a de
```
-### Setup reverse proxy settings
+### Setup reverse proxy settings
The settings below enabled connection upgrade, sets up logging (optional) and proxies everything from the `/` context to the docker host and port specified earlier in the configuration
diff --git a/docs/docs/integrations/api.md b/docs/docs/integrations/api.md
index 4cf696010..510a8a3c8 100644
--- a/docs/docs/integrations/api.md
+++ b/docs/docs/integrations/api.md
@@ -43,7 +43,7 @@ Accepts the following query string parameters:
Example parameters:
-- `h=300`: resizes the image to 300 pixes tall
+- `h=300`: resizes the image to 300 pixels tall
### `GET /api/stats`
diff --git a/docs/docs/plus/faq.md b/docs/docs/plus/faq.md
index 1723e0583..fb0cd2512 100644
--- a/docs/docs/plus/faq.md
+++ b/docs/docs/plus/faq.md
@@ -7,10 +7,6 @@ title: FAQ
Frigate+ models are built by fine tuning a base model with the images you have annotated and verified. The base model is trained from scratch from a sampling of images across all Frigate+ user submissions and takes weeks of expensive GPU resources to train. If the models were built using your image uploads alone, you would need to provide tens of thousands of examples and it would take more than a week (and considerable cost) to train. Diversity helps the model generalize.
-### What is a training credit and how do I use them?
-
-Essentially, `1 training credit = 1 trained model`. When you have uploaded, annotated, and verified additional images and you are ready to train your model, you will submit a model request which will use one credit. The model that is trained will utilize all of the verified images in your account. When new base models are available, it will require the use of a training credit to generate a new user model on the new base model.
-
### Are my video feeds sent to the cloud for analysis when using Frigate+ models?
No. Frigate+ models are a drop in replacement for the default model. All processing is performed locally as always. The only images sent to Frigate+ are the ones you specifically submit via the `Send to Frigate+` button or upload directly.
@@ -25,4 +21,4 @@ Yes. Models and metadata are stored in the `model_cache` directory within the co
### Can I keep using my Frigate+ models even if I do not renew my subscription?
-Yes. Subscriptions to Frigate+ provide access to the infrastructure used to train the models. Models trained using the training credits that you purchased are yours to keep and use forever. However, do note that the terms and conditions prohibit you from sharing, reselling, or creating derivative products from the models.
+Yes. Subscriptions to Frigate+ provide access to the infrastructure used to train the models. Models trained with your subscription are yours to keep and use forever. However, do note that the terms and conditions prohibit you from sharing, reselling, or creating derivative products from the models.
diff --git a/docs/docs/plus/first_model.md b/docs/docs/plus/first_model.md
index 8dcc52015..2f76dd08a 100644
--- a/docs/docs/plus/first_model.md
+++ b/docs/docs/plus/first_model.md
@@ -13,7 +13,7 @@ For more detailed recommendations, you can refer to the docs on [improving your
## Step 2: Submit a model request
-Once you have an initial set of verified images, you can request a model on the Models page. Each model request requires 1 of the training credits that you receive with your annual subscription. This model will support all [label types available](./index.md#available-label-types) even if you do not submit any examples for those labels. Model creation can take up to 36 hours.
+Once you have an initial set of verified images, you can request a model on the Models page. Each model request requires 1 of the 12 trainings that you receive with your annual subscription. This model will support all [label types available](./index.md#available-label-types) even if you do not submit any examples for those labels. Model creation can take up to 36 hours.

## Step 3: Set your model id in the config
diff --git a/docs/docs/plus/index.md b/docs/docs/plus/index.md
index c04e594e8..de84c6a45 100644
--- a/docs/docs/plus/index.md
+++ b/docs/docs/plus/index.md
@@ -11,7 +11,7 @@ The baseline model isn't directly available after subscribing. This may change i
:::
-With a subscription, and at each annual renewal, you will receive 12 model training credits. If you cancel your subscription, you will retain access to any trained models. An active subscription is required to submit model requests or purchase additional training credits.
+With a subscription, 12 model trainings per year are included. If you cancel your subscription, you will retain access to any trained models. An active subscription is required to submit model requests or purchase additional trainings.
Information on how to integrate Frigate+ with Frigate can be found in the [integration docs](../integrations/plus.md).
diff --git a/docs/docs/troubleshooting/edgetpu.md b/docs/docs/troubleshooting/edgetpu.md
index b6cb8d878..5cac6e5af 100644
--- a/docs/docs/troubleshooting/edgetpu.md
+++ b/docs/docs/troubleshooting/edgetpu.md
@@ -25,7 +25,7 @@ The USB coral can draw up to 900mA and this can be too much for some on-device U
The USB coral has different IDs when it is uninitialized and initialized.
-- When running Frigate in a VM, Proxmox lxc, etc. you must ensure both device IDs are mapped.
+- When running Frigate in a VM, Proxmox lxc, etc. you must ensure both device IDs are mapped.
- When running HA OS you may need to run the Full Access version of the Frigate addon with the `Protected Mode` switch disabled so that the coral can be accessed.
## USB Coral Detection Appears to be Stuck
diff --git a/docs/docs/troubleshooting/faqs.md b/docs/docs/troubleshooting/faqs.md
index ca64974fa..2201fec58 100644
--- a/docs/docs/troubleshooting/faqs.md
+++ b/docs/docs/troubleshooting/faqs.md
@@ -56,4 +56,4 @@ SQLite does not work well on a network share, if the `/media` folder is mapped t
If MQTT isn't working in docker try using the IP of the device hosting the MQTT server instead of `localhost`, `127.0.0.1`, or `mosquitto.ix-mosquitto.svc.cluster.local`.
-This is because, by default, Frigate does not run in host mode so localhost points to the Frigate container and not the host device's network.
+This is because, by default, Frigate does not run in host mode so localhost points to the Frigate container and not the host device's network.
diff --git a/docs/docs/troubleshooting/recordings.md b/docs/docs/troubleshooting/recordings.md
index d1d2dc7fe..611ba45e2 100644
--- a/docs/docs/troubleshooting/recordings.md
+++ b/docs/docs/troubleshooting/recordings.md
@@ -5,7 +5,7 @@ title: Troubleshooting Recordings
### WARNING : Unable to keep up with recording segments in cache for camera. Keeping the 5 most recent segments out of 6 and discarding the rest...
-This error can be caused by a number of different issues. The first step in troubleshooting is to enable debug logging for recording, this will enable logging showing how long it takes for recordings to be moved from RAM cache to the disk.
+This error can be caused by a number of different issues. The first step in troubleshooting is to enable debug logging for recording. This will enable logging showing how long it takes for recordings to be moved from RAM cache to the disk.
```yaml
logger:
@@ -25,6 +25,41 @@ It is important to let this run until the errors begin to happen, to confirm tha
If the storage is too slow to keep up with the recordings then the maintainer will fall behind and purge the oldest recordings to ensure the cache does not fill up causing a crash. In this case it is important to diagnose why the copy times are slow.
+##### Check RAM, swap, cache utilization, and disk utilization
+
+If CPU, RAM, disk throughput, or bus I/O is insufficient, nothing inside frigate will help. It is important to review each aspect of available system resources.
+
+On linux, some helpful tools/commands in diagnosing would be:
+
+- docker stats
+- htop
+- iotop -o
+- iostat -sxy --human 1 1
+- vmstat 1
+
+On modern linux kernels, the system will utilize some swap if enabled. Setting vm.swappiness=1 no longer means that the kernel will only swap in order to avoid OOM. To prevent any swapping inside a container, set allocations memory and memory+swap to be the same and disable swapping by setting the following docker/podman run parameters:
+
+**Compose example**
+```yaml
+version: "3.9"
+services:
+ frigate:
+ ...
+ mem_swappiness: 0
+ memswap_limit:
+ deploy:
+ resources:
+ limits:
+ memory:
+```
+
+**Run command example**
+```
+--memory= --memory-swap= --memory-swappiness=0
+```
+
+NOTE: These are hard-limits for the container, be sure there is enough headroom above what is shown by `docker stats` for your container. It will immediately halt if it hits ``. In general, running all cache and tmp filespace in RAM is preferable to disk I/O where possible.
+
##### Check Storage Type
Mounting a network share is a popular option for storing Recordings, but this can lead to reduced copy times and cause problems. Some users have found that using `NFS` instead of `SMB` considerably decreased the copy times and fixed the issue. It is also important to ensure that the network connection between the device running Frigate and the network share is stable and fast.
diff --git a/frigate/app.py b/frigate/app.py
index 5aa738d93..be01bd0ab 100644
--- a/frigate/app.py
+++ b/frigate/app.py
@@ -17,11 +17,13 @@ from peewee_migrate import Router
from playhouse.sqlite_ext import SqliteExtDatabase
from playhouse.sqliteq import SqliteQueueDatabase
+from frigate.comms.config_updater import ConfigPublisher
+from frigate.comms.detections_updater import DetectionProxy
from frigate.comms.dispatcher import Communicator, Dispatcher
from frigate.comms.inter_process import InterProcessCommunicator
from frigate.comms.mqtt import MqttClient
from frigate.comms.ws import WebSocketClient
-from frigate.config import BirdseyeModeEnum, FrigateConfig
+from frigate.config import FrigateConfig
from frigate.const import (
CACHE_DIR,
CLIPS_DIR,
@@ -43,6 +45,7 @@ from frigate.models import (
Recordings,
RecordingsToDelete,
Regions,
+ ReviewSegment,
Timeline,
)
from frigate.object_detection import ObjectDetectProcess
@@ -53,10 +56,12 @@ from frigate.ptz.autotrack import PtzAutoTrackerThread
from frigate.ptz.onvif import OnvifController
from frigate.record.cleanup import RecordingCleanup
from frigate.record.record import manage_recordings
-from frigate.stats import StatsEmitter, stats_init
+from frigate.review.review import manage_review_segments
+from frigate.stats.emitter import StatsEmitter
+from frigate.stats.util import stats_init
from frigate.storage import StorageMaintainer
from frigate.timeline import TimelineProcessor
-from frigate.types import CameraMetricsTypes, FeatureMetricsTypes, PTZMetricsTypes
+from frigate.types import CameraMetricsTypes, PTZMetricsTypes
from frigate.util.object import get_camera_regions_grid
from frigate.version import VERSION
from frigate.video import capture_camera, track_camera
@@ -75,7 +80,6 @@ class FrigateApp:
self.log_queue: Queue = mp.Queue()
self.plus_api = PlusApi()
self.camera_metrics: dict[str, CameraMetricsTypes] = {}
- self.feature_metrics: dict[str, FeatureMetricsTypes] = {}
self.ptz_metrics: dict[str, PTZMetricsTypes] = {}
self.processes: dict[str, int] = {}
self.region_grids: dict[str, list[list[dict[str, int]]]] = {}
@@ -129,35 +133,6 @@ class FrigateApp:
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
"process_fps": mp.Value("d", 0.0), # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "detection_enabled": mp.Value( # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "i",
- self.config.cameras[camera_name].detect.enabled,
- ),
- "motion_enabled": mp.Value("i", True), # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "improve_contrast_enabled": mp.Value( # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "i",
- self.config.cameras[camera_name].motion.improve_contrast,
- ),
- "motion_threshold": mp.Value( # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "i",
- self.config.cameras[camera_name].motion.threshold,
- ),
- "motion_contour_area": mp.Value( # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "i",
- self.config.cameras[camera_name].motion.contour_area,
- ),
"detection_fps": mp.Value("d", 0.0), # type: ignore[typeddict-item]
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
@@ -171,25 +146,10 @@ class FrigateApp:
# issue https://github.com/python/typeshed/issues/8799
# from mypy 0.981 onwards
"frame_queue": mp.Queue(maxsize=2),
- "region_grid_queue": mp.Queue(maxsize=1),
"capture_process": None,
"process": None,
"audio_rms": mp.Value("d", 0.0), # type: ignore[typeddict-item]
"audio_dBFS": mp.Value("d", 0.0), # type: ignore[typeddict-item]
- "birdseye_enabled": mp.Value( # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "i",
- self.config.cameras[camera_name].birdseye.enabled,
- ),
- "birdseye_mode": mp.Value( # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "i",
- BirdseyeModeEnum.get_index(
- self.config.cameras[camera_name].birdseye.mode.value
- ),
- ),
}
self.ptz_metrics[camera_name] = {
"ptz_autotracker_enabled": mp.Value( # type: ignore[typeddict-item]
@@ -221,20 +181,6 @@ class FrigateApp:
# from mypy 0.981 onwards
}
self.ptz_metrics[camera_name]["ptz_motor_stopped"].set()
- self.feature_metrics[camera_name] = {
- "audio_enabled": mp.Value( # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "i",
- self.config.cameras[camera_name].audio.enabled,
- ),
- "record_enabled": mp.Value( # type: ignore[typeddict-item]
- # issue https://github.com/python/typeshed/issues/8799
- # from mypy 0.981 onwards
- "i",
- self.config.cameras[camera_name].record.enabled,
- ),
- }
def set_log_levels(self) -> None:
logging.getLogger().setLevel(self.config.logger.default.value.upper())
@@ -251,31 +197,15 @@ class FrigateApp:
# Queues for clip processing
self.event_queue: Queue = mp.Queue()
self.event_processed_queue: Queue = mp.Queue()
- self.video_output_queue: Queue = mp.Queue(
- maxsize=sum(camera.enabled for camera in self.config.cameras.values()) * 2
- )
# Queue for cameras to push tracked objects to
self.detected_frames_queue: Queue = mp.Queue(
maxsize=sum(camera.enabled for camera in self.config.cameras.values()) * 2
)
- # Queue for object recordings info
- self.object_recordings_info_queue: Queue = mp.Queue()
-
- # Queue for audio recordings info if enabled
- self.audio_recordings_info_queue: Optional[Queue] = (
- mp.Queue()
- if len([c for c in self.config.cameras.values() if c.audio.enabled]) > 0
- else None
- )
-
# Queue for timeline events
self.timeline_queue: Queue = mp.Queue()
- # Queue for inter process communication
- self.inter_process_queue: Queue = mp.Queue()
-
def init_database(self) -> None:
def vacuum_db(db: SqliteExtDatabase) -> None:
logger.info("Running database vacuum")
@@ -348,13 +278,7 @@ class FrigateApp:
recording_process = mp.Process(
target=manage_recordings,
name="recording_manager",
- args=(
- self.config,
- self.inter_process_queue,
- self.object_recordings_info_queue,
- self.audio_recordings_info_queue,
- self.feature_metrics,
- ),
+ args=(self.config,),
)
recording_process.daemon = True
self.recording_process = recording_process
@@ -362,6 +286,18 @@ class FrigateApp:
self.processes["recording"] = recording_process.pid or 0
logger.info(f"Recording process started: {recording_process.pid}")
+ def init_review_segment_manager(self) -> None:
+ review_segment_process = mp.Process(
+ target=manage_review_segments,
+ name="review_segment_manager",
+ args=(self.config,),
+ )
+ review_segment_process.daemon = True
+ self.review_segment_process = review_segment_process
+ review_segment_process.start()
+ self.processes["review_segment"] = review_segment_process.pid or 0
+ logger.info(f"Recording process started: {review_segment_process.pid}")
+
def bind_database(self) -> None:
"""Bind db to the main process."""
# NOTE: all db accessing processes need to be created before the db can be bound to the main process
@@ -376,34 +312,37 @@ class FrigateApp:
60, 10 * len([c for c in self.config.cameras.values() if c.enabled])
),
)
- models = [Event, Recordings, RecordingsToDelete, Previews, Regions, Timeline]
+ models = [
+ Event,
+ Previews,
+ Recordings,
+ RecordingsToDelete,
+ Regions,
+ ReviewSegment,
+ Timeline,
+ ]
self.db.bind(models)
- def init_stats(self) -> None:
- self.stats_tracking = stats_init(
- self.config, self.camera_metrics, self.detectors, self.processes
- )
-
def init_external_event_processor(self) -> None:
self.external_event_processor = ExternalEventProcessor(
self.config, self.event_queue
)
def init_inter_process_communicator(self) -> None:
- self.inter_process_communicator = InterProcessCommunicator(
- self.inter_process_queue
- )
+ self.inter_process_communicator = InterProcessCommunicator()
+ self.inter_config_updater = ConfigPublisher()
+ self.inter_detection_proxy = DetectionProxy()
def init_web_server(self) -> None:
self.flask_app = create_app(
self.config,
self.db,
- self.stats_tracking,
self.detected_frames_processor,
self.storage_maintainer,
self.onvif_controller,
self.external_event_processor,
self.plus_api,
+ self.stats_emitter,
)
def init_onvif(self) -> None:
@@ -420,9 +359,8 @@ class FrigateApp:
self.dispatcher = Dispatcher(
self.config,
+ self.inter_config_updater,
self.onvif_controller,
- self.camera_metrics,
- self.feature_metrics,
self.ptz_metrics,
comms,
)
@@ -481,8 +419,6 @@ class FrigateApp:
self.detected_frames_queue,
self.event_queue,
self.event_processed_queue,
- self.video_output_queue,
- self.object_recordings_info_queue,
self.ptz_autotracker_thread,
self.stop_event,
)
@@ -492,12 +428,7 @@ class FrigateApp:
output_processor = mp.Process(
target=output_frames,
name="output_processor",
- args=(
- self.config,
- self.video_output_queue,
- self.inter_process_queue,
- self.camera_metrics,
- ),
+ args=(self.config,),
)
output_processor.daemon = True
self.output_processor = output_processor
@@ -534,7 +465,6 @@ class FrigateApp:
self.detection_queue,
self.detection_out_events[name],
self.detected_frames_queue,
- self.inter_process_queue,
self.camera_metrics[name],
self.ptz_metrics[name],
self.region_grids[name],
@@ -568,10 +498,7 @@ class FrigateApp:
name="audio_capture",
args=(
self.config,
- self.audio_recordings_info_queue,
self.camera_metrics,
- self.feature_metrics,
- self.inter_process_communicator,
),
)
audio_process.daemon = True
@@ -611,8 +538,9 @@ class FrigateApp:
def start_stats_emitter(self) -> None:
self.stats_emitter = StatsEmitter(
self.config,
- self.stats_tracking,
- self.dispatcher,
+ stats_init(
+ self.config, self.camera_metrics, self.detectors, self.processes
+ ),
self.stop_event,
)
self.stats_emitter.start()
@@ -647,6 +575,25 @@ class FrigateApp:
self.init_logger()
logger.info(f"Starting Frigate ({VERSION})")
+
+ if not os.environ.get("I_PROMISE_I_WONT_MAKE_AN_ISSUE_ON_GITHUB"):
+ print(
+ "**********************************************************************************"
+ )
+ print(
+ "**********************************************************************************"
+ )
+ print("Frigate 0.14 UNSTABLE")
+ print("This build is not for public use. Please use Frigate stable.")
+ print("Unstable/experimental builds are not enabled, Frigate is exiting.")
+ print(
+ "**********************************************************************************"
+ )
+ print(
+ "**********************************************************************************"
+ )
+ sys.exit(1)
+
try:
self.ensure_dirs()
try:
@@ -680,6 +627,7 @@ class FrigateApp:
self.init_database()
self.init_onvif()
self.init_recording_manager()
+ self.init_review_segment_manager()
self.init_go2rtc()
self.bind_database()
self.init_inter_process_communicator()
@@ -697,14 +645,13 @@ class FrigateApp:
self.start_camera_capture_processes()
self.start_audio_processors()
self.start_storage_maintainer()
- self.init_stats()
self.init_external_event_processor()
+ self.start_stats_emitter()
self.init_web_server()
self.start_timeline_processor()
self.start_event_processor()
self.start_event_cleanup()
self.start_record_cleanup()
- self.start_stats_emitter()
self.start_watchdog()
self.check_shm()
@@ -753,15 +700,16 @@ class FrigateApp:
for queue in [
self.event_queue,
self.event_processed_queue,
- self.video_output_queue,
self.detected_frames_queue,
- self.object_recordings_info_queue,
- self.audio_recordings_info_queue,
self.log_queue,
- self.inter_process_queue,
]:
if queue is not None:
while not queue.empty():
queue.get_nowait()
queue.close()
queue.join_thread()
+
+ # Stop Communicators
+ self.inter_process_communicator.stop()
+ self.inter_config_updater.stop()
+ self.inter_detection_proxy.stop()
diff --git a/frigate/comms/config_updater.py b/frigate/comms/config_updater.py
new file mode 100644
index 000000000..273103911
--- /dev/null
+++ b/frigate/comms/config_updater.py
@@ -0,0 +1,51 @@
+"""Facilitates communication between processes."""
+
+import multiprocessing as mp
+from multiprocessing.synchronize import Event as MpEvent
+from typing import Optional
+
+import zmq
+
+SOCKET_PUB_SUB = "ipc:///tmp/cache/config"
+
+
+class ConfigPublisher:
+ """Publishes config changes to different processes."""
+
+ def __init__(self) -> None:
+ self.context = zmq.Context()
+ self.socket = self.context.socket(zmq.PUB)
+ self.socket.bind(SOCKET_PUB_SUB)
+ self.stop_event: MpEvent = mp.Event()
+
+ def publish(self, topic: str, payload: any) -> None:
+ """There is no communication back to the processes."""
+ self.socket.send_string(topic, flags=zmq.SNDMORE)
+ self.socket.send_pyobj(payload)
+
+ def stop(self) -> None:
+ self.stop_event.set()
+ self.socket.close()
+ self.context.destroy()
+
+
+class ConfigSubscriber:
+ """Simplifies receiving an updated config."""
+
+ def __init__(self, topic: str) -> None:
+ self.context = zmq.Context()
+ self.socket = self.context.socket(zmq.SUB)
+ self.socket.setsockopt_string(zmq.SUBSCRIBE, topic)
+ self.socket.connect(SOCKET_PUB_SUB)
+
+ def check_for_update(self) -> Optional[tuple[str, any]]:
+ """Returns updated config or None if no update."""
+ try:
+ topic = self.socket.recv_string(flags=zmq.NOBLOCK)
+ return (topic, self.socket.recv_pyobj())
+ except zmq.ZMQError:
+ return (None, None)
+
+ def stop(self) -> None:
+ self.socket.close()
+ self.context.destroy()
diff --git a/frigate/comms/detections_updater.py b/frigate/comms/detections_updater.py
new file mode 100644
index 000000000..ff544dfbd
--- /dev/null
+++ b/frigate/comms/detections_updater.py
@@ -0,0 +1,102 @@
+"""Facilitates communication between processes."""
+
+import threading
+from enum import Enum
+from typing import Optional
+
+import zmq
+
+SOCKET_CONTROL = "inproc://control.detections_updater"
+SOCKET_PUB = "ipc:///tmp/cache/detect_pub"
+SOCKET_SUB = "ipc:///tmp/cache/detect_sun"
+
+
+class DetectionTypeEnum(str, Enum):
+ all = ""
+ video = "video"
+ audio = "audio"
+
+
+class DetectionProxyRunner(threading.Thread):
+ def __init__(self, context: zmq.Context[zmq.Socket]) -> None:
+ threading.Thread.__init__(self)
+ self.name = "detection_proxy"
+ self.context = context
+
+ def run(self) -> None:
+ """Run the proxy."""
+ control = self.context.socket(zmq.SUB)
+ control.connect(SOCKET_CONTROL)
+ control.setsockopt_string(zmq.SUBSCRIBE, "")
+ incoming = self.context.socket(zmq.XSUB)
+ incoming.bind(SOCKET_PUB)
+ outgoing = self.context.socket(zmq.XPUB)
+ outgoing.bind(SOCKET_SUB)
+
+ zmq.proxy_steerable(
+ incoming, outgoing, None, control
+ ) # blocking, will unblock terminate message is received
+ incoming.close()
+ outgoing.close()
+
+
+class DetectionProxy:
+ """Proxies video and audio detections."""
+
+ def __init__(self) -> None:
+ self.context = zmq.Context()
+ self.control = self.context.socket(zmq.PUB)
+ self.control.bind(SOCKET_CONTROL)
+ self.runner = DetectionProxyRunner(self.context)
+ self.runner.start()
+
+ def stop(self) -> None:
+ self.control.send_string("TERMINATE") # tell the proxy to stop
+ self.runner.join()
+ self.context.destroy()
+
+
+class DetectionPublisher:
+ """Simplifies receiving video and audio detections."""
+
+ def __init__(self, topic: DetectionTypeEnum) -> None:
+ self.topic = topic
+ self.context = zmq.Context()
+ self.socket = self.context.socket(zmq.PUB)
+ self.socket.connect(SOCKET_PUB)
+
+ def send_data(self, payload: any) -> None:
+ """Publish detection."""
+ self.socket.send_string(self.topic.value, flags=zmq.SNDMORE)
+ self.socket.send_pyobj(payload)
+
+ def stop(self) -> None:
+ self.socket.close()
+ self.context.destroy()
+
+
+class DetectionSubscriber:
+ """Simplifies receiving video and audio detections."""
+
+ def __init__(self, topic: DetectionTypeEnum) -> None:
+ self.context = zmq.Context()
+ self.socket = self.context.socket(zmq.SUB)
+ self.socket.setsockopt_string(zmq.SUBSCRIBE, topic.value)
+ self.socket.connect(SOCKET_SUB)
+
+ def get_data(self, timeout: float = None) -> Optional[tuple[str, any]]:
+ """Returns detections or None if no update."""
+ try:
+ has_update, _, _ = zmq.select([self.socket], [], [], timeout)
+
+ if has_update:
+ topic = DetectionTypeEnum[self.socket.recv_string(flags=zmq.NOBLOCK)]
+ return (topic, self.socket.recv_pyobj())
+ except zmq.ZMQError:
+ pass
+
+ return (None, None)
+
+ def stop(self) -> None:
+ self.socket.close()
+ self.context.destroy()
diff --git a/frigate/comms/dispatcher.py b/frigate/comms/dispatcher.py
index d83371c01..bf551419a 100644
--- a/frigate/comms/dispatcher.py
+++ b/frigate/comms/dispatcher.py
@@ -2,13 +2,19 @@
import logging
from abc import ABC, abstractmethod
-from typing import Any, Callable
+from typing import Any, Callable, Optional
+from frigate.comms.config_updater import ConfigPublisher
from frigate.config import BirdseyeModeEnum, FrigateConfig
-from frigate.const import INSERT_MANY_RECORDINGS, INSERT_PREVIEW, REQUEST_REGION_GRID
-from frigate.models import Previews, Recordings
+from frigate.const import (
+ INSERT_MANY_RECORDINGS,
+ INSERT_PREVIEW,
+ REQUEST_REGION_GRID,
+ UPSERT_REVIEW_SEGMENT,
+)
+from frigate.models import Previews, Recordings, ReviewSegment
from frigate.ptz.onvif import OnvifCommandEnum, OnvifController
-from frigate.types import CameraMetricsTypes, FeatureMetricsTypes, PTZMetricsTypes
+from frigate.types import PTZMetricsTypes
from frigate.util.object import get_camera_regions_grid
from frigate.util.services import restart_frigate
@@ -40,16 +46,14 @@ class Dispatcher:
def __init__(
self,
config: FrigateConfig,
+ config_updater: ConfigPublisher,
onvif: OnvifController,
- camera_metrics: dict[str, CameraMetricsTypes],
- feature_metrics: dict[str, FeatureMetricsTypes],
ptz_metrics: dict[str, PTZMetricsTypes],
communicators: list[Communicator],
) -> None:
self.config = config
+ self.config_updater = config_updater
self.onvif = onvif
- self.camera_metrics = camera_metrics
- self.feature_metrics = feature_metrics
self.ptz_metrics = ptz_metrics
self.comms = communicators
@@ -70,7 +74,7 @@ class Dispatcher:
for comm in self.comms:
comm.subscribe(self._receive)
- def _receive(self, topic: str, payload: str) -> None:
+ def _receive(self, topic: str, payload: str) -> Optional[Any]:
"""Handle receiving of payload from communicators."""
if topic.endswith("set"):
try:
@@ -95,15 +99,23 @@ class Dispatcher:
Recordings.insert_many(payload).execute()
elif topic == REQUEST_REGION_GRID:
camera = payload
- self.camera_metrics[camera]["region_grid_queue"].put(
- get_camera_regions_grid(
- camera,
- self.config.cameras[camera].detect,
- max(self.config.model.width, self.config.model.height),
- )
+ grid = get_camera_regions_grid(
+ camera,
+ self.config.cameras[camera].detect,
+ max(self.config.model.width, self.config.model.height),
)
+ return grid
elif topic == INSERT_PREVIEW:
Previews.insert(payload).execute()
+ elif topic == UPSERT_REVIEW_SEGMENT:
+ (
+ ReviewSegment.insert(payload)
+ .on_conflict(
+ conflict_target=[ReviewSegment.id],
+ update=payload,
+ )
+ .execute()
+ )
else:
self.publish(topic, payload, retain=False)
@@ -119,44 +131,51 @@ class Dispatcher:
def _on_detect_command(self, camera_name: str, payload: str) -> None:
"""Callback for detect topic."""
detect_settings = self.config.cameras[camera_name].detect
+ motion_settings = self.config.cameras[camera_name].motion
if payload == "ON":
- if not self.camera_metrics[camera_name]["detection_enabled"].value:
+ if not detect_settings.enabled:
logger.info(f"Turning on detection for {camera_name}")
- self.camera_metrics[camera_name]["detection_enabled"].value = True
detect_settings.enabled = True
- if not self.camera_metrics[camera_name]["motion_enabled"].value:
+ if not motion_settings.enabled:
logger.info(
f"Turning on motion for {camera_name} due to detection being enabled."
)
- self.camera_metrics[camera_name]["motion_enabled"].value = True
+ motion_settings.enabled = True
+ self.config_updater.publish(
+ f"config/motion/{camera_name}", motion_settings
+ )
self.publish(f"{camera_name}/motion/state", payload, retain=True)
elif payload == "OFF":
- if self.camera_metrics[camera_name]["detection_enabled"].value:
+ if detect_settings.enabled:
logger.info(f"Turning off detection for {camera_name}")
- self.camera_metrics[camera_name]["detection_enabled"].value = False
detect_settings.enabled = False
+ self.config_updater.publish(f"config/detect/{camera_name}", detect_settings)
self.publish(f"{camera_name}/detect/state", payload, retain=True)
def _on_motion_command(self, camera_name: str, payload: str) -> None:
"""Callback for motion topic."""
+ detect_settings = self.config.cameras[camera_name].detect
+ motion_settings = self.config.cameras[camera_name].motion
+
if payload == "ON":
- if not self.camera_metrics[camera_name]["motion_enabled"].value:
+ if not motion_settings.enabled:
logger.info(f"Turning on motion for {camera_name}")
- self.camera_metrics[camera_name]["motion_enabled"].value = True
+ motion_settings.enabled = True
elif payload == "OFF":
- if self.camera_metrics[camera_name]["detection_enabled"].value:
+ if detect_settings.enabled:
logger.error(
"Turning off motion is not allowed when detection is enabled."
)
return
- if self.camera_metrics[camera_name]["motion_enabled"].value:
+ if motion_settings.enabled:
logger.info(f"Turning off motion for {camera_name}")
- self.camera_metrics[camera_name]["motion_enabled"].value = False
+ motion_settings.enabled = False
+ self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
self.publish(f"{camera_name}/motion/state", payload, retain=True)
def _on_motion_improve_contrast_command(
@@ -166,20 +185,15 @@ class Dispatcher:
motion_settings = self.config.cameras[camera_name].motion
if payload == "ON":
- if not self.camera_metrics[camera_name]["improve_contrast_enabled"].value:
+ if not motion_settings.improve_contrast:
logger.info(f"Turning on improve contrast for {camera_name}")
- self.camera_metrics[camera_name][
- "improve_contrast_enabled"
- ].value = True
motion_settings.improve_contrast = True # type: ignore[union-attr]
elif payload == "OFF":
- if self.camera_metrics[camera_name]["improve_contrast_enabled"].value:
+ if motion_settings.improve_contrast:
logger.info(f"Turning off improve contrast for {camera_name}")
- self.camera_metrics[camera_name][
- "improve_contrast_enabled"
- ].value = False
motion_settings.improve_contrast = False # type: ignore[union-attr]
+ self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
self.publish(f"{camera_name}/improve_contrast/state", payload, retain=True)
def _on_ptz_autotracker_command(self, camera_name: str, payload: str) -> None:
@@ -218,8 +232,8 @@ class Dispatcher:
motion_settings = self.config.cameras[camera_name].motion
logger.info(f"Setting motion contour area for {camera_name}: {payload}")
- self.camera_metrics[camera_name]["motion_contour_area"].value = payload
motion_settings.contour_area = payload # type: ignore[union-attr]
+ self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
self.publish(f"{camera_name}/motion_contour_area/state", payload, retain=True)
def _on_motion_threshold_command(self, camera_name: str, payload: int) -> None:
@@ -232,8 +246,8 @@ class Dispatcher:
motion_settings = self.config.cameras[camera_name].motion
logger.info(f"Setting motion threshold for {camera_name}: {payload}")
- self.camera_metrics[camera_name]["motion_threshold"].value = payload
motion_settings.threshold = payload # type: ignore[union-attr]
+ self.config_updater.publish(f"config/motion/{camera_name}", motion_settings)
self.publish(f"{camera_name}/motion_threshold/state", payload, retain=True)
def _on_audio_command(self, camera_name: str, payload: str) -> None:
@@ -250,13 +264,12 @@ class Dispatcher:
if not audio_settings.enabled:
logger.info(f"Turning on audio detection for {camera_name}")
audio_settings.enabled = True
- self.feature_metrics[camera_name]["audio_enabled"].value = True
elif payload == "OFF":
- if self.feature_metrics[camera_name]["audio_enabled"].value:
+ if audio_settings.enabled:
logger.info(f"Turning off audio detection for {camera_name}")
audio_settings.enabled = False
- self.feature_metrics[camera_name]["audio_enabled"].value = False
+ self.config_updater.publish(f"config/audio/{camera_name}", audio_settings)
self.publish(f"{camera_name}/audio/state", payload, retain=True)
def _on_recordings_command(self, camera_name: str, payload: str) -> None:
@@ -273,13 +286,12 @@ class Dispatcher:
if not record_settings.enabled:
logger.info(f"Turning on recordings for {camera_name}")
record_settings.enabled = True
- self.feature_metrics[camera_name]["record_enabled"].value = True
elif payload == "OFF":
- if self.feature_metrics[camera_name]["record_enabled"].value:
+ if record_settings.enabled:
logger.info(f"Turning off recordings for {camera_name}")
record_settings.enabled = False
- self.feature_metrics[camera_name]["record_enabled"].value = False
+ self.config_updater.publish(f"config/record/{camera_name}", record_settings)
self.publish(f"{camera_name}/recordings/state", payload, retain=True)
def _on_snapshots_command(self, camera_name: str, payload: str) -> None:
@@ -317,17 +329,16 @@ class Dispatcher:
birdseye_settings = self.config.cameras[camera_name].birdseye
if payload == "ON":
- if not self.camera_metrics[camera_name]["birdseye_enabled"].value:
+ if not birdseye_settings.enabled:
logger.info(f"Turning on birdseye for {camera_name}")
- self.camera_metrics[camera_name]["birdseye_enabled"].value = True
birdseye_settings.enabled = True
elif payload == "OFF":
- if self.camera_metrics[camera_name]["birdseye_enabled"].value:
+ if birdseye_settings.enabled:
logger.info(f"Turning off birdseye for {camera_name}")
- self.camera_metrics[camera_name]["birdseye_enabled"].value = False
birdseye_settings.enabled = False
+ self.config_updater.publish(f"config/birdseye/{camera_name}", birdseye_settings)
self.publish(f"{camera_name}/birdseye/state", payload, retain=True)
def _on_birdseye_mode_command(self, camera_name: str, payload: str) -> None:
@@ -337,17 +348,16 @@ class Dispatcher:
logger.info(f"Invalid birdseye_mode command: {payload}")
return
- birdseye_config = self.config.cameras[camera_name].birdseye
- if not birdseye_config.enabled:
+ birdseye_settings = self.config.cameras[camera_name].birdseye
+
+ if not birdseye_settings.enabled:
logger.info(f"Birdseye mode not enabled for {camera_name}")
return
- new_birdseye_mode = BirdseyeModeEnum(payload.lower())
- logger.info(f"Setting birdseye mode for {camera_name} to {new_birdseye_mode}")
-
- # update the metric (need the mode converted to an int)
- self.camera_metrics[camera_name][
- "birdseye_mode"
- ].value = BirdseyeModeEnum.get_index(new_birdseye_mode)
+ birdseye_settings.mode = BirdseyeModeEnum(payload.lower())
+ logger.info(
+ f"Setting birdseye mode for {camera_name} to {birdseye_settings.mode}"
+ )
+ self.config_updater.publish(f"config/birdseye/{camera_name}", birdseye_settings)
self.publish(f"{camera_name}/birdseye_mode/state", payload, retain=True)
diff --git a/frigate/comms/inter_process.py b/frigate/comms/inter_process.py
index 74ce9bc0c..deec77a40 100644
--- a/frigate/comms/inter_process.py
+++ b/frigate/comms/inter_process.py
@@ -1,16 +1,22 @@
+"""Facilitates communication between processes."""
+
import multiprocessing as mp
-import queue
import threading
-from multiprocessing import Queue
from multiprocessing.synchronize import Event as MpEvent
from typing import Callable
+import zmq
+
from frigate.comms.dispatcher import Communicator
+SOCKET_REP_REQ = "ipc:///tmp/cache/comms"
+
class InterProcessCommunicator(Communicator):
- def __init__(self, queue: Queue) -> None:
- self.queue = queue
+ def __init__(self) -> None:
+ self.context = zmq.Context()
+ self.socket = self.context.socket(zmq.REP)
+ self.socket.bind(SOCKET_REP_REQ)
self.stop_event: MpEvent = mp.Event()
def publish(self, topic: str, payload: str, retain: bool) -> None:
@@ -24,16 +30,44 @@ class InterProcessCommunicator(Communicator):
def read(self) -> None:
while not self.stop_event.is_set():
- try:
- (
- topic,
- value,
- ) = self.queue.get(True, 1)
- except queue.Empty:
- continue
+ while True: # load all messages that are queued
+ has_message, _, _ = zmq.select([self.socket], [], [], 1)
- self._dispatcher(topic, value)
+ if not has_message:
+ break
+
+ try:
+ (topic, value) = self.socket.recv_pyobj(flags=zmq.NOBLOCK)
+
+ response = self._dispatcher(topic, value)
+
+ if response is not None:
+ self.socket.send_pyobj(response)
+ else:
+ self.socket.send_pyobj([])
+ except zmq.ZMQError:
+ break
def stop(self) -> None:
self.stop_event.set()
self.reader_thread.join()
+ self.socket.close()
+ self.context.destroy()
+
+
+class InterProcessRequestor:
+ """Simplifies sending data to InterProcessCommunicator and getting a reply."""
+
+ def __init__(self) -> None:
+ self.context = zmq.Context()
+ self.socket = self.context.socket(zmq.REQ)
+ self.socket.connect(SOCKET_REP_REQ)
+
+ def send_data(self, topic: str, data: any) -> any:
+ """Sends data and then waits for reply."""
+ self.socket.send_pyobj((topic, data))
+ return self.socket.recv_pyobj()
+
+ def stop(self) -> None:
+ self.socket.close()
+ self.context.destroy()
diff --git a/frigate/comms/mqtt.py b/frigate/comms/mqtt.py
index 6182c89e3..b83484d41 100644
--- a/frigate/comms/mqtt.py
+++ b/frigate/comms/mqtt.py
@@ -3,6 +3,7 @@ import threading
from typing import Any, Callable
import paho.mqtt.client as mqtt
+from paho.mqtt.enums import CallbackAPIVersion
from frigate.comms.dispatcher import Communicator
from frigate.config import FrigateConfig
@@ -96,9 +97,11 @@ class MqttClient(Communicator): # type: ignore[misc]
)
self.publish(
f"{camera_name}/birdseye_mode/state",
- camera.birdseye.mode.value.upper()
- if camera.birdseye.enabled
- else "OFF",
+ (
+ camera.birdseye.mode.value.upper()
+ if camera.birdseye.enabled
+ else "OFF"
+ ),
retain=True,
)
@@ -117,25 +120,26 @@ class MqttClient(Communicator): # type: ignore[misc]
client: mqtt.Client,
userdata: Any,
flags: Any,
- rc: mqtt.ReasonCodes,
+ reason_code: mqtt.ReasonCode,
+ properties: Any,
) -> None:
"""Mqtt connection callback."""
threading.current_thread().name = "mqtt"
- if rc != 0:
- if rc == 3:
+ if reason_code != 0:
+ if reason_code == "Server Unavailable":
logger.error(
"Unable to connect to MQTT server: MQTT Server unavailable"
)
- elif rc == 4:
+ elif reason_code == "Bad user name or password":
logger.error(
"Unable to connect to MQTT server: MQTT Bad username or password"
)
- elif rc == 5:
+ elif reason_code == "Not authorized":
logger.error("Unable to connect to MQTT server: MQTT Not authorized")
else:
logger.error(
"Unable to connect to MQTT server: Connection refused. Error code: "
- + str(rc)
+ + reason_code.getName()
)
self.connected = True
@@ -144,7 +148,12 @@ class MqttClient(Communicator): # type: ignore[misc]
self._set_initial_topics()
def _on_disconnect(
- self, client: mqtt.Client, userdata: Any, flags: Any, rc: mqtt
+ self,
+ client: mqtt.Client,
+ userdata: Any,
+ flags: Any,
+ reason_code: mqtt.ReasonCode,
+ properties: Any,
) -> None:
"""Mqtt disconnection callback."""
self.connected = False
@@ -152,7 +161,10 @@ class MqttClient(Communicator): # type: ignore[misc]
def _start(self) -> None:
"""Start mqtt client."""
- self.client = mqtt.Client(client_id=self.mqtt_config.client_id)
+ self.client = mqtt.Client(
+ callback_api_version=CallbackAPIVersion.VERSION2,
+ client_id=self.mqtt_config.client_id,
+ )
self.client.on_connect = self._on_connect
self.client.will_set(
self.mqtt_config.topic_prefix + "/available",
diff --git a/frigate/comms/ws.py b/frigate/comms/ws.py
index 98f24cf28..fccd8db5c 100644
--- a/frigate/comms/ws.py
+++ b/frigate/comms/ws.py
@@ -38,6 +38,7 @@ class WebSocketClient(Communicator): # type: ignore[misc]
def __init__(self, config: FrigateConfig) -> None:
self.config = config
+ self.websocket_server = None
def subscribe(self, receiver: Callable) -> None:
self._dispatcher = receiver
@@ -98,6 +99,10 @@ class WebSocketClient(Communicator): # type: ignore[misc]
logger.debug(f"payload for {topic} wasn't text. Skipping...")
return
+ if self.websocket_server is None:
+ logger.debug("Skipping message, websocket not connected yet")
+ return
+
try:
self.websocket_server.manager.broadcast(ws_message)
except ConnectionResetError:
diff --git a/frigate/config.py b/frigate/config.py
index 9373cbcaf..e48475ec6 100644
--- a/frigate/config.py
+++ b/frigate/config.py
@@ -6,11 +6,19 @@ import logging
import os
from enum import Enum
from pathlib import Path
-from typing import Dict, List, Optional, Tuple, Union
+from typing import Any, Dict, List, Optional, Tuple, Union
import matplotlib.pyplot as plt
import numpy as np
-from pydantic import BaseModel, Extra, Field, parse_obj_as, validator
+from pydantic import (
+ BaseModel,
+ ConfigDict,
+ Field,
+ TypeAdapter,
+ ValidationInfo,
+ field_serializer,
+ field_validator,
+)
from pydantic.fields import PrivateAttr
from frigate.const import (
@@ -50,7 +58,7 @@ DEFAULT_TIME_FORMAT = "%m/%d/%Y %H:%M:%S"
FRIGATE_ENV_VARS = {k: v for k, v in os.environ.items() if k.startswith("FRIGATE_")}
# read docker secret files as env vars too
-if os.path.isdir("/run/secrets"):
+if os.path.isdir("/run/secrets") and os.access("/run/secrets", os.R_OK):
for secret_file in os.listdir("/run/secrets"):
if secret_file.startswith("FRIGATE_"):
FRIGATE_ENV_VARS[secret_file] = Path(
@@ -58,6 +66,7 @@ if os.path.isdir("/run/secrets"):
).read_text()
DEFAULT_TRACKED_OBJECTS = ["person"]
+DEFAULT_ALERT_OBJECTS = ["person", "car"]
DEFAULT_LISTEN_AUDIO = ["bark", "fire_alarm", "scream", "speech", "yell"]
DEFAULT_DETECTORS = {"cpu": {"type": "cpu"}}
DEFAULT_DETECT_DIMENSIONS = {"width": 1280, "height": 720}
@@ -65,8 +74,7 @@ DEFAULT_TIME_LAPSE_FFMPEG_ARGS = "-vf setpts=0.04*PTS -r 30"
class FrigateBaseModel(BaseModel):
- class Config:
- extra = Extra.forbid
+ model_config = ConfigDict(extra="forbid", protected_namespaces=())
class LiveModeEnum(str, Enum):
@@ -92,7 +100,7 @@ class UIConfig(FrigateBaseModel):
live_mode: LiveModeEnum = Field(
default=LiveModeEnum.mse, title="Default Live Mode."
)
- timezone: Optional[str] = Field(title="Override UI timezone.")
+ timezone: Optional[str] = Field(default=None, title="Override UI timezone.")
use_experimental: bool = Field(default=False, title="Experimental UI")
time_format: TimeFormatEnum = Field(
default=TimeFormatEnum.browser, title="Override UI time format."
@@ -134,16 +142,17 @@ class MqttConfig(FrigateBaseModel):
topic_prefix: str = Field(default="frigate", title="MQTT Topic Prefix")
client_id: str = Field(default="frigate", title="MQTT Client ID")
stats_interval: int = Field(default=60, title="MQTT Camera Stats Interval")
- user: Optional[str] = Field(title="MQTT Username")
- password: Optional[str] = Field(title="MQTT Password")
- tls_ca_certs: Optional[str] = Field(title="MQTT TLS CA Certificates")
- tls_client_cert: Optional[str] = Field(title="MQTT TLS Client Certificate")
- tls_client_key: Optional[str] = Field(title="MQTT TLS Client Key")
- tls_insecure: Optional[bool] = Field(title="MQTT TLS Insecure")
+ user: Optional[str] = Field(None, title="MQTT Username")
+ password: Optional[str] = Field(None, title="MQTT Password", validate_default=True)
+ tls_ca_certs: Optional[str] = Field(None, title="MQTT TLS CA Certificates")
+ tls_client_cert: Optional[str] = Field(None, title="MQTT TLS Client Certificate")
+ tls_client_key: Optional[str] = Field(None, title="MQTT TLS Client Key")
+ tls_insecure: Optional[bool] = Field(None, title="MQTT TLS Insecure")
- @validator("password", pre=True, always=True)
- def validate_password(cls, v, values):
- if (v is None) != (values["user"] is None):
+ @field_validator("password")
+ def user_requires_pass(cls, v, info: ValidationInfo):
+ print(f"doing a check where {v} is None and {info.data['user']} is None")
+ if (v is None) != (info.data["user"] is None):
raise ValueError("Password must be provided with username.")
return v
@@ -185,18 +194,19 @@ class PtzAutotrackConfig(FrigateBaseModel):
title="Internal value used for PTZ movements based on the speed of your camera's motor.",
)
enabled_in_config: Optional[bool] = Field(
- title="Keep track of original state of autotracking."
+ None, title="Keep track of original state of autotracking."
)
- @validator("movement_weights", pre=True)
+ @field_validator("movement_weights", mode="before")
+ @classmethod
def validate_weights(cls, v):
if v is None:
return None
if isinstance(v, str):
- weights = list(map(float, v.split(",")))
+ weights = list(map(str, map(float, v.split(","))))
elif isinstance(v, list):
- weights = [float(val) for val in v]
+ weights = [str(float(val)) for val in v]
else:
raise ValueError("Invalid type for movement_weights")
@@ -209,8 +219,8 @@ class PtzAutotrackConfig(FrigateBaseModel):
class OnvifConfig(FrigateBaseModel):
host: str = Field(default="", title="Onvif Host")
port: int = Field(default=8000, title="Onvif Port")
- user: Optional[str] = Field(title="Onvif Username")
- password: Optional[str] = Field(title="Onvif Password")
+ user: Optional[str] = Field(None, title="Onvif Username")
+ password: Optional[str] = Field(None, title="Onvif Password")
autotracking: PtzAutotrackConfig = Field(
default_factory=PtzAutotrackConfig,
title="PTZ auto tracking config.",
@@ -241,6 +251,7 @@ class EventsConfig(FrigateBaseModel):
title="List of required zones to be entered in order to save the event.",
)
objects: Optional[List[str]] = Field(
+ None,
title="List of objects to be detected in order to save the event.",
)
retain: RetainConfig = Field(
@@ -295,11 +306,12 @@ class RecordConfig(FrigateBaseModel):
default_factory=RecordPreviewConfig, title="Recording Preview Config"
)
enabled_in_config: Optional[bool] = Field(
- title="Keep track of original state of recording."
+ None, title="Keep track of original state of recording."
)
class MotionConfig(FrigateBaseModel):
+ enabled: bool = Field(default=True, title="Enable motion on all cameras.")
threshold: int = Field(
default=30,
title="Motion detection threshold (1-255).",
@@ -321,6 +333,18 @@ class MotionConfig(FrigateBaseModel):
default=30,
title="Delay for updating MQTT with no motion detected.",
)
+ enabled_in_config: Optional[bool] = Field(
+ None, title="Keep track of original state of motion detection."
+ )
+ raw_mask: Union[str, List[str]] = ""
+
+ @field_serializer("mask", when_used="json")
+ def serialize_mask(self, value: Any, info):
+ return self.raw_mask
+
+ @field_serializer("raw_mask", when_used="json")
+ def serialize_raw_mask(self, value: Any, info):
+ return None
class RuntimeMotionConfig(MotionConfig):
@@ -343,19 +367,25 @@ class RuntimeMotionConfig(MotionConfig):
super().__init__(**config)
def dict(self, **kwargs):
- ret = super().dict(**kwargs)
+ ret = super().model_dump(**kwargs)
if "mask" in ret:
ret["mask"] = ret["raw_mask"]
ret.pop("raw_mask")
return ret
- class Config:
- arbitrary_types_allowed = True
- extra = Extra.ignore
+ @field_serializer("mask", when_used="json")
+ def serialize_mask(self, value: Any, info):
+ return self.raw_mask
+
+ @field_serializer("raw_mask", when_used="json")
+ def serialize_raw_mask(self, value: Any, info):
+ return None
+
+ model_config = ConfigDict(arbitrary_types_allowed=True, extra="ignore")
class StationaryMaxFramesConfig(FrigateBaseModel):
- default: Optional[int] = Field(title="Default max frames.", ge=1)
+ default: Optional[int] = Field(None, title="Default max frames.", ge=1)
objects: Dict[str, int] = Field(
default_factory=dict, title="Object specific max frames."
)
@@ -363,10 +393,12 @@ class StationaryMaxFramesConfig(FrigateBaseModel):
class StationaryConfig(FrigateBaseModel):
interval: Optional[int] = Field(
+ None,
title="Frame interval for checking stationary objects.",
gt=0,
)
threshold: Optional[int] = Field(
+ None,
title="Number of frames without a position change for an object to be considered stationary",
ge=1,
)
@@ -377,17 +409,21 @@ class StationaryConfig(FrigateBaseModel):
class DetectConfig(FrigateBaseModel):
- height: Optional[int] = Field(title="Height of the stream for the detect role.")
- width: Optional[int] = Field(title="Width of the stream for the detect role.")
+ height: Optional[int] = Field(
+ None, title="Height of the stream for the detect role."
+ )
+ width: Optional[int] = Field(None, title="Width of the stream for the detect role.")
fps: int = Field(
default=5, title="Number of frames per second to process through detection."
)
enabled: bool = Field(default=True, title="Detection Enabled.")
min_initialized: Optional[int] = Field(
- title="Minimum number of consecutive hits for an object to be initialized by the tracker."
+ None,
+ title="Minimum number of consecutive hits for an object to be initialized by the tracker.",
)
max_disappeared: Optional[int] = Field(
- title="Maximum number of frames the object can dissapear before detection ends."
+ None,
+ title="Maximum number of frames the object can dissapear before detection ends.",
)
stationary: StationaryConfig = Field(
default_factory=StationaryConfig,
@@ -421,8 +457,18 @@ class FilterConfig(FrigateBaseModel):
default=0.5, title="Minimum detection confidence for object to be counted."
)
mask: Optional[Union[str, List[str]]] = Field(
+ None,
title="Detection area polygon mask for this filter configuration.",
)
+ raw_mask: Union[str, List[str]] = ""
+
+ @field_serializer("mask", when_used="json")
+ def serialize_mask(self, value: Any, info):
+ return self.raw_mask
+
+ @field_serializer("raw_mask", when_used="json")
+ def serialize_raw_mask(self, value: Any, info):
+ return None
class AudioFilterConfig(FrigateBaseModel):
@@ -435,8 +481,8 @@ class AudioFilterConfig(FrigateBaseModel):
class RuntimeFilterConfig(FilterConfig):
- mask: Optional[np.ndarray]
- raw_mask: Optional[Union[str, List[str]]]
+ mask: Optional[np.ndarray] = None
+ raw_mask: Optional[Union[str, List[str]]] = None
def __init__(self, **config):
mask = config.get("mask")
@@ -448,15 +494,13 @@ class RuntimeFilterConfig(FilterConfig):
super().__init__(**config)
def dict(self, **kwargs):
- ret = super().dict(**kwargs)
+ ret = super().model_dump(**kwargs)
if "mask" in ret:
ret["mask"] = ret["raw_mask"]
ret.pop("raw_mask")
return ret
- class Config:
- arbitrary_types_allowed = True
- extra = Extra.ignore
+ model_config = ConfigDict(arbitrary_types_allowed=True, extra="ignore")
# this uses the base model because the color is an extra attribute
@@ -508,6 +552,9 @@ class ZoneConfig(BaseModel):
class ObjectConfig(FrigateBaseModel):
track: List[str] = Field(default=DEFAULT_TRACKED_OBJECTS, title="Objects to track.")
+ alert: List[str] = Field(
+ default=DEFAULT_ALERT_OBJECTS, title="Objects to create alerts for."
+ )
filters: Dict[str, FilterConfig] = Field(default={}, title="Object filters.")
mask: Union[str, List[str]] = Field(default="", title="Object mask.")
@@ -523,9 +570,11 @@ class AudioConfig(FrigateBaseModel):
listen: List[str] = Field(
default=DEFAULT_LISTEN_AUDIO, title="Audio to listen for."
)
- filters: Optional[Dict[str, AudioFilterConfig]] = Field(title="Audio filters.")
+ filters: Optional[Dict[str, AudioFilterConfig]] = Field(
+ None, title="Audio filters."
+ )
enabled_in_config: Optional[bool] = Field(
- title="Keep track of original state of audio detection."
+ None, title="Keep track of original state of audio detection."
)
num_threads: int = Field(default=2, title="Number of detection threads", ge=1)
@@ -544,6 +593,13 @@ class BirdseyeModeEnum(str, Enum):
return list(cls)[index]
+class BirdseyeLayoutConfig(FrigateBaseModel):
+ scaling_factor: float = Field(
+ default=2.0, title="Birdseye Scaling Factor", ge=1.0, le=5.0
+ )
+ max_cameras: Optional[int] = Field(default=None, title="Max cameras")
+
+
class BirdseyeConfig(FrigateBaseModel):
enabled: bool = Field(default=True, title="Enable birdseye view.")
restream: bool = Field(default=False, title="Restream birdseye via RTSP.")
@@ -555,9 +611,15 @@ class BirdseyeConfig(FrigateBaseModel):
ge=1,
le=31,
)
+ inactivity_threshold: int = Field(
+ default=30, title="Birdseye Inactivity Threshold", gt=0
+ )
mode: BirdseyeModeEnum = Field(
default=BirdseyeModeEnum.objects, title="Tracking mode."
)
+ layout: BirdseyeLayoutConfig = Field(
+ default_factory=BirdseyeLayoutConfig, title="Birdseye Layout Config"
+ )
# uses BaseModel because some global attributes are not available at the camera level
@@ -593,6 +655,7 @@ class FfmpegOutputArgsConfig(FrigateBaseModel):
default=RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT,
title="Record role FFmpeg output arguments.",
)
+ _force_record_hvc1: bool = PrivateAttr(default=False)
class FfmpegConfig(FrigateBaseModel):
@@ -638,7 +701,8 @@ class CameraInput(FrigateBaseModel):
class CameraFfmpegConfig(FfmpegConfig):
inputs: List[CameraInput] = Field(title="Camera inputs.")
- @validator("inputs")
+ @field_validator("inputs")
+ @classmethod
def validate_roles(cls, v):
roles = [role for i in v for role in i.roles]
roles_set = set(roles)
@@ -668,7 +732,7 @@ class SnapshotsConfig(FrigateBaseModel):
default_factory=list,
title="List of required zones to be entered in order to save a snapshot.",
)
- height: Optional[int] = Field(title="Snapshot image height.")
+ height: Optional[int] = Field(None, title="Snapshot image height.")
retain: RetainConfig = Field(
default_factory=RetainConfig, title="Snapshot retention."
)
@@ -705,7 +769,7 @@ class TimestampStyleConfig(FrigateBaseModel):
format: str = Field(default=DEFAULT_TIME_FORMAT, title="Timestamp format.")
color: ColorConfig = Field(default_factory=ColorConfig, title="Timestamp color.")
thickness: int = Field(default=2, title="Timestamp thickness.")
- effect: Optional[TimestampEffectEnum] = Field(title="Timestamp effect.")
+ effect: Optional[TimestampEffectEnum] = Field(None, title="Timestamp effect.")
class CameraMqttConfig(FrigateBaseModel):
@@ -733,8 +797,7 @@ class CameraLiveConfig(FrigateBaseModel):
class RestreamConfig(BaseModel):
- class Config:
- extra = Extra.allow
+ model_config = ConfigDict(extra="allow")
class CameraUiConfig(FrigateBaseModel):
@@ -745,7 +808,7 @@ class CameraUiConfig(FrigateBaseModel):
class CameraConfig(FrigateBaseModel):
- name: Optional[str] = Field(title="Camera name.", regex=REGEX_CAMERA_NAME)
+ name: Optional[str] = Field(None, title="Camera name.", pattern=REGEX_CAMERA_NAME)
enabled: bool = Field(default=True, title="Enable camera.")
ffmpeg: CameraFfmpegConfig = Field(title="FFmpeg configuration for the camera.")
best_image_timeout: int = Field(
@@ -753,6 +816,7 @@ class CameraConfig(FrigateBaseModel):
title="How long to wait for the image with the highest confidence score.",
)
webui_url: Optional[str] = Field(
+ None,
title="URL to visit the camera directly from system page",
)
zones: Dict[str, ZoneConfig] = Field(
@@ -776,7 +840,9 @@ class CameraConfig(FrigateBaseModel):
audio: AudioConfig = Field(
default_factory=AudioConfig, title="Audio events configuration."
)
- motion: Optional[MotionConfig] = Field(title="Motion detection configuration.")
+ motion: Optional[MotionConfig] = Field(
+ None, title="Motion detection configuration."
+ )
detect: DetectConfig = Field(
default_factory=DetectConfig, title="Object detection configuration."
)
@@ -857,7 +923,10 @@ class CameraConfig(FrigateBaseModel):
if "record" in ffmpeg_input.roles and self.record.enabled:
record_args = get_ffmpeg_arg_list(
- parse_preset_output_record(self.ffmpeg.output_args.record)
+ parse_preset_output_record(
+ self.ffmpeg.output_args.record,
+ self.ffmpeg.output_args._force_record_hvc1,
+ )
or self.ffmpeg.output_args.record
)
@@ -874,6 +943,10 @@ class CameraConfig(FrigateBaseModel):
global_args = get_ffmpeg_arg_list(
ffmpeg_input.global_args or self.ffmpeg.global_args
)
+
+ camera_arg = (
+ self.ffmpeg.hwaccel_args if self.ffmpeg.hwaccel_args != "auto" else None
+ )
hwaccel_args = get_ffmpeg_arg_list(
parse_preset_hardware_acceleration_decode(
ffmpeg_input.hwaccel_args,
@@ -883,12 +956,13 @@ class CameraConfig(FrigateBaseModel):
)
or ffmpeg_input.hwaccel_args
or parse_preset_hardware_acceleration_decode(
- self.ffmpeg.hwaccel_args,
+ camera_arg,
self.detect.fps,
self.detect.width,
self.detect.height,
)
- or self.ffmpeg.hwaccel_args
+ or camera_arg
+ or []
)
input_args = get_ffmpeg_arg_list(
parse_preset_input(ffmpeg_input.input_args, self.detect.fps)
@@ -953,7 +1027,7 @@ def verify_valid_live_stream_name(
"""Verify that a restream exists to use for live view."""
if (
camera_config.live.stream_name
- not in frigate_config.go2rtc.dict().get("streams", {}).keys()
+ not in frigate_config.go2rtc.model_dump().get("streams", {}).keys()
):
return ValueError(
f"No restream with name {camera_config.live.stream_name} exists for camera {camera_config.name}."
@@ -1023,6 +1097,14 @@ def verify_autotrack_zones(camera_config: CameraConfig) -> ValueError | None:
)
+def verify_motion_and_detect(camera_config: CameraConfig) -> ValueError | None:
+ """Verify that required_zones are specified when autotracking is enabled."""
+ if camera_config.detect.enabled and not camera_config.motion.enabled:
+ raise ValueError(
+ f"Camera {camera_config.name} has motion detection disabled and object detection enabled but object detection requires motion detection."
+ )
+
+
class FrigateConfig(FrigateBaseModel):
mqtt: MqttConfig = Field(title="MQTT Configuration.")
database: DatabaseConfig = Field(
@@ -1070,7 +1152,7 @@ class FrigateConfig(FrigateBaseModel):
default_factory=AudioConfig, title="Global Audio events configuration."
)
motion: Optional[MotionConfig] = Field(
- title="Global motion detection configuration."
+ None, title="Global motion detection configuration."
)
detect: DetectConfig = Field(
default_factory=DetectConfig, title="Global object tracking configuration."
@@ -1083,7 +1165,7 @@ class FrigateConfig(FrigateBaseModel):
def runtime_config(self, plus_api: PlusApi = None) -> FrigateConfig:
"""Merge camera config with globals."""
- config = self.copy(deep=True)
+ config = self.model_copy(deep=True)
# MQTT user/password substitutions
if config.mqtt.user or config.mqtt.password:
@@ -1102,7 +1184,7 @@ class FrigateConfig(FrigateBaseModel):
config.ffmpeg.hwaccel_args = auto_detect_hwaccel()
# Global config to propagate down to camera level
- global_config = config.dict(
+ global_config = config.model_dump(
include={
"audio": ...,
"birdseye": ...,
@@ -1119,42 +1201,55 @@ class FrigateConfig(FrigateBaseModel):
)
for name, camera in config.cameras.items():
- merged_config = deep_merge(camera.dict(exclude_unset=True), global_config)
- camera_config: CameraConfig = CameraConfig.parse_obj(
+ merged_config = deep_merge(
+ camera.model_dump(exclude_unset=True), global_config
+ )
+ camera_config: CameraConfig = CameraConfig.model_validate(
{"name": name, **merged_config}
)
if camera_config.ffmpeg.hwaccel_args == "auto":
camera_config.ffmpeg.hwaccel_args = config.ffmpeg.hwaccel_args
- if (
- camera_config.detect.height is None
- or camera_config.detect.width is None
- ):
- for input in camera_config.ffmpeg.inputs:
- if "detect" in input.roles:
- stream_info = {"width": 0, "height": 0}
- try:
- stream_info = asyncio.run(get_video_properties(input.path))
- except Exception:
- logger.warn(
- f"Error detecting stream resolution automatically for {input.path} Applying default values."
- )
- stream_info = {"width": 0, "height": 0}
+ for input in camera_config.ffmpeg.inputs:
+ need_record_fourcc = "record" in input.roles
+ need_detect_dimensions = "detect" in input.roles and (
+ camera_config.detect.height is None
+ or camera_config.detect.width is None
+ )
- camera_config.detect.width = (
- stream_info["width"]
- if stream_info.get("width")
- else DEFAULT_DETECT_DIMENSIONS["width"]
- )
- camera_config.detect.height = (
- stream_info["height"]
- if stream_info.get("height")
- else DEFAULT_DETECT_DIMENSIONS["height"]
+ if need_detect_dimensions or need_record_fourcc:
+ stream_info = {"width": 0, "height": 0, "fourcc": None}
+ try:
+ stream_info = asyncio.run(get_video_properties(input.path))
+ except Exception:
+ logger.warn(
+ f"Error detecting stream parameters automatically for {input.path} Applying default values."
)
+ stream_info = {"width": 0, "height": 0, "fourcc": None}
+
+ if need_detect_dimensions:
+ camera_config.detect.width = (
+ stream_info["width"]
+ if stream_info.get("width")
+ else DEFAULT_DETECT_DIMENSIONS["width"]
+ )
+ camera_config.detect.height = (
+ stream_info["height"]
+ if stream_info.get("height")
+ else DEFAULT_DETECT_DIMENSIONS["height"]
+ )
+
+ if need_record_fourcc:
+ # Apple only supports HEVC if it is hvc1 (vs. hev1)
+ camera_config.ffmpeg.output_args._force_record_hvc1 = (
+ stream_info["fourcc"] == "hevc"
+ if stream_info.get("hevc")
+ else False
+ )
# Default min_initialized configuration
- min_initialized = camera_config.detect.fps / 2
+ min_initialized = int(camera_config.detect.fps / 2)
if camera_config.detect.min_initialized is None:
camera_config.detect.min_initialized = min_initialized
@@ -1184,8 +1279,8 @@ class FrigateConfig(FrigateBaseModel):
**FRIGATE_ENV_VARS
)
# set config pre-value
- camera_config.record.enabled_in_config = camera_config.record.enabled
camera_config.audio.enabled_in_config = camera_config.audio.enabled
+ camera_config.record.enabled_in_config = camera_config.record.enabled
camera_config.onvif.autotracking.enabled_in_config = (
camera_config.onvif.autotracking.enabled
)
@@ -1218,7 +1313,7 @@ class FrigateConfig(FrigateBaseModel):
# Set runtime filter to create masks
camera_config.objects.filters[object] = RuntimeFilterConfig(
frame_shape=camera_config.frame_shape,
- **filter.dict(exclude_unset=True),
+ **filter.model_dump(exclude_unset=True),
)
# Convert motion configuration
@@ -1230,8 +1325,9 @@ class FrigateConfig(FrigateBaseModel):
camera_config.motion = RuntimeMotionConfig(
frame_shape=camera_config.frame_shape,
raw_mask=camera_config.motion.mask,
- **camera_config.motion.dict(exclude_unset=True),
+ **camera_config.motion.model_dump(exclude_unset=True),
)
+ camera_config.motion.enabled_in_config = camera_config.motion.enabled
# Set live view stream if none is set
if not camera_config.live.stream_name:
@@ -1243,6 +1339,7 @@ class FrigateConfig(FrigateBaseModel):
verify_recording_segments_setup_with_reasonable_time(camera_config)
verify_zone_objects_are_tracked(camera_config)
verify_autotrack_zones(camera_config)
+ verify_motion_and_detect(camera_config)
# generate the ffmpeg commands
camera_config.create_ffmpeg_cmds()
@@ -1258,17 +1355,21 @@ class FrigateConfig(FrigateBaseModel):
config.model.check_and_load_plus_model(plus_api)
for key, detector in config.detectors.items():
- detector_config: DetectorConfig = parse_obj_as(DetectorConfig, detector)
+ adapter = TypeAdapter(DetectorConfig)
+ model_dict = (
+ detector if isinstance(detector, dict) else detector.model_dump()
+ )
+ detector_config: DetectorConfig = adapter.validate_python(model_dict)
if detector_config.model is None:
detector_config.model = config.model
else:
model = detector_config.model
- schema = ModelConfig.schema()["properties"]
+ schema = ModelConfig.model_json_schema()["properties"]
if (
model.width != schema["width"]["default"]
or model.height != schema["height"]["default"]
or model.labelmap_path is not None
- or model.labelmap is not {}
+ or model.labelmap
or model.input_tensor != schema["input_tensor"]["default"]
or model.input_pixel_format
!= schema["input_pixel_format"]["default"]
@@ -1277,8 +1378,8 @@ class FrigateConfig(FrigateBaseModel):
"Customizing more than a detector model path is unsupported."
)
merged_model = deep_merge(
- detector_config.model.dict(exclude_unset=True),
- config.model.dict(exclude_unset=True),
+ detector_config.model.model_dump(exclude_unset=True),
+ config.model.model_dump(exclude_unset=True),
)
if "path" not in merged_model:
@@ -1287,7 +1388,7 @@ class FrigateConfig(FrigateBaseModel):
elif detector_config.type == "edgetpu":
merged_model["path"] = "/edgetpu_model.tflite"
- detector_config.model = ModelConfig.parse_obj(merged_model)
+ detector_config.model = ModelConfig.model_validate(merged_model)
detector_config.model.check_and_load_plus_model(
plus_api, detector_config.type
)
@@ -1296,7 +1397,8 @@ class FrigateConfig(FrigateBaseModel):
return config
- @validator("cameras")
+ @field_validator("cameras")
+ @classmethod
def ensure_zones_and_cameras_have_different_names(cls, v: Dict[str, CameraConfig]):
zones = [zone for camera in v.values() for zone in camera.zones.keys()]
for zone in zones:
@@ -1314,9 +1416,9 @@ class FrigateConfig(FrigateBaseModel):
elif config_file.endswith(".json"):
config = json.loads(raw_config)
- return cls.parse_obj(config)
+ return cls.model_validate(config)
@classmethod
def parse_raw(cls, raw_config):
config = load_config_with_no_duplicates(raw_config)
- return cls.parse_obj(config)
+ return cls.model_validate(config)
diff --git a/frigate/const.py b/frigate/const.py
index 97e33b689..62a202c37 100644
--- a/frigate/const.py
+++ b/frigate/const.py
@@ -26,6 +26,10 @@ LABEL_CONSOLIDATION_MAP = {
"face": 0.5,
}
LABEL_CONSOLIDATION_DEFAULT = 0.9
+LABEL_NMS_MAP = {
+ "car": 0.6,
+}
+LABEL_NMS_DEFAULT = 0.4
# Audio Consts
@@ -66,6 +70,7 @@ MAX_PLAYLIST_SECONDS = 7200 # support 2 hour segments for a single playlist to
INSERT_MANY_RECORDINGS = "insert_many_recordings"
INSERT_PREVIEW = "insert_preview"
REQUEST_REGION_GRID = "request_region_grid"
+UPSERT_REVIEW_SEGMENT = "upsert_review_segment"
# Autotracking
diff --git a/frigate/detectors/detector_config.py b/frigate/detectors/detector_config.py
index ca1915449..c00f840de 100644
--- a/frigate/detectors/detector_config.py
+++ b/frigate/detectors/detector_config.py
@@ -7,7 +7,7 @@ from typing import Dict, Optional, Tuple
import matplotlib.pyplot as plt
import requests
-from pydantic import BaseModel, Extra, Field
+from pydantic import BaseModel, ConfigDict, Field
from pydantic.fields import PrivateAttr
from frigate.plus import PlusApi
@@ -35,8 +35,10 @@ class ModelTypeEnum(str, Enum):
class ModelConfig(BaseModel):
- path: Optional[str] = Field(title="Custom Object detection model path.")
- labelmap_path: Optional[str] = Field(title="Label map for custom object detector.")
+ path: Optional[str] = Field(None, title="Custom Object detection model path.")
+ labelmap_path: Optional[str] = Field(
+ None, title="Label map for custom object detector."
+ )
width: int = Field(default=320, title="Object detection model input width.")
height: int = Field(default=320, title="Object detection model input height.")
labelmap: Dict[int, str] = Field(
@@ -132,17 +134,15 @@ class ModelConfig(BaseModel):
for key, val in enumerate(enabled_labels):
self._colormap[val] = tuple(int(round(255 * c)) for c in cmap(key)[:3])
- class Config:
- extra = Extra.forbid
+ model_config = ConfigDict(extra="forbid", protected_namespaces=())
class BaseDetectorConfig(BaseModel):
# the type field must be defined in all subclasses
type: str = Field(default="cpu", title="Detector Type")
- model: ModelConfig = Field(
+ model: Optional[ModelConfig] = Field(
default=None, title="Detector specific model configuration."
)
-
- class Config:
- extra = Extra.allow
- arbitrary_types_allowed = True
+ model_config = ConfigDict(
+ extra="allow", arbitrary_types_allowed=True, protected_namespaces=()
+ )
diff --git a/frigate/detectors/plugins/edgetpu_tfl.py b/frigate/detectors/plugins/edgetpu_tfl.py
index ac67626a2..247e30fc8 100644
--- a/frigate/detectors/plugins/edgetpu_tfl.py
+++ b/frigate/detectors/plugins/edgetpu_tfl.py
@@ -6,6 +6,7 @@ from typing_extensions import Literal
from frigate.detectors.detection_api import DetectionApi
from frigate.detectors.detector_config import BaseDetectorConfig
+from frigate.detectors.util import yolov8_postprocess
try:
from tflite_runtime.interpreter import Interpreter, load_delegate
@@ -54,11 +55,29 @@ class EdgeTpuTfl(DetectionApi):
self.tensor_input_details = self.interpreter.get_input_details()
self.tensor_output_details = self.interpreter.get_output_details()
+ self.model_type = detector_config.model.model_type
def detect_raw(self, tensor_input):
+ if self.model_type == "yolov8":
+ scale, zero_point = self.tensor_input_details[0]["quantization"]
+ tensor_input = (
+ (tensor_input - scale * zero_point * 255) * (1.0 / (scale * 255))
+ ).astype(self.tensor_input_details[0]["dtype"])
+
self.interpreter.set_tensor(self.tensor_input_details[0]["index"], tensor_input)
self.interpreter.invoke()
+ if self.model_type == "yolov8":
+ scale, zero_point = self.tensor_output_details[0]["quantization"]
+ tensor_output = self.interpreter.get_tensor(
+ self.tensor_output_details[0]["index"]
+ )
+ tensor_output = (tensor_output.astype(np.float32) - zero_point) * scale
+ model_input_shape = self.tensor_input_details[0]["shape"]
+ tensor_output[:, [0, 2]] *= model_input_shape[2]
+ tensor_output[:, [1, 3]] *= model_input_shape[1]
+ return yolov8_postprocess(model_input_shape, tensor_output)
+
boxes = self.interpreter.tensor(self.tensor_output_details[0]["index"])()[0]
class_ids = self.interpreter.tensor(self.tensor_output_details[1]["index"])()[0]
scores = self.interpreter.tensor(self.tensor_output_details[2]["index"])()[0]
diff --git a/frigate/detectors/plugins/onnx.py b/frigate/detectors/plugins/onnx.py
new file mode 100644
index 000000000..41dc2a727
--- /dev/null
+++ b/frigate/detectors/plugins/onnx.py
@@ -0,0 +1,65 @@
+import glob
+import logging
+
+import numpy as np
+from typing_extensions import Literal
+
+from frigate.detectors.detection_api import DetectionApi
+from frigate.detectors.detector_config import BaseDetectorConfig
+from frigate.detectors.util import preprocess, yolov8_postprocess
+
+logger = logging.getLogger(__name__)
+
+DETECTOR_KEY = "onnx"
+
+
+class ONNXDetectorConfig(BaseDetectorConfig):
+ type: Literal[DETECTOR_KEY]
+
+
+class ONNXDetector(DetectionApi):
+ type_key = DETECTOR_KEY
+
+ def __init__(self, detector_config: ONNXDetectorConfig):
+ try:
+ import onnxruntime
+
+ logger.info("ONNX: loaded onnxruntime module")
+ except ModuleNotFoundError:
+ logger.error(
+ "ONNX: module loading failed, need 'pip install onnxruntime'?!?"
+ )
+ raise
+
+ assert (
+ detector_config.model.model_type == "yolov8"
+ ), "ONNX: detector_config.model.model_type: only yolov8 supported"
+ assert (
+ detector_config.model.input_tensor == "nhwc"
+ ), "ONNX: detector_config.model.input_tensor: only nhwc supported"
+ if detector_config.model.input_pixel_format != "rgb":
+ logger.warn(
+ "ONNX: detector_config.model.input_pixel_format: should be 'rgb' for yolov8, but '{detector_config.model.input_pixel_format}' specified!"
+ )
+
+ assert detector_config.model.path is not None, (
+ "ONNX: No model.path configured, please configure model.path and model.labelmap_path; some suggestions: "
+ + ", ".join(glob.glob("/config/model_cache/yolov8/*.onnx"))
+ + " and "
+ + ", ".join(glob.glob("/config/model_cache/yolov8/*_labels.txt"))
+ )
+
+ path = detector_config.model.path
+ logger.info(f"ONNX: loading {detector_config.model.path}")
+ self.model = onnxruntime.InferenceSession(path)
+ logger.info(f"ONNX: {path} loaded")
+
+ def detect_raw(self, tensor_input):
+ model_input_name = self.model.get_inputs()[0].name
+ model_input_shape = self.model.get_inputs()[0].shape
+
+ tensor_input = preprocess(tensor_input, model_input_shape, np.float32)
+
+ tensor_output = self.model.run(None, {model_input_name: tensor_input})[0]
+
+ return yolov8_postprocess(model_input_shape, tensor_output)
diff --git a/frigate/detectors/plugins/rknn.py b/frigate/detectors/plugins/rknn.py
index 01c58b94d..a52e6cb71 100644
--- a/frigate/detectors/plugins/rknn.py
+++ b/frigate/detectors/plugins/rknn.py
@@ -42,11 +42,6 @@ class Rknn(DetectionApi):
type_key = DETECTOR_KEY
def __init__(self, config: RknnDetectorConfig):
- # create symlink for Home Assistant add on
- if not os.path.isfile("/proc/device-tree/compatible"):
- if os.path.isfile("/device-tree/compatible"):
- os.symlink("/device-tree/compatible", "/proc/device-tree/compatible")
-
# find out SoC
try:
with open("/proc/device-tree/compatible") as file:
@@ -105,10 +100,10 @@ class Rknn(DetectionApi):
if (config.model.width != 320) or (config.model.height != 320):
logger.error(
- "Make sure to set the model width and heigth to 320 in your config.yml."
+ "Make sure to set the model width and height to 320 in your config.yml."
)
raise Exception(
- "Make sure to set the model width and heigth to 320 in your config.yml."
+ "Make sure to set the model width and height to 320 in your config.yml."
)
if config.model.input_pixel_format != "bgr":
diff --git a/frigate/detectors/plugins/rocm.py b/frigate/detectors/plugins/rocm.py
new file mode 100644
index 000000000..e40febab9
--- /dev/null
+++ b/frigate/detectors/plugins/rocm.py
@@ -0,0 +1,143 @@
+import ctypes
+import glob
+import logging
+import os
+import subprocess
+import sys
+
+import numpy as np
+from pydantic import Field
+from typing_extensions import Literal
+
+from frigate.detectors.detection_api import DetectionApi
+from frigate.detectors.detector_config import BaseDetectorConfig
+from frigate.detectors.util import preprocess, yolov8_postprocess
+
+logger = logging.getLogger(__name__)
+
+DETECTOR_KEY = "rocm"
+
+
+def detect_gfx_version():
+ return subprocess.getoutput(
+ "unset HSA_OVERRIDE_GFX_VERSION && /opt/rocm/bin/rocminfo | grep gfx |head -1|awk '{print $2}'"
+ )
+
+
+def auto_override_gfx_version():
+ # If environment variable already in place, do not override
+ gfx_version = detect_gfx_version()
+ old_override = os.getenv("HSA_OVERRIDE_GFX_VERSION")
+ if old_override not in (None, ""):
+ logger.warning(
+ f"AMD/ROCm: detected {gfx_version} but HSA_OVERRIDE_GFX_VERSION already present ({old_override}), not overriding!"
+ )
+ return old_override
+ mapping = {
+ "gfx90c": "9.0.0",
+ "gfx1031": "10.3.0",
+ "gfx1103": "11.0.0",
+ }
+ override = mapping.get(gfx_version)
+ if override is not None:
+ logger.warning(
+ f"AMD/ROCm: detected {gfx_version}, overriding HSA_OVERRIDE_GFX_VERSION={override}"
+ )
+ os.putenv("HSA_OVERRIDE_GFX_VERSION", override)
+ return override
+ return ""
+
+
+class ROCmDetectorConfig(BaseDetectorConfig):
+ type: Literal[DETECTOR_KEY]
+ conserve_cpu: bool = Field(
+ default=True,
+ title="Conserve CPU at the expense of latency (and reduced max throughput)",
+ )
+ auto_override_gfx: bool = Field(
+ default=True, title="Automatically detect and override gfx version"
+ )
+
+
+class ROCmDetector(DetectionApi):
+ type_key = DETECTOR_KEY
+
+ def __init__(self, detector_config: ROCmDetectorConfig):
+ if detector_config.auto_override_gfx:
+ auto_override_gfx_version()
+
+ try:
+ sys.path.append("/opt/rocm/lib")
+ import migraphx
+
+ logger.info("AMD/ROCm: loaded migraphx module")
+ except ModuleNotFoundError:
+ logger.error("AMD/ROCm: module loading failed, missing ROCm environment?")
+ raise
+
+ if detector_config.conserve_cpu:
+ logger.info("AMD/ROCm: switching HIP to blocking mode to conserve CPU")
+ ctypes.CDLL("/opt/rocm/lib/libamdhip64.so").hipSetDeviceFlags(4)
+ assert (
+ detector_config.model.model_type == "yolov8"
+ ), "AMD/ROCm: detector_config.model.model_type: only yolov8 supported"
+ assert (
+ detector_config.model.input_tensor == "nhwc"
+ ), "AMD/ROCm: detector_config.model.input_tensor: only nhwc supported"
+ if detector_config.model.input_pixel_format != "rgb":
+ logger.warn(
+ "AMD/ROCm: detector_config.model.input_pixel_format: should be 'rgb' for yolov8, but '{detector_config.model.input_pixel_format}' specified!"
+ )
+
+ assert detector_config.model.path is not None, (
+ "No model.path configured, please configure model.path and model.labelmap_path; some suggestions: "
+ + ", ".join(glob.glob("/config/model_cache/yolov8/*.onnx"))
+ + " and "
+ + ", ".join(glob.glob("/config/model_cache/yolov8/*_labels.txt"))
+ )
+
+ path = detector_config.model.path
+ mxr_path = os.path.splitext(path)[0] + ".mxr"
+ if path.endswith(".mxr"):
+ logger.info(f"AMD/ROCm: loading parsed model from {mxr_path}")
+ self.model = migraphx.load(mxr_path)
+ elif os.path.exists(mxr_path):
+ logger.info(f"AMD/ROCm: loading parsed model from {mxr_path}")
+ self.model = migraphx.load(mxr_path)
+ else:
+ logger.info(f"AMD/ROCm: loading model from {path}")
+ if path.endswith(".onnx"):
+ self.model = migraphx.parse_onnx(path)
+ elif (
+ path.endswith(".tf")
+ or path.endswith(".tf2")
+ or path.endswith(".tflite")
+ ):
+ # untested
+ self.model = migraphx.parse_tf(path)
+ else:
+ raise Exception(f"AMD/ROCm: unknown model format {path}")
+ logger.info("AMD/ROCm: compiling the model")
+ self.model.compile(
+ migraphx.get_target("gpu"), offload_copy=True, fast_math=True
+ )
+ logger.info(f"AMD/ROCm: saving parsed model into {mxr_path}")
+ os.makedirs("/config/model_cache/rocm", exist_ok=True)
+ migraphx.save(self.model, mxr_path)
+ logger.info("AMD/ROCm: model loaded")
+
+ def detect_raw(self, tensor_input):
+ model_input_name = self.model.get_parameter_names()[0]
+ model_input_shape = tuple(
+ self.model.get_parameter_shapes()[model_input_name].lens()
+ )
+ tensor_input = preprocess(tensor_input, model_input_shape, np.float32)
+
+ detector_result = self.model.run({model_input_name: tensor_input})[0]
+
+ addr = ctypes.cast(detector_result.data_ptr(), ctypes.POINTER(ctypes.c_float))
+ tensor_output = np.ctypeslib.as_array(
+ addr, shape=detector_result.get_shape().lens()
+ )
+
+ return yolov8_postprocess(model_input_shape, tensor_output)
diff --git a/frigate/detectors/util.py b/frigate/detectors/util.py
new file mode 100644
index 000000000..db1b9f794
--- /dev/null
+++ b/frigate/detectors/util.py
@@ -0,0 +1,83 @@
+import logging
+
+import cv2
+import numpy as np
+
+logger = logging.getLogger(__name__)
+
+
+def preprocess(tensor_input, model_input_shape, model_input_element_type):
+ model_input_shape = tuple(model_input_shape)
+ assert tensor_input.dtype == np.uint8, f"tensor_input.dtype: {tensor_input.dtype}"
+ if len(tensor_input.shape) == 3:
+ tensor_input = tensor_input[np.newaxis, :]
+ if model_input_element_type == np.uint8:
+ # nothing to do for uint8 model input
+ assert (
+ model_input_shape == tensor_input.shape
+ ), f"model_input_shape: {model_input_shape}, tensor_input.shape: {tensor_input.shape}"
+ return tensor_input
+ assert (
+ model_input_element_type == np.float32
+ ), f"model_input_element_type: {model_input_element_type}"
+ # tensor_input must be nhwc
+ assert tensor_input.shape[3] == 3, f"tensor_input.shape: {tensor_input.shape}"
+ if tensor_input.shape[1:3] != model_input_shape[2:4]:
+ logger.warn(
+ f"preprocess: tensor_input.shape {tensor_input.shape} and model_input_shape {model_input_shape} do not match!"
+ )
+ # cv2.dnn.blobFromImage is faster than numpying it
+ return cv2.dnn.blobFromImage(
+ tensor_input[0],
+ 1.0 / 255,
+ (model_input_shape[3], model_input_shape[2]),
+ None,
+ swapRB=False,
+ )
+
+
+def yolov8_postprocess(
+ model_input_shape,
+ tensor_output,
+ box_count=20,
+ score_threshold=0.5,
+ nms_threshold=0.5,
+):
+ model_box_count = tensor_output.shape[2]
+ probs = tensor_output[0, 4:, :]
+ all_ids = np.argmax(probs, axis=0)
+ all_confidences = probs.T[np.arange(model_box_count), all_ids]
+ all_boxes = tensor_output[0, 0:4, :].T
+ mask = all_confidences > score_threshold
+ class_ids = all_ids[mask]
+ confidences = all_confidences[mask]
+ cx, cy, w, h = all_boxes[mask].T
+
+ if model_input_shape[3] == 3:
+ scale_y, scale_x = 1 / model_input_shape[1], 1 / model_input_shape[2]
+ else:
+ scale_y, scale_x = 1 / model_input_shape[2], 1 / model_input_shape[3]
+ detections = np.stack(
+ (
+ class_ids,
+ confidences,
+ scale_y * (cy - h / 2),
+ scale_x * (cx - w / 2),
+ scale_y * (cy + h / 2),
+ scale_x * (cx + w / 2),
+ ),
+ axis=1,
+ )
+ if detections.shape[0] > box_count:
+ # if too many detections, do nms filtering to suppress overlapping boxes
+ boxes = np.stack((cx - w / 2, cy - h / 2, w, h), axis=1)
+ indexes = cv2.dnn.NMSBoxes(boxes, confidences, score_threshold, nms_threshold)
+ detections = detections[indexes]
+ # if still too many, trim the rest by confidence
+ if detections.shape[0] > box_count:
+ detections = detections[
+ np.argpartition(detections[:, 1], -box_count)[-box_count:]
+ ]
+ detections = detections.copy()
+ detections.resize((box_count, 6))
+ return detections
diff --git a/frigate/events/audio.py b/frigate/events/audio.py
index ed457adf1..fc8f38dad 100644
--- a/frigate/events/audio.py
+++ b/frigate/events/audio.py
@@ -13,7 +13,9 @@ import numpy as np
import requests
from setproctitle import setproctitle
-from frigate.comms.inter_process import InterProcessCommunicator
+from frigate.comms.config_updater import ConfigSubscriber
+from frigate.comms.detections_updater import DetectionPublisher, DetectionTypeEnum
+from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import CameraConfig, CameraInput, FfmpegConfig, FrigateConfig
from frigate.const import (
AUDIO_DURATION,
@@ -26,7 +28,7 @@ from frigate.const import (
from frigate.ffmpeg_presets import parse_preset_input
from frigate.log import LogPipe
from frigate.object_detection import load_labels
-from frigate.types import CameraMetricsTypes, FeatureMetricsTypes
+from frigate.types import CameraMetricsTypes
from frigate.util.builtin import get_ffmpeg_arg_list
from frigate.util.services import listen
from frigate.video import start_or_restart_ffmpeg, stop_ffmpeg
@@ -67,10 +69,7 @@ def get_ffmpeg_command(ffmpeg: FfmpegConfig) -> list[str]:
def listen_to_audio(
config: FrigateConfig,
- recordings_info_queue: mp.Queue,
camera_metrics: dict[str, CameraMetricsTypes],
- process_info: dict[str, FeatureMetricsTypes],
- inter_process_communicator: InterProcessCommunicator,
) -> None:
stop_event = mp.Event()
audio_threads: list[threading.Thread] = []
@@ -96,11 +95,8 @@ def listen_to_audio(
if camera.enabled and camera.audio.enabled_in_config:
audio = AudioEventMaintainer(
camera,
- recordings_info_queue,
camera_metrics,
- process_info,
stop_event,
- inter_process_communicator,
)
audio_threads.append(audio)
audio.start()
@@ -170,19 +166,13 @@ class AudioEventMaintainer(threading.Thread):
def __init__(
self,
camera: CameraConfig,
- recordings_info_queue: mp.Queue,
camera_metrics: dict[str, CameraMetricsTypes],
- feature_metrics: dict[str, FeatureMetricsTypes],
stop_event: mp.Event,
- inter_process_communicator: InterProcessCommunicator,
) -> None:
threading.Thread.__init__(self)
self.name = f"{camera.name}_audio_event_processor"
self.config = camera
- self.recordings_info_queue = recordings_info_queue
self.camera_metrics = camera_metrics
- self.feature_metrics = feature_metrics
- self.inter_process_communicator = inter_process_communicator
self.detections: dict[dict[str, any]] = {}
self.stop_event = stop_event
self.detector = AudioTfl(stop_event, self.config.audio.num_threads)
@@ -193,8 +183,13 @@ class AudioEventMaintainer(threading.Thread):
self.logpipe = LogPipe(f"ffmpeg.{self.config.name}.audio")
self.audio_listener = None
+ # create communication for audio detections
+ self.requestor = InterProcessRequestor()
+ self.config_subscriber = ConfigSubscriber(f"config/audio/{camera.name}")
+ self.detection_publisher = DetectionPublisher(DetectionTypeEnum.audio)
+
def detect_audio(self, audio) -> None:
- if not self.feature_metrics[self.config.name]["audio_enabled"].value:
+ if not self.config.audio.enabled or self.stop_event.is_set():
return
audio_as_float = audio.astype(np.float32)
@@ -222,8 +217,8 @@ class AudioEventMaintainer(threading.Thread):
self.handle_detection(label, score)
audio_detections.append(label)
- # add audio info to recordings queue
- self.recordings_info_queue.put(
+ # send audio detection data
+ self.detection_publisher.send_data(
(
self.config.name,
datetime.datetime.now().timestamp(),
@@ -245,24 +240,18 @@ class AudioEventMaintainer(threading.Thread):
else:
dBFS = 0
- self.inter_process_communicator.queue.put(
- (f"{self.config.name}/audio/dBFS", float(dBFS))
- )
- self.inter_process_communicator.queue.put(
- (f"{self.config.name}/audio/rms", float(rms))
- )
+ self.requestor.send_data(f"{self.config.name}/audio/dBFS", float(dBFS))
+ self.requestor.send_data(f"{self.config.name}/audio/rms", float(rms))
return float(rms), float(dBFS)
def handle_detection(self, label: str, score: float) -> None:
if self.detections.get(label):
- self.detections[label][
- "last_detection"
- ] = datetime.datetime.now().timestamp()
- else:
- self.inter_process_communicator.queue.put(
- (f"{self.config.name}/audio/{label}", "ON")
+ self.detections[label]["last_detection"] = (
+ datetime.datetime.now().timestamp()
)
+ else:
+ self.requestor.send_data(f"{self.config.name}/audio/{label}", "ON")
resp = requests.post(
f"{FRIGATE_LOCALHOST}/api/events/{self.config.name}/{label}/create",
@@ -288,8 +277,8 @@ class AudioEventMaintainer(threading.Thread):
now - detection.get("last_detection", now)
> self.config.audio.max_not_heard
):
- self.inter_process_communicator.queue.put(
- (f"{self.config.name}/audio/{detection['label']}", "OFF")
+ self.requestor.send_data(
+ f"{self.config.name}/audio/{detection['label']}", "OFF"
)
resp = requests.put(
@@ -346,7 +335,19 @@ class AudioEventMaintainer(threading.Thread):
self.start_or_restart_ffmpeg()
while not self.stop_event.is_set():
+ # check if there is an updated config
+ (
+ updated_topic,
+ updated_audio_config,
+ ) = self.config_subscriber.check_for_update()
+
+ if updated_topic:
+ self.config.audio = updated_audio_config
+
self.read_audio()
stop_ffmpeg(self.audio_listener, self.logger)
self.logpipe.close()
+ self.requestor.stop()
+ self.config_subscriber.stop()
+ self.detection_publisher.stop()
diff --git a/frigate/ffmpeg_presets.py b/frigate/ffmpeg_presets.py
index 96314e6a5..d07ae369f 100644
--- a/frigate/ffmpeg_presets.py
+++ b/frigate/ffmpeg_presets.py
@@ -69,8 +69,8 @@ PRESETS_HW_ACCEL_DECODE = {
FFMPEG_HWACCEL_NVIDIA: "-hwaccel cuda -hwaccel_output_format cuda",
"preset-jetson-h264": "-c:v h264_nvmpi -resize {1}x{2}",
"preset-jetson-h265": "-c:v hevc_nvmpi -resize {1}x{2}",
- "preset-rk-h264": "-c:v h264_rkmpp_decoder",
- "preset-rk-h265": "-c:v hevc_rkmpp_decoder",
+ "preset-rk-h264": "-hwaccel rkmpp -hwaccel_output_format drm_prime",
+ "preset-rk-h265": "-hwaccel rkmpp -hwaccel_output_format drm_prime",
}
PRESETS_HW_ACCEL_DECODE["preset-nvidia-h264"] = PRESETS_HW_ACCEL_DECODE[
FFMPEG_HWACCEL_NVIDIA
@@ -91,8 +91,8 @@ PRESETS_HW_ACCEL_SCALE = {
FFMPEG_HWACCEL_NVIDIA: "-r {0} -vf fps={0},scale_cuda=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p",
"preset-jetson-h264": "-r {0}", # scaled in decoder
"preset-jetson-h265": "-r {0}", # scaled in decoder
- "preset-rk-h264": "-r {0} -vf fps={0},scale={1}:{2}",
- "preset-rk-h265": "-r {0} -vf fps={0},scale={1}:{2}",
+ "preset-rk-h264": "-r {0} -vf scale_rkrga=w={1}:h={2}:format=yuv420p:force_original_aspect_ratio=0,hwmap=mode=read,format=yuv420p",
+ "preset-rk-h265": "-r {0} -vf scale_rkrga=w={1}:h={2}:format=yuv420p:force_original_aspect_ratio=0,hwmap=mode=read,format=yuv420p",
"default": "-r {0} -vf fps={0},scale={1}:{2}",
}
PRESETS_HW_ACCEL_SCALE["preset-nvidia-h264"] = PRESETS_HW_ACCEL_SCALE[
@@ -111,16 +111,16 @@ PRESETS_HW_ACCEL_ENCODE_BIRDSEYE = {
FFMPEG_HWACCEL_NVIDIA: "ffmpeg -hide_banner {0} -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll {1}",
"preset-jetson-h264": "ffmpeg -hide_banner {0} -c:v h264_nvmpi -profile high {1}",
"preset-jetson-h265": "ffmpeg -hide_banner {0} -c:v h264_nvmpi -profile high {1}",
- "preset-rk-h264": "ffmpeg -hide_banner {0} -c:v h264_rkmpp_encoder -profile high {1}",
- "preset-rk-h265": "ffmpeg -hide_banner {0} -c:v hevc_rkmpp_encoder -profile high {1}",
+ "preset-rk-h264": "ffmpeg -hide_banner {0} -c:v h264_rkmpp -profile:v high {1}",
+ "preset-rk-h265": "ffmpeg -hide_banner {0} -c:v hevc_rkmpp -profile:v high {1}",
"default": "ffmpeg -hide_banner {0} -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency {1}",
}
-PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[
- "preset-nvidia-h264"
-] = PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[FFMPEG_HWACCEL_NVIDIA]
-PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[
- "preset-nvidia-h265"
-] = PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[FFMPEG_HWACCEL_NVIDIA]
+PRESETS_HW_ACCEL_ENCODE_BIRDSEYE["preset-nvidia-h264"] = (
+ PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[FFMPEG_HWACCEL_NVIDIA]
+)
+PRESETS_HW_ACCEL_ENCODE_BIRDSEYE["preset-nvidia-h265"] = (
+ PRESETS_HW_ACCEL_ENCODE_BIRDSEYE[FFMPEG_HWACCEL_NVIDIA]
+)
PRESETS_HW_ACCEL_ENCODE_TIMELAPSE = {
"preset-rpi-64-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m -pix_fmt yuv420p {1}",
@@ -132,13 +132,13 @@ PRESETS_HW_ACCEL_ENCODE_TIMELAPSE = {
"preset-nvidia-h265": "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 8 {0} -c:v hevc_nvenc {1}",
"preset-jetson-h264": "ffmpeg -hide_banner {0} -c:v h264_nvmpi -profile high {1}",
"preset-jetson-h265": "ffmpeg -hide_banner {0} -c:v hevc_nvmpi -profile high {1}",
- "preset-rk-h264": "ffmpeg -hide_banner {0} -c:v h264_rkmpp_encoder -profile high {1}",
- "preset-rk-h265": "ffmpeg -hide_banner {0} -c:v hevc_rkmpp_encoder -profile high {1}",
+ "preset-rk-h264": "ffmpeg -hide_banner {0} -c:v h264_rkmpp -profile:v high {1}",
+ "preset-rk-h265": "ffmpeg -hide_banner {0} -c:v hevc_rkmpp -profile:v high {1}",
"default": "ffmpeg -hide_banner {0} -c:v libx264 -preset:v ultrafast -tune:v zerolatency {1}",
}
-PRESETS_HW_ACCEL_ENCODE_TIMELAPSE[
- "preset-nvidia-h264"
-] = PRESETS_HW_ACCEL_ENCODE_TIMELAPSE[FFMPEG_HWACCEL_NVIDIA]
+PRESETS_HW_ACCEL_ENCODE_TIMELAPSE["preset-nvidia-h264"] = (
+ PRESETS_HW_ACCEL_ENCODE_TIMELAPSE[FFMPEG_HWACCEL_NVIDIA]
+)
# encoding of previews is only done on CPU due to comparable encode times and better quality from libx264
PRESETS_HW_ACCEL_ENCODE_PREVIEW = {
@@ -175,7 +175,7 @@ def parse_preset_hardware_acceleration_scale(
if not isinstance(arg, str) or " " in arg:
scale = PRESETS_HW_ACCEL_SCALE["default"]
else:
- scale = PRESETS_HW_ACCEL_SCALE.get(arg, "")
+ scale = PRESETS_HW_ACCEL_SCALE.get(arg, PRESETS_HW_ACCEL_SCALE["default"])
scale = scale.format(fps, width, height).split(" ")
scale.extend(detect_args)
@@ -461,9 +461,18 @@ PRESETS_RECORD_OUTPUT = {
}
-def parse_preset_output_record(arg: Any) -> list[str]:
+def parse_preset_output_record(arg: Any, force_record_hvc1: bool) -> list[str]:
"""Return the correct preset if in preset format otherwise return None."""
if not isinstance(arg, str):
return None
- return PRESETS_RECORD_OUTPUT.get(arg, None)
+ preset = PRESETS_RECORD_OUTPUT.get(arg, None)
+
+ if not preset:
+ return None
+
+ if force_record_hvc1:
+ # Apple only supports HEVC if it is hvc1 (vs. hev1)
+ preset += ["-tag:v", "hvc1"]
+
+ return preset
diff --git a/frigate/http.py b/frigate/http.py
index 141f095f0..416de151d 100644
--- a/frigate/http.py
+++ b/frigate/http.py
@@ -24,11 +24,11 @@ from flask import (
Flask,
Response,
current_app,
- escape,
jsonify,
make_response,
request,
)
+from markupsafe import escape
from peewee import DoesNotExist, fn, operator
from playhouse.shortcuts import model_to_dict
from playhouse.sqliteq import SqliteQueueDatabase
@@ -45,12 +45,12 @@ from frigate.const import (
RECORD_DIR,
)
from frigate.events.external import ExternalEventProcessor
-from frigate.models import Event, Previews, Recordings, Regions, Timeline
+from frigate.models import Event, Previews, Recordings, Regions, ReviewSegment, Timeline
from frigate.object_processing import TrackedObject
from frigate.plus import PlusApi
from frigate.ptz.onvif import OnvifController
from frigate.record.export import PlaybackFactorEnum, RecordingExporter
-from frigate.stats import stats_snapshot
+from frigate.stats.emitter import StatsEmitter
from frigate.storage import StorageMaintainer
from frigate.util.builtin import (
clean_camera_user_pass,
@@ -70,12 +70,12 @@ bp = Blueprint("frigate", __name__)
def create_app(
frigate_config,
database: SqliteQueueDatabase,
- stats_tracking,
detected_frames_processor,
storage_maintainer: StorageMaintainer,
onvif: OnvifController,
external_processor: ExternalEventProcessor,
plus_api: PlusApi,
+ stats_emitter: StatsEmitter,
):
app = Flask(__name__)
@@ -97,14 +97,13 @@ def create_app(
database.close()
app.frigate_config = frigate_config
- app.stats_tracking = stats_tracking
app.detected_frames_processor = detected_frames_processor
app.storage_maintainer = storage_maintainer
app.onvif = onvif
app.external_processor = external_processor
app.plus_api = plus_api
app.camera_error_image = None
- app.hwaccel_errors = []
+ app.stats_emitter = stats_emitter
app.register_blueprint(bp)
@@ -277,6 +276,13 @@ def send_to_plus(id):
box,
event.label,
)
+ except ValueError:
+ message = "Error uploading annotation, unsupported label provided."
+ logger.error(message)
+ return make_response(
+ jsonify({"success": False, "message": message}),
+ 400,
+ )
except Exception as ex:
logger.exception(ex)
return make_response(
@@ -348,6 +354,13 @@ def false_positive(id):
event.model_type,
event.detector_type,
)
+ except ValueError:
+ message = "Error uploading false positive, unsupported label provided."
+ logger.error(message)
+ return make_response(
+ jsonify({"success": False, "message": message}),
+ 400,
+ )
except Exception as ex:
logger.exception(ex)
return make_response(
@@ -593,6 +606,22 @@ def event_thumbnail(id, max_cache_age=2592000):
return response
+@bp.route("/events//preview.gif")
+def event_preview(id: str):
+ try:
+ event: Event = Event.get(Event.id == id)
+ except DoesNotExist:
+ return make_response(
+ jsonify({"success": False, "message": "Event not found"}), 404
+ )
+
+ start_ts = event.start_time
+ end_ts = start_ts + (
+ min(event.end_time - event.start_time, 20) if event.end_time else 20
+ )
+ return preview_gif(event.camera, start_ts, end_ts)
+
+
@bp.route("/timeline")
def timeline():
camera = request.args.get("camera", "all")
@@ -904,9 +933,9 @@ def event_snapshot(id):
else:
response.headers["Cache-Control"] = "no-store"
if download:
- response.headers[
- "Content-Disposition"
- ] = f"attachment; filename=snapshot-{id}.jpg"
+ response.headers["Content-Disposition"] = (
+ f"attachment; filename=snapshot-{id}.jpg"
+ )
return response
@@ -1093,9 +1122,9 @@ def event_clip(id):
if download:
response.headers["Content-Disposition"] = "attachment; filename=%s" % file_name
response.headers["Content-Length"] = os.path.getsize(clip_path)
- response.headers[
- "X-Accel-Redirect"
- ] = f"/clips/{file_name}" # nginx: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers
+ response.headers["X-Accel-Redirect"] = (
+ f"/clips/{file_name}" # nginx: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers
+ )
return response
@@ -1371,7 +1400,7 @@ def end_event(event_id):
@bp.route("/config")
def config():
- config = current_app.frigate_config.dict()
+ config = current_app.frigate_config.model_dump(mode="json", exclude_none=True)
# remove the mqtt password
config["mqtt"].pop("password", None)
@@ -1391,9 +1420,9 @@ def config():
config["plus"] = {"enabled": current_app.plus_api.is_active()}
for detector, detector_config in config["detectors"].items():
- detector_config["model"][
- "labelmap"
- ] = current_app.frigate_config.model.merged_labelmap
+ detector_config["model"]["labelmap"] = (
+ current_app.frigate_config.model.merged_labelmap
+ )
return jsonify(config)
@@ -1587,12 +1616,12 @@ def version():
@bp.route("/stats")
def stats():
- stats = stats_snapshot(
- current_app.frigate_config,
- current_app.stats_tracking,
- current_app.hwaccel_errors,
- )
- return jsonify(stats)
+ return jsonify(current_app.stats_emitter.get_latest_stats())
+
+
+@bp.route("/stats/history")
+def stats_history():
+ return jsonify(current_app.stats_emitter.get_stats_history())
@bp.route("/")
@@ -1789,20 +1818,18 @@ def get_snapshot_from_recording(camera_name: str, frame_time: str):
@bp.route("/recordings/storage", methods=["GET"])
def get_recordings_storage_usage():
- recording_stats = stats_snapshot(
- current_app.frigate_config,
- current_app.stats_tracking,
- current_app.hwaccel_errors,
- )["service"]["storage"][RECORD_DIR]
+ recording_stats = current_app.stats_emitter.get_latest_stats()["service"][
+ "storage"
+ ][RECORD_DIR]
if not recording_stats:
return jsonify({})
total_mb = recording_stats["total"]
- camera_usages: dict[
- str, dict
- ] = current_app.storage_maintainer.calculate_camera_usages()
+ camera_usages: dict[str, dict] = (
+ current_app.storage_maintainer.calculate_camera_usages()
+ )
for camera_name in camera_usages.keys():
if camera_usages.get(camera_name, {}).get("usage"):
@@ -1990,9 +2017,9 @@ def recording_clip(camera_name, start_ts, end_ts):
if download:
response.headers["Content-Disposition"] = "attachment; filename=%s" % file_name
response.headers["Content-Length"] = os.path.getsize(path)
- response.headers[
- "X-Accel-Redirect"
- ] = f"/cache/{file_name}" # nginx: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers
+ response.headers["X-Accel-Redirect"] = (
+ f"/cache/{file_name}" # nginx: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers
+ )
return response
@@ -2148,32 +2175,13 @@ def preview_hour(year_month, day, hour, camera_name, tz_name):
return preview_ts(camera_name, start_ts, end_ts)
-@bp.route("/preview///thumbnail.jpg")
-def preview_thumbnail(camera_name, frame_time):
+@bp.route("/preview//thumbnail.jpg")
+def preview_thumbnail(file_name: str):
"""Get a thumbnail from the cached preview jpgs."""
+ safe_file_name_current = secure_filename(file_name)
preview_dir = os.path.join(CACHE_DIR, "preview_frames")
- file_start = f"preview_{camera_name}"
- file_check = f"{file_start}-{frame_time}.jpg"
- selected_preview = None
- for file in os.listdir(preview_dir):
- if file.startswith(file_start):
- if file < file_check:
- selected_preview = file
- break
-
- if selected_preview is None:
- return make_response(
- jsonify(
- {
- "success": False,
- "message": "Could not find valid preview jpg.",
- }
- ),
- 404,
- )
-
- with open(os.path.join(preview_dir, selected_preview), "rb") as image_file:
+ with open(os.path.join(preview_dir, safe_file_name_current), "rb") as image_file:
jpg_bytes = image_file.read()
response = make_response(jpg_bytes)
@@ -2182,6 +2190,172 @@ def preview_thumbnail(camera_name, frame_time):
return response
+@bp.route("/preview//start//end//frames")
+@bp.route("/preview//start//end//frames")
+def get_preview_frames_from_cache(camera_name: str, start_ts, end_ts):
+ """Get list of cached preview frames"""
+ preview_dir = os.path.join(CACHE_DIR, "preview_frames")
+ file_start = f"preview_{camera_name}"
+ start_file = f"{file_start}-{start_ts}.jpg"
+ end_file = f"{file_start}-{end_ts}.jpg"
+ selected_previews = []
+
+ for file in sorted(os.listdir(preview_dir)):
+ if not file.startswith(file_start):
+ continue
+
+ if file < start_file:
+ continue
+
+ if file > end_file:
+ break
+
+ selected_previews.append(file)
+
+ return jsonify(selected_previews)
+
+
+@bp.route("//start//end//preview.gif")
+@bp.route("//start//end//preview.gif")
+def preview_gif(camera_name: str, start_ts, end_ts, max_cache_age=2592000):
+ if datetime.fromtimestamp(start_ts) < datetime.now().replace(minute=0, second=0):
+ # has preview mp4
+ preview: Previews = (
+ Previews.select(
+ Previews.camera,
+ Previews.path,
+ Previews.duration,
+ Previews.start_time,
+ Previews.end_time,
+ )
+ .where(
+ Previews.start_time.between(start_ts, end_ts)
+ | Previews.end_time.between(start_ts, end_ts)
+ | ((start_ts > Previews.start_time) & (end_ts < Previews.end_time))
+ )
+ .where(Previews.camera == camera_name)
+ .limit(1)
+ .get()
+ )
+
+ if not preview:
+ return make_response(
+ jsonify({"success": False, "message": "Preview not found"}), 404
+ )
+
+ diff = start_ts - preview.start_time
+ minutes = int(diff / 60)
+ seconds = int(diff % 60)
+ ffmpeg_cmd = [
+ "ffmpeg",
+ "-hide_banner",
+ "-loglevel",
+ "warning",
+ "-ss",
+ f"00:{minutes}:{seconds}",
+ "-t",
+ f"{end_ts - start_ts}",
+ "-i",
+ preview.path,
+ "-r",
+ "8",
+ "-vf",
+ "setpts=0.12*PTS",
+ "-loop",
+ "0",
+ "-c:v",
+ "gif",
+ "-f",
+ "gif",
+ "-",
+ ]
+
+ process = sp.run(
+ ffmpeg_cmd,
+ capture_output=True,
+ )
+
+ if process.returncode != 0:
+ logger.error(process.stderr)
+ return make_response(
+ jsonify({"success": False, "message": "Unable to create preview gif"}),
+ 500,
+ )
+
+ gif_bytes = process.stdout
+ else:
+ # need to generate from existing images
+ preview_dir = os.path.join(CACHE_DIR, "preview_frames")
+ file_start = f"preview_{camera_name}"
+ start_file = f"{file_start}-{start_ts}.jpg"
+ end_file = f"{file_start}-{end_ts}.jpg"
+ selected_previews = []
+
+ for file in sorted(os.listdir(preview_dir)):
+ if not file.startswith(file_start):
+ continue
+
+ if file < start_file:
+ continue
+
+ if file > end_file:
+ break
+
+ selected_previews.append(f"file '{os.path.join(preview_dir, file)}'")
+ selected_previews.append("duration 0.12")
+
+ if not selected_previews:
+ return make_response(
+ jsonify({"success": False, "message": "Preview not found"}), 404
+ )
+
+ last_file = selected_previews[-2]
+ selected_previews.append(last_file)
+
+ ffmpeg_cmd = [
+ "ffmpeg",
+ "-hide_banner",
+ "-loglevel",
+ "warning",
+ "-f",
+ "concat",
+ "-y",
+ "-protocol_whitelist",
+ "pipe,file",
+ "-safe",
+ "0",
+ "-i",
+ "/dev/stdin",
+ "-loop",
+ "0",
+ "-c:v",
+ "gif",
+ "-f",
+ "gif",
+ "-",
+ ]
+
+ process = sp.run(
+ ffmpeg_cmd,
+ input=str.encode("\n".join(selected_previews)),
+ capture_output=True,
+ )
+
+ if process.returncode != 0:
+ logger.error(process.stderr)
+ return make_response(
+ jsonify({"success": False, "message": "Unable to create preview gif"}),
+ 500,
+ )
+
+ gif_bytes = process.stdout
+
+ response = make_response(gif_bytes)
+ response.headers["Content-Type"] = "image/gif"
+ response.headers["Cache-Control"] = f"private, max-age={max_cache_age}"
+ return response
+
+
@bp.route("/vod/event/")
def vod_event(id):
try:
@@ -2238,6 +2412,138 @@ def vod_event(id):
)
+@bp.route("/review")
+def review():
+ cameras = request.args.get("cameras", "all")
+ labels = request.args.get("labels", "all")
+ reviewed = request.args.get("reviewed", type=int, default=0)
+ limit = request.args.get("limit", 100)
+ severity = request.args.get("severity", None)
+
+ before = request.args.get("before", type=float, default=datetime.now().timestamp())
+ after = request.args.get(
+ "after", type=float, default=(datetime.now() - timedelta(hours=18)).timestamp()
+ )
+
+ clauses = [((ReviewSegment.start_time > after) & (ReviewSegment.end_time < before))]
+
+ if cameras != "all":
+ camera_list = cameras.split(",")
+ clauses.append((ReviewSegment.camera << camera_list))
+
+ if labels != "all":
+ # use matching so segments with multiple labels
+ # still match on a search where any label matches
+ label_clauses = []
+ filtered_labels = labels.split(",")
+
+ for label in filtered_labels:
+ label_clauses.append(
+ (ReviewSegment.data["objects"].cast("text") % f'*"{label}"*')
+ )
+
+ label_clause = reduce(operator.or_, label_clauses)
+ clauses.append((label_clause))
+
+ if reviewed == 0:
+ clauses.append((ReviewSegment.has_been_reviewed == False))
+
+ if severity:
+ clauses.append((ReviewSegment.severity == severity))
+
+ review = (
+ ReviewSegment.select()
+ .where(reduce(operator.and_, clauses))
+ .order_by(ReviewSegment.severity.asc())
+ .order_by(ReviewSegment.start_time.desc())
+ .limit(limit)
+ .dicts()
+ )
+
+ return jsonify([r for r in review])
+
+
+@bp.route("/review//viewed", methods=("POST",))
+def set_reviewed(id):
+ try:
+ review: ReviewSegment = ReviewSegment.get(ReviewSegment.id == id)
+ except DoesNotExist:
+ return make_response(
+ jsonify({"success": False, "message": "Review " + id + " not found"}), 404
+ )
+
+ review.has_been_reviewed = True
+ review.save()
+
+ return make_response(
+ jsonify({"success": True, "message": "Reviewed " + id + " viewed"}), 200
+ )
+
+
+@bp.route("/reviews//viewed", methods=("POST",))
+def set_multiple_reviewed(ids: str):
+ list_of_ids = ids.split(",")
+
+ if not list_of_ids or len(list_of_ids) == 0:
+ return make_response(
+ jsonify({"success": False, "message": "Not a valid list of ids"}), 404
+ )
+
+ ReviewSegment.update(has_been_reviewed=True).where(
+ ReviewSegment.id << list_of_ids
+ ).execute()
+
+ return make_response(
+ jsonify({"success": True, "message": "Reviewed multiple items"}), 200
+ )
+
+
+@bp.route("/review//viewed", methods=("DELETE",))
+def set_not_reviewed(id):
+ try:
+ review: ReviewSegment = ReviewSegment.get(ReviewSegment.id == id)
+ except DoesNotExist:
+ return make_response(
+ jsonify({"success": False, "message": "Review " + id + " not found"}), 404
+ )
+
+ review.has_been_reviewed = False
+ review.save()
+
+ return make_response(
+ jsonify({"success": True, "message": "Reviewed " + id + " not viewed"}), 200
+ )
+
+
+@bp.route("/reviews/", methods=("DELETE",))
+def delete_reviews(ids: str):
+ list_of_ids = ids.split(",")
+
+ if not list_of_ids or len(list_of_ids) == 0:
+ return make_response(
+ jsonify({"success": False, "message": "Not a valid list of ids"}), 404
+ )
+
+ ReviewSegment.delete().where(ReviewSegment.id << list_of_ids).execute()
+
+ return make_response(jsonify({"success": True, "message": "Delete reviews"}), 200)
+
+
+@bp.route("/review//preview.gif")
+def review_preview(id: str):
+ try:
+ review: ReviewSegment = ReviewSegment.get(ReviewSegment.id == id)
+ except DoesNotExist:
+ return make_response(
+ jsonify({"success": False, "message": "Review segment not found"}), 404
+ )
+
+ padding = 8
+ start_ts = review.start_time - padding
+ end_ts = review.end_time + padding
+ return preview_gif(review.camera, start_ts, end_ts)
+
+
@bp.route(
"/export//start//end/", methods=["POST"]
)
@@ -2281,9 +2587,11 @@ def export_recording(camera_name: str, start_time, end_time):
camera_name,
int(start_time),
int(end_time),
- PlaybackFactorEnum[playback_factor]
- if playback_factor in PlaybackFactorEnum.__members__.values()
- else PlaybackFactorEnum.realtime,
+ (
+ PlaybackFactorEnum[playback_factor]
+ if playback_factor in PlaybackFactorEnum.__members__.values()
+ else PlaybackFactorEnum.realtime
+ ),
)
exporter.start()
return make_response(
@@ -2439,12 +2747,16 @@ def ffprobe():
output.append(
{
"return_code": ffprobe.returncode,
- "stderr": ffprobe.stderr.decode("unicode_escape").strip()
- if ffprobe.returncode != 0
- else "",
- "stdout": json.loads(ffprobe.stdout.decode("unicode_escape").strip())
- if ffprobe.returncode == 0
- else "",
+ "stderr": (
+ ffprobe.stderr.decode("unicode_escape").strip()
+ if ffprobe.returncode != 0
+ else ""
+ ),
+ "stdout": (
+ json.loads(ffprobe.stdout.decode("unicode_escape").strip())
+ if ffprobe.returncode == 0
+ else ""
+ ),
}
)
@@ -2457,12 +2769,16 @@ def vainfo():
return jsonify(
{
"return_code": vainfo.returncode,
- "stderr": vainfo.stderr.decode("unicode_escape").strip()
- if vainfo.returncode != 0
- else "",
- "stdout": vainfo.stdout.decode("unicode_escape").strip()
- if vainfo.returncode == 0
- else "",
+ "stderr": (
+ vainfo.stderr.decode("unicode_escape").strip()
+ if vainfo.returncode != 0
+ else ""
+ ),
+ "stdout": (
+ vainfo.stdout.decode("unicode_escape").strip()
+ if vainfo.returncode == 0
+ else ""
+ ),
}
)
diff --git a/frigate/models.py b/frigate/models.py
index 56d429b19..87424e3a8 100644
--- a/frigate/models.py
+++ b/frigate/models.py
@@ -76,6 +76,17 @@ class Recordings(Model): # type: ignore[misc]
segment_size = FloatField(default=0) # this should be stored as MB
+class ReviewSegment(Model): # type: ignore[misc]
+ id = CharField(null=False, primary_key=True, max_length=30)
+ camera = CharField(index=True, max_length=20)
+ start_time = DateTimeField()
+ end_time = DateTimeField()
+ has_been_reviewed = BooleanField(default=False)
+ severity = CharField(max_length=30) # alert, detection, significant_motion
+ thumb_path = CharField(unique=True)
+ data = JSONField() # additional data about detection like list of labels, zone, areas of significant motion
+
+
class Previews(Model): # type: ignore[misc]
id = CharField(null=False, primary_key=True, max_length=30)
camera = CharField(index=True, max_length=20)
diff --git a/frigate/motion/__init__.py b/frigate/motion/__init__.py
index 248c37092..db5f25879 100644
--- a/frigate/motion/__init__.py
+++ b/frigate/motion/__init__.py
@@ -24,3 +24,7 @@ class MotionDetector(ABC):
@abstractmethod
def is_calibrating(self):
pass
+
+ @abstractmethod
+ def stop(self):
+ pass
diff --git a/frigate/motion/improved_motion.py b/frigate/motion/improved_motion.py
index 603d8fda4..6fb17ec29 100644
--- a/frigate/motion/improved_motion.py
+++ b/frigate/motion/improved_motion.py
@@ -5,6 +5,7 @@ import imutils
import numpy as np
from scipy.ndimage import gaussian_filter
+from frigate.comms.config_updater import ConfigSubscriber
from frigate.config import MotionConfig
from frigate.motion import MotionDetector
@@ -17,9 +18,6 @@ class ImprovedMotionDetector(MotionDetector):
frame_shape,
config: MotionConfig,
fps: int,
- improve_contrast,
- threshold,
- contour_area,
name="improved",
blur_radius=1,
interpolation=cv2.INTER_NEAREST,
@@ -44,14 +42,12 @@ class ImprovedMotionDetector(MotionDetector):
self.mask = np.where(resized_mask == [0])
self.save_images = False
self.calibrating = True
- self.improve_contrast = improve_contrast
- self.threshold = threshold
- self.contour_area = contour_area
self.blur_radius = blur_radius
self.interpolation = interpolation
self.contrast_values = np.zeros((contrast_frame_history, 2), np.uint8)
self.contrast_values[:, 1:2] = 255
self.contrast_values_index = 0
+ self.config_subscriber = ConfigSubscriber(f"config/motion/{name}")
def is_calibrating(self):
return self.calibrating
@@ -59,6 +55,15 @@ class ImprovedMotionDetector(MotionDetector):
def detect(self, frame):
motion_boxes = []
+ # check for updated motion config
+ _, updated_motion_config = self.config_subscriber.check_for_update()
+
+ if updated_motion_config:
+ self.config = updated_motion_config
+
+ if not self.config.enabled:
+ return motion_boxes
+
gray = frame[0 : self.frame_shape[0], 0 : self.frame_shape[1]]
# resize frame
@@ -72,7 +77,7 @@ class ImprovedMotionDetector(MotionDetector):
resized_saved = resized_frame.copy()
# Improve contrast
- if self.improve_contrast.value:
+ if self.config.improve_contrast:
# TODO tracking moving average of min/max to avoid sudden contrast changes
minval = np.percentile(resized_frame, 4).astype(np.uint8)
maxval = np.percentile(resized_frame, 96).astype(np.uint8)
@@ -96,7 +101,8 @@ class ImprovedMotionDetector(MotionDetector):
# mask frame
# this has to come after contrast improvement
- resized_frame[self.mask] = [255]
+ # Setting masked pixels to zero, to match the average frame at startup
+ resized_frame[self.mask] = [0]
resized_frame = gaussian_filter(resized_frame, sigma=1, radius=self.blur_radius)
@@ -110,7 +116,7 @@ class ImprovedMotionDetector(MotionDetector):
# compute the threshold image for the current frame
thresh = cv2.threshold(
- frameDelta, self.threshold.value, 255, cv2.THRESH_BINARY
+ frameDelta, self.config.threshold, 255, cv2.THRESH_BINARY
)[1]
# dilate the thresholded image to fill in holes, then find contours
@@ -127,7 +133,7 @@ class ImprovedMotionDetector(MotionDetector):
# if the contour is big enough, count it as motion
contour_area = cv2.contourArea(c)
total_contour_area += contour_area
- if contour_area > self.contour_area.value:
+ if contour_area > self.config.contour_area:
x, y, w, h = cv2.boundingRect(c)
motion_boxes.append(
(
@@ -170,9 +176,11 @@ class ImprovedMotionDetector(MotionDetector):
]
cv2.imwrite(
f"debug/frames/{self.name}-{self.frame_counter}.jpg",
- cv2.hconcat(frames)
- if self.frame_shape[0] > self.frame_shape[1]
- else cv2.vconcat(frames),
+ (
+ cv2.hconcat(frames)
+ if self.frame_shape[0] > self.frame_shape[1]
+ else cv2.vconcat(frames)
+ ),
)
if len(motion_boxes) > 0:
@@ -194,3 +202,7 @@ class ImprovedMotionDetector(MotionDetector):
self.motion_frame_count = 0
return motion_boxes
+
+ def stop(self) -> None:
+ """stop the motion detector."""
+ self.config_subscriber.stop()
diff --git a/frigate/object_processing.py b/frigate/object_processing.py
index 2d141b970..f3bb54adc 100644
--- a/frigate/object_processing.py
+++ b/frigate/object_processing.py
@@ -12,6 +12,7 @@ from typing import Callable
import cv2
import numpy as np
+from frigate.comms.detections_updater import DetectionPublisher, DetectionTypeEnum
from frigate.comms.dispatcher import Dispatcher
from frigate.config import (
CameraConfig,
@@ -488,8 +489,12 @@ class CameraState:
# draw the bounding boxes on the frame
for obj in tracked_objects.values():
if obj["frame_time"] == frame_time:
- thickness = 2
- color = self.config.model.colormap[obj["label"]]
+ if obj["stationary"]:
+ color = (220, 220, 220)
+ thickness = 1
+ else:
+ thickness = 2
+ color = self.config.model.colormap[obj["label"]]
else:
thickness = 1
color = (255, 0, 0)
@@ -813,8 +818,6 @@ class TrackedObjectProcessor(threading.Thread):
tracked_objects_queue,
event_queue,
event_processed_queue,
- video_output_queue,
- recordings_info_queue,
ptz_autotracker_thread,
stop_event,
):
@@ -825,13 +828,12 @@ class TrackedObjectProcessor(threading.Thread):
self.tracked_objects_queue = tracked_objects_queue
self.event_queue = event_queue
self.event_processed_queue = event_processed_queue
- self.video_output_queue = video_output_queue
- self.recordings_info_queue = recordings_info_queue
self.stop_event = stop_event
self.camera_states: dict[str, CameraState] = {}
self.frame_manager = SharedMemoryFrameManager()
self.last_motion_detected: dict[str, float] = {}
self.ptz_autotracker_thread = ptz_autotracker_thread
+ self.detection_publisher = DetectionPublisher(DetectionTypeEnum.video)
def start(camera, obj: TrackedObject, current_frame_time):
self.event_queue.put(
@@ -1116,18 +1118,8 @@ class TrackedObjectProcessor(threading.Thread):
o.to_dict() for o in camera_state.tracked_objects.values()
]
- self.video_output_queue.put(
- (
- camera,
- frame_time,
- tracked_objects,
- motion_boxes,
- regions,
- )
- )
-
- # send info on this frame to the recordings maintainer
- self.recordings_info_queue.put(
+ # publish info on this frame
+ self.detection_publisher.send_data(
(
camera,
frame_time,
@@ -1212,4 +1204,5 @@ class TrackedObjectProcessor(threading.Thread):
event_id, camera = self.event_processed_queue.get()
self.camera_states[camera].finished(event_id)
+ self.detection_publisher.stop()
logger.info("Exiting object processor...")
diff --git a/frigate/output/birdseye.py b/frigate/output/birdseye.py
index dbaafa313..99ff3a6fa 100644
--- a/frigate/output/birdseye.py
+++ b/frigate/output/birdseye.py
@@ -14,9 +14,9 @@ import traceback
import cv2
import numpy as np
+from frigate.comms.config_updater import ConfigSubscriber
from frigate.config import BirdseyeModeEnum, FrigateConfig
from frigate.const import BASE_DIR, BIRDSEYE_PIPE
-from frigate.types import CameraMetricsTypes
from frigate.util.image import (
SharedMemoryFrameManager,
copy_yuv_to_position,
@@ -33,11 +33,13 @@ def get_standard_aspect_ratio(width: int, height: int) -> tuple[int, int]:
(16, 9),
(9, 16),
(20, 10),
+ (16, 3), # max wide camera
(16, 6), # reolink duo 2
(32, 9), # panoramic cameras
(12, 9),
(9, 12),
(22, 15), # Amcrest, NTSC DVT
+ (1, 1), # fisheye
] # aspects are scaled to have common relative size
known_aspects_ratios = list(
map(lambda aspect: aspect[0] / aspect[1], known_aspects)
@@ -66,7 +68,13 @@ def get_canvas_shape(width: int, height: int) -> tuple[int, int]:
class Canvas:
- def __init__(self, canvas_width: int, canvas_height: int) -> None:
+ def __init__(
+ self,
+ canvas_width: int,
+ canvas_height: int,
+ scaling_factor: int,
+ ) -> None:
+ self.scaling_factor = scaling_factor
gcd = math.gcd(canvas_width, canvas_height)
self.aspect = get_standard_aspect_ratio(
(canvas_width / gcd), (canvas_height / gcd)
@@ -80,7 +88,7 @@ class Canvas:
return (self.aspect[0] * coefficient, self.aspect[1] * coefficient)
def get_coefficient(self, camera_count: int) -> int:
- return self.coefficient_cache.get(camera_count, 2)
+ return self.coefficient_cache.get(camera_count, self.scaling_factor)
def set_coefficient(self, camera_count: int, coefficient: int) -> None:
self.coefficient_cache[camera_count] = coefficient
@@ -259,7 +267,6 @@ class BirdsEyeFrameManager:
config: FrigateConfig,
frame_manager: SharedMemoryFrameManager,
stop_event: mp.Event,
- camera_metrics: dict[str, CameraMetricsTypes],
):
self.config = config
self.mode = config.birdseye.mode
@@ -268,9 +275,12 @@ class BirdsEyeFrameManager:
self.frame_shape = (height, width)
self.yuv_shape = (height * 3 // 2, width)
self.frame = np.ndarray(self.yuv_shape, dtype=np.uint8)
- self.canvas = Canvas(width, height)
+ self.canvas = Canvas(width, height, config.birdseye.layout.scaling_factor)
self.stop_event = stop_event
- self.camera_metrics = camera_metrics
+ self.inactivity_threshold = config.birdseye.inactivity_threshold
+
+ if config.birdseye.layout.max_cameras:
+ self.last_refresh_time = 0
# initialize the frame as black and with the Frigate logo
self.blank_frame = np.zeros(self.yuv_shape, np.uint8)
@@ -376,16 +386,39 @@ class BirdsEyeFrameManager:
def update_frame(self):
"""Update to a new frame for birdseye."""
- # determine how many cameras are tracking objects within the last 30 seconds
- active_cameras = set(
+ # determine how many cameras are tracking objects within the last inactivity_threshold seconds
+ active_cameras: set[str] = set(
[
cam
for cam, cam_data in self.cameras.items()
if cam_data["last_active_frame"] > 0
- and cam_data["current_frame"] - cam_data["last_active_frame"] < 30
+ and cam_data["current_frame"] - cam_data["last_active_frame"]
+ < self.inactivity_threshold
]
)
+ max_cameras = self.config.birdseye.layout.max_cameras
+ max_camera_refresh = False
+ if max_cameras:
+ now = datetime.datetime.now().timestamp()
+
+ if len(active_cameras) == max_cameras and now - self.last_refresh_time < 10:
+ # don't refresh cameras too often
+ active_cameras = self.active_cameras
+ else:
+ limited_active_cameras = sorted(
+ active_cameras,
+ key=lambda active_camera: (
+ self.cameras[active_camera]["current_frame"]
+ - self.cameras[active_camera]["last_active_frame"]
+ ),
+ )
+ active_cameras = limited_active_cameras[
+ : self.config.birdseye.layout.max_cameras
+ ]
+ max_camera_refresh = True
+ self.last_refresh_time = now
+
# if there are no active cameras
if len(active_cameras) == 0:
# if the layout is already cleared
@@ -399,7 +432,15 @@ class BirdsEyeFrameManager:
return True
# check if we need to reset the layout because there is a different number of cameras
- reset_layout = len(self.active_cameras) - len(active_cameras) != 0
+ if len(self.active_cameras) - len(active_cameras) == 0:
+ if len(self.active_cameras) == 1 and self.active_cameras != active_cameras:
+ reset_layout = True
+ elif max_camera_refresh:
+ reset_layout = True
+ else:
+ reset_layout = False
+ else:
+ reset_layout = True
# reset the layout if it needs to be different
if reset_layout:
@@ -423,17 +464,23 @@ class BirdsEyeFrameManager:
camera = active_cameras_to_add[0]
camera_dims = self.cameras[camera]["dimensions"].copy()
scaled_width = int(self.canvas.height * camera_dims[0] / camera_dims[1])
- coefficient = (
- 1
- if scaled_width <= self.canvas.width
- else self.canvas.width / scaled_width
- )
+
+ # center camera view in canvas and ensure that it fits
+ if scaled_width < self.canvas.width:
+ coefficient = 1
+ x_offset = int((self.canvas.width - scaled_width) / 2)
+ else:
+ coefficient = self.canvas.width / scaled_width
+ x_offset = int(
+ (self.canvas.width - (scaled_width * coefficient)) / 2
+ )
+
self.camera_layout = [
[
(
camera,
(
- 0,
+ x_offset,
0,
int(scaled_width * coefficient),
int(self.canvas.height * coefficient),
@@ -477,7 +524,11 @@ class BirdsEyeFrameManager:
return True
- def calculate_layout(self, cameras_to_add: list[str], coefficient) -> tuple[any]:
+ def calculate_layout(
+ self,
+ cameras_to_add: list[str],
+ coefficient: float,
+ ) -> tuple[any]:
"""Calculate the optimal layout for 2+ cameras."""
def map_layout(camera_layout: list[list[any]], row_height: int):
@@ -619,15 +670,12 @@ class BirdsEyeFrameManager:
def update(self, camera, object_count, motion_count, frame_time, frame) -> bool:
# don't process if birdseye is disabled for this camera
camera_config = self.config.cameras[camera].birdseye
+
if not camera_config.enabled:
return False
- # get our metrics (sync'd across processes)
- # which allows us to control it via mqtt (or any other dispatcher)
- camera_metrics = self.camera_metrics[camera]
-
# disabling birdseye is a little tricky
- if not camera_metrics["birdseye_enabled"].value:
+ if not camera_config.enabled:
# if we've rendered a frame (we have a value for last_active_frame)
# then we need to set it to zero
if self.cameras[camera]["last_active_frame"] > 0:
@@ -635,12 +683,9 @@ class BirdsEyeFrameManager:
return False
- # get the birdseye mode state from camera metrics
- birdseye_mode = BirdseyeModeEnum.get(camera_metrics["birdseye_mode"].value)
-
# update the last active frame for the camera
self.cameras[camera]["current_frame"] = frame_time
- if self.camera_active(birdseye_mode, object_count, motion_count):
+ if self.camera_active(camera_config.mode, object_count, motion_count):
self.cameras[camera]["last_active_frame"] = frame_time
now = datetime.datetime.now().timestamp()
@@ -669,7 +714,6 @@ class Birdseye:
self,
config: FrigateConfig,
frame_manager: SharedMemoryFrameManager,
- camera_metrics: dict[str, CameraMetricsTypes],
stop_event: mp.Event,
websocket_server,
) -> None:
@@ -689,9 +733,8 @@ class Birdseye:
self.broadcaster = BroadcastThread(
"birdseye", self.converter, websocket_server, stop_event
)
- self.birdseye_manager = BirdsEyeFrameManager(
- config, frame_manager, stop_event, camera_metrics
- )
+ self.birdseye_manager = BirdsEyeFrameManager(config, frame_manager, stop_event)
+ self.config_subscriber = ConfigSubscriber("config/birdseye/")
if config.birdseye.restream:
self.birdseye_buffer = frame_manager.create(
@@ -710,6 +753,19 @@ class Birdseye:
frame_time: float,
frame,
) -> None:
+ # check if there is an updated config
+ while True:
+ (
+ updated_topic,
+ updated_birdseye_config,
+ ) = self.config_subscriber.check_for_update()
+
+ if not updated_topic:
+ break
+
+ camera_name = updated_topic.rpartition("/")[-1]
+ self.config.cameras[camera_name].birdseye = updated_birdseye_config
+
if self.birdseye_manager.update(
camera,
len([o for o in current_tracked_objects if not o["stationary"]]),
@@ -729,5 +785,6 @@ class Birdseye:
pass
def stop(self) -> None:
+ self.config_subscriber.stop()
self.converter.join()
self.broadcaster.join()
diff --git a/frigate/output/output.py b/frigate/output/output.py
index 2dd9dd082..e717463b1 100644
--- a/frigate/output/output.py
+++ b/frigate/output/output.py
@@ -2,7 +2,6 @@
import logging
import multiprocessing as mp
-import queue
import signal
import threading
from typing import Optional
@@ -16,12 +15,12 @@ from ws4py.server.wsgirefserver import (
)
from ws4py.server.wsgiutils import WebSocketWSGIApplication
+from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum
from frigate.comms.ws import WebSocket
from frigate.config import FrigateConfig
from frigate.output.birdseye import Birdseye
from frigate.output.camera import JsmpegCamera
from frigate.output.preview import PreviewRecorder
-from frigate.types import CameraMetricsTypes
from frigate.util.image import SharedMemoryFrameManager
logger = logging.getLogger(__name__)
@@ -29,9 +28,6 @@ logger = logging.getLogger(__name__)
def output_frames(
config: FrigateConfig,
- video_output_queue: mp.Queue,
- inter_process_queue: mp.Queue,
- camera_metrics: dict[str, CameraMetricsTypes],
):
threading.current_thread().name = "output"
setproctitle("frigate.output")
@@ -59,6 +55,8 @@ def output_frames(
websocket_server.initialize_websockets_manager()
websocket_thread = threading.Thread(target=websocket_server.serve_forever)
+ detection_subscriber = DetectionSubscriber(DetectionTypeEnum.video)
+
jsmpeg_cameras: dict[str, JsmpegCamera] = {}
birdseye: Optional[Birdseye] = None
preview_recorders: dict[str, PreviewRecorder] = {}
@@ -68,27 +66,27 @@ def output_frames(
continue
jsmpeg_cameras[camera] = JsmpegCamera(cam_config, stop_event, websocket_server)
- preview_recorders[camera] = PreviewRecorder(cam_config, inter_process_queue)
+ preview_recorders[camera] = PreviewRecorder(cam_config)
if config.birdseye.enabled:
- birdseye = Birdseye(
- config, frame_manager, camera_metrics, stop_event, websocket_server
- )
+ birdseye = Birdseye(config, frame_manager, stop_event, websocket_server)
websocket_thread.start()
while not stop_event.is_set():
- try:
- (
- camera,
- frame_time,
- current_tracked_objects,
- motion_boxes,
- regions,
- ) = video_output_queue.get(True, 1)
- except queue.Empty:
+ (topic, data) = detection_subscriber.get_data(timeout=10)
+
+ if not topic:
continue
+ (
+ camera,
+ frame_time,
+ current_tracked_objects,
+ motion_boxes,
+ regions,
+ ) = data
+
frame_id = f"{camera}{frame_time}"
frame = frame_manager.get(frame_id, config.cameras[camera].frame_shape_yuv)
@@ -127,19 +125,26 @@ def output_frames(
previous_frames[camera] = frame_time
- while not video_output_queue.empty():
+ while True:
+ (topic, data) = detection_subscriber.get_data(timeout=0)
+
+ if not topic:
+ break
+
(
camera,
frame_time,
current_tracked_objects,
motion_boxes,
regions,
- ) = video_output_queue.get(True, 10)
+ ) = data
frame_id = f"{camera}{frame_time}"
frame = frame_manager.get(frame_id, config.cameras[camera].frame_shape_yuv)
frame_manager.delete(frame_id)
+ detection_subscriber.stop()
+
for jsmpeg in jsmpeg_cameras.values():
jsmpeg.stop()
diff --git a/frigate/output/preview.py b/frigate/output/preview.py
index 784051f47..33d0de884 100644
--- a/frigate/output/preview.py
+++ b/frigate/output/preview.py
@@ -2,7 +2,6 @@
import datetime
import logging
-import multiprocessing as mp
import os
import shutil
import subprocess as sp
@@ -12,6 +11,7 @@ from pathlib import Path
import cv2
import numpy as np
+from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import CameraConfig, RecordQualityEnum
from frigate.const import CACHE_DIR, CLIPS_DIR, INSERT_PREVIEW
from frigate.ffmpeg_presets import (
@@ -20,21 +20,21 @@ from frigate.ffmpeg_presets import (
parse_preset_hardware_acceleration_encode,
)
from frigate.models import Previews
+from frigate.object_processing import TrackedObject
from frigate.util.image import copy_yuv_to_position, get_yuv_crop
logger = logging.getLogger(__name__)
FOLDER_PREVIEW_FRAMES = "preview_frames"
-PREVIEW_OUTPUT_FPS = 1
PREVIEW_SEGMENT_DURATION = 3600 # one hour
# important to have lower keyframe to maintain scrubbing performance
PREVIEW_KEYFRAME_INTERVAL = 60
PREVIEW_BIT_RATES = {
- RecordQualityEnum.very_low: 4096,
- RecordQualityEnum.low: 6144,
- RecordQualityEnum.medium: 8192,
- RecordQualityEnum.high: 12288,
- RecordQualityEnum.very_high: 16384,
+ RecordQualityEnum.very_low: 5120,
+ RecordQualityEnum.low: 7168,
+ RecordQualityEnum.medium: 9216,
+ RecordQualityEnum.high: 13312,
+ RecordQualityEnum.very_high: 17408,
}
@@ -53,13 +53,13 @@ class FFMpegConverter(threading.Thread):
self,
config: CameraConfig,
frame_times: list[float],
- inter_process_queue: mp.Queue,
+ requestor: InterProcessRequestor,
):
threading.Thread.__init__(self)
self.name = f"{config.name}_preview_converter"
self.config = config
self.frame_times = frame_times
- self.inter_process_queue = inter_process_queue
+ self.requestor = requestor
self.path = os.path.join(
CLIPS_DIR,
f"previews/{self.config.name}/{self.frame_times[0]}-{self.frame_times[-1]}.mp4",
@@ -69,7 +69,7 @@ class FFMpegConverter(threading.Thread):
self.ffmpeg_cmd = parse_preset_hardware_acceleration_encode(
config.ffmpeg.hwaccel_args,
input="-f concat -y -protocol_whitelist pipe,file -safe 0 -i /dev/stdin",
- output=f"-g {PREVIEW_KEYFRAME_INTERVAL} -fpsmax {PREVIEW_OUTPUT_FPS} -bf 0 -b:v {PREVIEW_BIT_RATES[self.config.record.preview.quality]} {FPS_VFR_PARAM} -movflags +faststart -pix_fmt yuv420p {self.path}",
+ output=f"-g {PREVIEW_KEYFRAME_INTERVAL} -fpsmax 2 -bf 0 -b:v {PREVIEW_BIT_RATES[self.config.record.preview.quality]} {FPS_VFR_PARAM} -movflags +faststart -pix_fmt yuv420p {self.path}",
type=EncodeTypeEnum.preview,
)
@@ -105,18 +105,16 @@ class FFMpegConverter(threading.Thread):
if p.returncode == 0:
logger.debug("successfully saved preview")
- self.inter_process_queue.put_nowait(
- (
- INSERT_PREVIEW,
- {
- Previews.id: f"{self.config.name}_{end}",
- Previews.camera: self.config.name,
- Previews.path: self.path,
- Previews.start_time: start,
- Previews.end_time: end,
- Previews.duration: end - start,
- },
- )
+ self.requestor.send_data(
+ INSERT_PREVIEW,
+ {
+ Previews.id: f"{self.config.name}_{end}",
+ Previews.camera: self.config.name,
+ Previews.path: self.path,
+ Previews.start_time: start,
+ Previews.end_time: end,
+ Previews.duration: end - start,
+ },
)
else:
logger.error(f"Error saving preview for {self.config.name} :: {p.stderr}")
@@ -128,17 +126,19 @@ class FFMpegConverter(threading.Thread):
class PreviewRecorder:
- def __init__(self, config: CameraConfig, inter_process_queue: mp.Queue) -> None:
+ def __init__(self, config: CameraConfig) -> None:
self.config = config
- self.inter_process_queue = inter_process_queue
self.start_time = 0
self.last_output_time = 0
self.output_frames = []
- self.out_height = 160
+ self.out_height = 180
self.out_width = (
int((config.detect.width / config.detect.height) * self.out_height) // 4 * 4
)
+ # create communication for finished previews
+ self.requestor = InterProcessRequestor()
+
y, u1, u2, v1, v2 = get_yuv_crop(
self.config.frame_shape_yuv,
(
@@ -175,8 +175,19 @@ class PreviewRecorder:
frame_time: float,
) -> bool:
"""Decide if this frame should be added to PREVIEW."""
+ preview_output_fps = (
+ 2
+ if any(
+ o["label"] == "car"
+ for o in get_active_objects(
+ frame_time, self.config, current_tracked_objects
+ )
+ )
+ else 1
+ )
+
# limit output to 1 fps
- if (frame_time - self.last_output_time) < 1 / PREVIEW_OUTPUT_FPS:
+ if (frame_time - self.last_output_time) < 1 / preview_output_fps:
return False
# send frame if a non-stationary object is in a zone
@@ -237,7 +248,7 @@ class PreviewRecorder:
FFMpegConverter(
self.config,
self.output_frames,
- self.inter_process_queue,
+ self.requestor,
).start()
# reset frame cache
@@ -262,3 +273,19 @@ class PreviewRecorder:
shutil.rmtree(os.path.join(CACHE_DIR, FOLDER_PREVIEW_FRAMES))
except FileNotFoundError:
pass
+
+ self.requestor.stop()
+
+
+def get_active_objects(
+ frame_time: float, camera_config: CameraConfig, all_objects: list[TrackedObject]
+) -> list[TrackedObject]:
+ """get active objects for detection."""
+ return [
+ o
+ for o in all_objects
+ if o["motionless_count"] < camera_config.detect.stationary.threshold
+ and o["position_changes"] > 0
+ and o["frame_time"] == frame_time
+ and not o["false_positive"]
+ ]
diff --git a/frigate/plus.py b/frigate/plus.py
index 88e025596..7c4564562 100644
--- a/frigate/plus.py
+++ b/frigate/plus.py
@@ -37,8 +37,10 @@ class PlusApi:
self.key = None
if PLUS_ENV_VAR in os.environ:
self.key = os.environ.get(PLUS_ENV_VAR)
- elif os.path.isdir("/run/secrets") and PLUS_ENV_VAR in os.listdir(
- "/run/secrets"
+ elif (
+ os.path.isdir("/run/secrets")
+ and os.access("/run/secrets", os.R_OK)
+ and PLUS_ENV_VAR in os.listdir("/run/secrets")
):
self.key = Path(os.path.join("/run/secrets", PLUS_ENV_VAR)).read_text()
# check for the addon options file
@@ -171,6 +173,17 @@ class PlusApi:
)
if not r.ok:
+ try:
+ error_response = r.json()
+ errors = error_response.get("errors", [])
+ for error in errors:
+ if (
+ error.get("param") == "label"
+ and error.get("type") == "invalid_enum_value"
+ ):
+ raise ValueError(f"Unsupported label value provided: {label}")
+ except ValueError as e:
+ raise e
raise Exception(r.text)
def add_annotation(
@@ -193,6 +206,17 @@ class PlusApi:
)
if not r.ok:
+ try:
+ error_response = r.json()
+ errors = error_response.get("errors", [])
+ for error in errors:
+ if (
+ error.get("param") == "label"
+ and error.get("type") == "invalid_enum_value"
+ ):
+ raise ValueError(f"Unsupported label value provided: {label}")
+ except ValueError as e:
+ raise e
raise Exception(r.text)
def get_model_download_url(
diff --git a/frigate/ptz/autotrack.py b/frigate/ptz/autotrack.py
index 8266e4b87..44082a52e 100644
--- a/frigate/ptz/autotrack.py
+++ b/frigate/ptz/autotrack.py
@@ -297,12 +297,12 @@ class PtzAutoTracker:
self.ptz_metrics[camera][
"ptz_max_zoom"
].value = camera_config.onvif.autotracking.movement_weights[1]
- self.intercept[
- camera
- ] = camera_config.onvif.autotracking.movement_weights[2]
- self.move_coefficients[
- camera
- ] = camera_config.onvif.autotracking.movement_weights[3:]
+ self.intercept[camera] = (
+ camera_config.onvif.autotracking.movement_weights[2]
+ )
+ self.move_coefficients[camera] = (
+ camera_config.onvif.autotracking.movement_weights[3:]
+ )
else:
camera_config.onvif.autotracking.enabled = False
self.ptz_metrics[camera]["ptz_autotracker_enabled"].value = False
@@ -603,9 +603,9 @@ class PtzAutoTracker:
) ** self.zoom_factor[camera]
if "original_target_box" not in self.tracked_object_metrics[camera]:
- self.tracked_object_metrics[camera][
- "original_target_box"
- ] = self.tracked_object_metrics[camera]["target_box"]
+ self.tracked_object_metrics[camera]["original_target_box"] = (
+ self.tracked_object_metrics[camera]["target_box"]
+ )
(
self.tracked_object_metrics[camera]["valid_velocity"],
diff --git a/frigate/ptz/onvif.py b/frigate/ptz/onvif.py
index 06570a7d3..a7f7f045e 100644
--- a/frigate/ptz/onvif.py
+++ b/frigate/ptz/onvif.py
@@ -6,6 +6,7 @@ from enum import Enum
import numpy
from onvif import ONVIFCamera, ONVIFError
+from zeep.exceptions import Fault, TransportError
from frigate.config import FrigateConfig, ZoomingModeEnum
from frigate.types import PTZMetricsTypes
@@ -66,28 +67,68 @@ class OnvifController:
# create init services
media = onvif.create_media_service()
+ logger.debug(f"Onvif media xaddr for {camera_name}: {media.xaddr}")
try:
- profile = media.GetProfiles()[0]
- except ONVIFError as e:
- logger.error(f"Unable to connect to camera: {camera_name}: {e}")
+ # this will fire an exception if camera is not a ptz
+ capabilities = onvif.get_definition("ptz")
+ logger.debug(f"Onvif capabilities for {camera_name}: {capabilities}")
+ except (ONVIFError, Fault, TransportError) as e:
+ logger.error(
+ f"Unable to get Onvif capabilities for camera: {camera_name}: {e}"
+ )
+ return False
+
+ try:
+ profiles = media.GetProfiles()
+ except (ONVIFError, Fault, TransportError) as e:
+ logger.error(
+ f"Unable to get Onvif media profiles for camera: {camera_name}: {e}"
+ )
+ return False
+
+ profile = None
+ for key, onvif_profile in enumerate(profiles):
+ if (
+ onvif_profile.VideoEncoderConfiguration
+ and onvif_profile.VideoEncoderConfiguration.Encoding == "H264"
+ and onvif_profile.PTZConfiguration
+ and onvif_profile.PTZConfiguration.DefaultContinuousPanTiltVelocitySpace
+ is not None
+ ):
+ profile = onvif_profile
+ logger.debug(f"Selected Onvif profile for {camera_name}: {profile}")
+ break
+
+ if profile is None:
+ logger.error(
+ f"No appropriate Onvif profiles found for camera: {camera_name}."
+ )
+ return False
+
+ # get the PTZ config for the profile
+ try:
+ configs = profile.PTZConfiguration
+ logger.debug(
+ f"Onvif ptz config for media profile in {camera_name}: {configs}"
+ )
+ except Exception as e:
+ logger.error(
+ f"Invalid Onvif PTZ configuration for camera: {camera_name}: {e}"
+ )
return False
ptz = onvif.create_ptz_service()
- request = ptz.create_type("GetConfigurations")
- configs = ptz.GetConfigurations(request)[0]
- logger.debug(f"Onvif configs for {camera_name}: {configs}")
-
request = ptz.create_type("GetConfigurationOptions")
request.ConfigurationToken = profile.PTZConfiguration.token
ptz_config = ptz.GetConfigurationOptions(request)
logger.debug(f"Onvif config for {camera_name}: {ptz_config}")
service_capabilities_request = ptz.create_type("GetServiceCapabilities")
- self.cams[camera_name][
- "service_capabilities_request"
- ] = service_capabilities_request
+ self.cams[camera_name]["service_capabilities_request"] = (
+ service_capabilities_request
+ )
fov_space_id = next(
(
@@ -113,7 +154,10 @@ class OnvifController:
# autoracking relative panning/tilting needs a relative zoom value set to 0
# if camera supports relative movement
- if self.config.cameras[camera_name].onvif.autotracking.zooming:
+ if (
+ self.config.cameras[camera_name].onvif.autotracking.zooming
+ != ZoomingModeEnum.disabled
+ ):
zoom_space_id = next(
(
i
@@ -144,23 +188,21 @@ class OnvifController:
try:
if (
self.config.cameras[camera_name].onvif.autotracking.zooming
- == ZoomingModeEnum.relative
+ != ZoomingModeEnum.disabled
):
if zoom_space_id is not None:
move_request.Translation.Zoom.space = ptz_config["Spaces"][
"RelativeZoomTranslationSpace"
- ][0]["URI"]
+ ][zoom_space_id]["URI"]
+ else:
+ move_request.Translation.Zoom = []
except Exception:
- if (
- self.config.cameras[camera_name].onvif.autotracking.zooming
- == ZoomingModeEnum.relative
- ):
- self.config.cameras[
- camera_name
- ].onvif.autotracking.zooming = ZoomingModeEnum.disabled
- logger.warning(
- f"Disabling autotracking zooming for {camera_name}: Relative zoom not supported"
- )
+ self.config.cameras[
+ camera_name
+ ].onvif.autotracking.zooming = ZoomingModeEnum.disabled
+ logger.warning(
+ f"Disabling autotracking zooming for {camera_name}: Relative zoom not supported"
+ )
if move_request.Speed is None:
move_request.Speed = configs.DefaultPTZSpeed if configs else None
@@ -187,25 +229,24 @@ class OnvifController:
] = preset["token"]
# get list of supported features
- ptz_config = ptz.GetConfigurationOptions(request)
supported_features = []
- if ptz_config.Spaces and ptz_config.Spaces.ContinuousPanTiltVelocitySpace:
+ if configs.DefaultContinuousPanTiltVelocitySpace:
supported_features.append("pt")
- if ptz_config.Spaces and ptz_config.Spaces.ContinuousZoomVelocitySpace:
+ if configs.DefaultContinuousZoomVelocitySpace:
supported_features.append("zoom")
- if ptz_config.Spaces and ptz_config.Spaces.RelativePanTiltTranslationSpace:
+ if configs.DefaultRelativePanTiltTranslationSpace:
supported_features.append("pt-r")
- if ptz_config.Spaces and ptz_config.Spaces.RelativeZoomTranslationSpace:
+ if configs.DefaultRelativeZoomTranslationSpace:
supported_features.append("zoom-r")
try:
# get camera's zoom limits from onvif config
- self.cams[camera_name][
- "relative_zoom_range"
- ] = ptz_config.Spaces.RelativeZoomTranslationSpace[0]
+ self.cams[camera_name]["relative_zoom_range"] = (
+ ptz_config.Spaces.RelativeZoomTranslationSpace[0]
+ )
except Exception:
if (
self.config.cameras[camera_name].onvif.autotracking.zooming
@@ -218,13 +259,13 @@ class OnvifController:
f"Disabling autotracking zooming for {camera_name}: Relative zoom not supported"
)
- if ptz_config.Spaces and ptz_config.Spaces.AbsoluteZoomPositionSpace:
+ if configs.DefaultAbsoluteZoomPositionSpace:
supported_features.append("zoom-a")
try:
# get camera's zoom limits from onvif config
- self.cams[camera_name][
- "absolute_zoom_range"
- ] = ptz_config.Spaces.AbsoluteZoomPositionSpace[0]
+ self.cams[camera_name]["absolute_zoom_range"] = (
+ ptz_config.Spaces.AbsoluteZoomPositionSpace[0]
+ )
self.cams[camera_name]["zoom_limits"] = configs.ZoomLimits
except Exception:
if self.config.cameras[camera_name].onvif.autotracking.zooming:
@@ -236,11 +277,14 @@ class OnvifController:
)
# set relative pan/tilt space for autotracker
- if fov_space_id is not None:
+ if (
+ fov_space_id is not None
+ and configs.DefaultRelativePanTiltTranslationSpace is not None
+ ):
supported_features.append("pt-r-fov")
- self.cams[camera_name][
- "relative_fov_range"
- ] = ptz_config.Spaces.RelativePanTiltTranslationSpace[fov_space_id]
+ self.cams[camera_name]["relative_fov_range"] = (
+ ptz_config.Spaces.RelativePanTiltTranslationSpace[fov_space_id]
+ )
self.cams[camera_name]["features"] = supported_features
@@ -347,7 +391,11 @@ class OnvifController:
move_request.Translation.PanTilt.x = pan
move_request.Translation.PanTilt.y = tilt
- if "zoom-r" in self.cams[camera_name]["features"]:
+ if (
+ "zoom-r" in self.cams[camera_name]["features"]
+ and self.config.cameras[camera_name].onvif.autotracking.zooming
+ == ZoomingModeEnum.relative
+ ):
move_request.Speed = {
"PanTilt": {
"x": speed,
@@ -363,7 +411,11 @@ class OnvifController:
move_request.Translation.PanTilt.x = 0
move_request.Translation.PanTilt.y = 0
- if "zoom-r" in self.cams[camera_name]["features"]:
+ if (
+ "zoom-r" in self.cams[camera_name]["features"]
+ and self.config.cameras[camera_name].onvif.autotracking.zooming
+ == ZoomingModeEnum.relative
+ ):
move_request.Translation.Zoom.x = 0
self.cams[camera_name]["active"] = False
diff --git a/frigate/record/cleanup.py b/frigate/record/cleanup.py
index c2c7d32e7..86f1e63e1 100644
--- a/frigate/record/cleanup.py
+++ b/frigate/record/cleanup.py
@@ -9,7 +9,7 @@ from pathlib import Path
from frigate.config import CameraConfig, FrigateConfig, RetainModeEnum
from frigate.const import CACHE_DIR, RECORD_DIR
-from frigate.models import Event, Previews, Recordings
+from frigate.models import Event, Previews, Recordings, ReviewSegment
from frigate.record.util import remove_empty_directories, sync_recordings
from frigate.util.builtin import clear_and_unlink, get_tomorrow_at_time
@@ -174,6 +174,65 @@ class RecordingCleanup(threading.Thread):
Previews.id << deleted_previews_list[i : i + max_deletes]
).execute()
+ review_segments: list[ReviewSegment] = (
+ ReviewSegment.select(
+ ReviewSegment.id,
+ ReviewSegment.start_time,
+ ReviewSegment.end_time,
+ ReviewSegment.thumb_path,
+ )
+ .where(
+ ReviewSegment.camera == config.name,
+ ReviewSegment.end_time < expire_date,
+ )
+ .order_by(ReviewSegment.start_time)
+ .namedtuples()
+ .iterator()
+ )
+
+ # expire review segments
+ recording_start = 0
+ deleted_segments = set()
+ for segment in review_segments:
+ keep = False
+ # look for a reason to keep this segment
+ for idx in range(recording_start, len(kept_recordings)):
+ start_time, end_time = kept_recordings[idx]
+
+ # if the recording starts in the future, stop checking recordings
+ # and let this segment expire
+ if start_time > segment.end_time:
+ keep = False
+ break
+
+ # if the recording ends after the segment starts, keep it
+ # and stop looking at recordings
+ if end_time >= segment.start_time:
+ keep = True
+ break
+
+ # if the recording ends before this segment starts, skip
+ # this recording and check the next recording for an overlap.
+ # since the kept recordings and segments are sorted, we can skip recordings
+ # that end before the current segment started
+ if end_time < segment.start_time:
+ recording_start = idx
+
+ # Delete segments without any relevant recordings
+ if not keep:
+ Path(segment.thumb_path).unlink(missing_ok=True)
+ deleted_segments.add(segment.id)
+
+ # expire segments
+ logger.debug(f"Expiring {len(deleted_segments)} segments")
+ # delete up to 100,000 at a time
+ max_deletes = 100000
+ deleted_segments_list = list(deleted_segments)
+ for i in range(0, len(deleted_segments_list), max_deletes):
+ ReviewSegment.delete().where(
+ ReviewSegment.id << deleted_segments_list[i : i + max_deletes]
+ ).execute()
+
def expire_recordings(self) -> None:
"""Delete recordings based on retention config."""
logger.debug("Start expire recordings.")
diff --git a/frigate/record/maintainer.py b/frigate/record/maintainer.py
index 773a29a40..2715dec89 100644
--- a/frigate/record/maintainer.py
+++ b/frigate/record/maintainer.py
@@ -3,9 +3,7 @@
import asyncio
import datetime
import logging
-import multiprocessing as mp
import os
-import queue
import random
import string
import threading
@@ -17,6 +15,9 @@ from typing import Any, Optional, Tuple
import numpy as np
import psutil
+from frigate.comms.config_updater import ConfigSubscriber
+from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum
+from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import FrigateConfig, RetainModeEnum
from frigate.const import (
CACHE_DIR,
@@ -27,7 +28,6 @@ from frigate.const import (
RECORD_DIR,
)
from frigate.models import Event, Recordings
-from frigate.types import FeatureMetricsTypes
from frigate.util.image import area
from frigate.util.services import get_video_properties
@@ -56,22 +56,16 @@ class SegmentInfo:
class RecordingMaintainer(threading.Thread):
- def __init__(
- self,
- config: FrigateConfig,
- inter_process_queue: mp.Queue,
- object_recordings_info_queue: mp.Queue,
- audio_recordings_info_queue: Optional[mp.Queue],
- process_info: dict[str, FeatureMetricsTypes],
- stop_event: MpEvent,
- ):
+ def __init__(self, config: FrigateConfig, stop_event: MpEvent):
threading.Thread.__init__(self)
self.name = "recording_maintainer"
self.config = config
- self.inter_process_queue = inter_process_queue
- self.object_recordings_info_queue = object_recordings_info_queue
- self.audio_recordings_info_queue = audio_recordings_info_queue
- self.process_info = process_info
+
+ # create communication for retained recordings
+ self.requestor = InterProcessRequestor()
+ self.config_subscriber = ConfigSubscriber("config/record/")
+ self.detection_subscriber = DetectionSubscriber(DetectionTypeEnum.all)
+
self.stop_event = stop_event
self.object_recordings_info: dict[str, list] = defaultdict(list)
self.audio_recordings_info: dict[str, list] = defaultdict(list)
@@ -183,8 +177,9 @@ class RecordingMaintainer(threading.Thread):
recordings_to_insert: list[Optional[Recordings]] = await asyncio.gather(*tasks)
# fire and forget recordings entries
- self.inter_process_queue.put(
- (INSERT_MANY_RECORDINGS, [r for r in recordings_to_insert if r is not None])
+ self.requestor.send_data(
+ INSERT_MANY_RECORDINGS,
+ [r for r in recordings_to_insert if r is not None],
)
async def validate_and_move_segment(
@@ -196,7 +191,7 @@ class RecordingMaintainer(threading.Thread):
# Just delete files if recordings are turned off
if (
camera not in self.config.cameras
- or not self.process_info[camera]["record_enabled"].value
+ or not self.config.cameras[camera].record.enabled
):
Path(cache_path).unlink(missing_ok=True)
self.end_time_cache.pop(cache_path, None)
@@ -433,30 +428,45 @@ class RecordingMaintainer(threading.Thread):
return None
def run(self) -> None:
- camera_count = sum(camera.enabled for camera in self.config.cameras.values())
# Check for new files every 5 seconds
wait_time = 0.0
while not self.stop_event.wait(wait_time):
run_start = datetime.datetime.now().timestamp()
+
+ # check if there is an updated config
+ while True:
+ (
+ updated_topic,
+ updated_record_config,
+ ) = self.config_subscriber.check_for_update()
+
+ if not updated_topic:
+ break
+
+ camera_name = updated_topic.rpartition("/")[-1]
+ self.config.cameras[camera_name].record = updated_record_config
+
stale_frame_count = 0
stale_frame_count_threshold = 10
# empty the object recordings info queue
while True:
- try:
+ (topic, data) = self.detection_subscriber.get_data(
+ timeout=QUEUE_READ_TIMEOUT
+ )
+
+ if not topic:
+ break
+
+ if topic == DetectionTypeEnum.video:
(
camera,
frame_time,
current_tracked_objects,
motion_boxes,
regions,
- ) = self.object_recordings_info_queue.get(
- True, timeout=QUEUE_READ_TIMEOUT
- )
+ ) = data
- if frame_time < run_start - stale_frame_count_threshold:
- stale_frame_count += 1
-
- if self.process_info[camera]["record_enabled"].value:
+ if self.config.cameras[camera].record.enabled:
self.object_recordings_info[camera].append(
(
frame_time,
@@ -465,56 +475,29 @@ class RecordingMaintainer(threading.Thread):
regions,
)
)
- except queue.Empty:
- q_size = self.object_recordings_info_queue.qsize()
- if q_size > camera_count:
- logger.debug(
- f"object_recordings_info loop queue not empty ({q_size})."
+ elif topic == DetectionTypeEnum.audio:
+ (
+ camera,
+ frame_time,
+ dBFS,
+ audio_detections,
+ ) = data
+
+ if self.config.cameras[camera].record.enabled:
+ self.audio_recordings_info[camera].append(
+ (
+ frame_time,
+ dBFS,
+ audio_detections,
+ )
)
- break
+
+ if frame_time < run_start - stale_frame_count_threshold:
+ stale_frame_count += 1
if stale_frame_count > 0:
logger.debug(f"Found {stale_frame_count} old frames.")
- # empty the audio recordings info queue if audio is enabled
- if self.audio_recordings_info_queue:
- stale_frame_count = 0
-
- while True:
- try:
- (
- camera,
- frame_time,
- dBFS,
- audio_detections,
- ) = self.audio_recordings_info_queue.get(
- True, timeout=QUEUE_READ_TIMEOUT
- )
-
- if frame_time < run_start - stale_frame_count_threshold:
- stale_frame_count += 1
-
- if self.process_info[camera]["record_enabled"].value:
- self.audio_recordings_info[camera].append(
- (
- frame_time,
- dBFS,
- audio_detections,
- )
- )
- except queue.Empty:
- q_size = self.audio_recordings_info_queue.qsize()
- if q_size > camera_count:
- logger.debug(
- f"object_recordings_info loop audio queue not empty ({q_size})."
- )
- break
-
- if stale_frame_count > 0:
- logger.error(
- f"Found {stale_frame_count} old audio frames, segments from recordings may be missing"
- )
-
try:
asyncio.run(self.move_files())
except Exception as e:
@@ -525,4 +508,7 @@ class RecordingMaintainer(threading.Thread):
duration = datetime.datetime.now().timestamp() - run_start
wait_time = max(0, 5 - duration)
+ self.requestor.stop()
+ self.config_subscriber.stop()
+ self.detection_subscriber.stop()
logger.info("Exiting recording maintenance...")
diff --git a/frigate/record/record.py b/frigate/record/record.py
index ca4400e57..1ffd5394d 100644
--- a/frigate/record/record.py
+++ b/frigate/record/record.py
@@ -13,19 +13,12 @@ from setproctitle import setproctitle
from frigate.config import FrigateConfig
from frigate.models import Event, Recordings
from frigate.record.maintainer import RecordingMaintainer
-from frigate.types import FeatureMetricsTypes
from frigate.util.services import listen
logger = logging.getLogger(__name__)
-def manage_recordings(
- config: FrigateConfig,
- inter_process_queue: mp.Queue,
- object_recordings_info_queue: mp.Queue,
- audio_recordings_info_queue: mp.Queue,
- process_info: dict[str, FeatureMetricsTypes],
-) -> None:
+def manage_recordings(config: FrigateConfig) -> None:
stop_event = mp.Event()
def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None:
@@ -52,10 +45,6 @@ def manage_recordings(
maintainer = RecordingMaintainer(
config,
- inter_process_queue,
- object_recordings_info_queue,
- audio_recordings_info_queue,
- process_info,
stop_event,
)
maintainer.start()
diff --git a/frigate/review/__init__.py b/frigate/review/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/frigate/review/maintainer.py b/frigate/review/maintainer.py
new file mode 100644
index 000000000..9e0a38210
--- /dev/null
+++ b/frigate/review/maintainer.py
@@ -0,0 +1,351 @@
+"""Maintain review segments in db."""
+
+import json
+import logging
+import os
+import random
+import string
+import threading
+from enum import Enum
+from multiprocessing.synchronize import Event as MpEvent
+from typing import Optional
+
+import cv2
+import numpy as np
+
+from frigate.comms.config_updater import ConfigSubscriber
+from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum
+from frigate.comms.inter_process import InterProcessRequestor
+from frigate.config import CameraConfig, FrigateConfig
+from frigate.const import CLIPS_DIR, UPSERT_REVIEW_SEGMENT
+from frigate.models import ReviewSegment
+from frigate.object_processing import TrackedObject
+from frigate.util.image import SharedMemoryFrameManager, calculate_16_9_crop
+
+logger = logging.getLogger(__name__)
+
+
+THUMB_HEIGHT = 180
+THUMB_WIDTH = 320
+
+
+class SeverityEnum(str, Enum):
+ alert = "alert"
+ detection = "detection"
+ signification_motion = "significant_motion"
+
+
+class PendingReviewSegment:
+ def __init__(
+ self,
+ camera: str,
+ frame_time: float,
+ severity: SeverityEnum,
+ detections: set[str] = set(),
+ objects: set[str] = set(),
+ sub_labels: set[str] = set(),
+ zones: set[str] = set(),
+ audio: set[str] = set(),
+ motion: list[int] = [],
+ ):
+ rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
+ self.id = f"{frame_time}-{rand_id}"
+ self.camera = camera
+ self.start_time = frame_time
+ self.severity = severity
+ self.detections = detections
+ self.objects = objects
+ self.sub_labels = sub_labels
+ self.zones = zones
+ self.audio = audio
+ self.sig_motion_areas = motion
+ self.last_update = frame_time
+
+ # thumbnail
+ self.frame = np.zeros((THUMB_HEIGHT * 3 // 2, THUMB_WIDTH), np.uint8)
+ self.frame_active_count = 0
+
+ def update_frame(
+ self, camera_config: CameraConfig, frame, objects: list[TrackedObject]
+ ):
+ min_x = camera_config.frame_shape[1]
+ min_y = camera_config.frame_shape[0]
+ max_x = 0
+ max_y = 0
+
+ # find bounds for all boxes
+ for o in objects:
+ min_x = min(o["box"][0], min_x)
+ min_y = min(o["box"][1], min_y)
+ max_x = max(o["box"][2], max_x)
+ max_y = max(o["box"][3], max_y)
+
+ region = calculate_16_9_crop(
+ camera_config.frame_shape, min_x, min_y, max_x, max_y
+ )
+
+ # could not find suitable 16:9 region
+ if not region:
+ return
+
+ self.frame_active_count = len(objects)
+ color_frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420)
+ color_frame = color_frame[region[1] : region[3], region[0] : region[2]]
+ width = int(THUMB_HEIGHT * color_frame.shape[1] / color_frame.shape[0])
+ self.frame = cv2.resize(
+ color_frame, dsize=(width, THUMB_HEIGHT), interpolation=cv2.INTER_AREA
+ )
+
+ def end(self) -> dict:
+ path = os.path.join(CLIPS_DIR, f"thumb-{self.camera}-{self.id}.jpg")
+
+ if self.frame is not None:
+ cv2.imwrite(path, self.frame)
+
+ return {
+ ReviewSegment.id: self.id,
+ ReviewSegment.camera: self.camera,
+ ReviewSegment.start_time: self.start_time,
+ ReviewSegment.end_time: self.last_update,
+ ReviewSegment.severity: self.severity.value,
+ ReviewSegment.thumb_path: path,
+ ReviewSegment.data: {
+ "detections": list(self.detections),
+ "objects": list(self.objects),
+ "sub_labels": list(self.sub_labels),
+ "zones": list(self.zones),
+ "audio": list(self.audio),
+ "significant_motion_areas": self.sig_motion_areas,
+ },
+ }
+
+
+class ReviewSegmentMaintainer(threading.Thread):
+ """Maintain review segments."""
+
+ def __init__(self, config: FrigateConfig, stop_event: MpEvent):
+ threading.Thread.__init__(self)
+ self.name = "review_segment_maintainer"
+ self.config = config
+ self.active_review_segments: dict[str, Optional[PendingReviewSegment]] = {}
+ self.frame_manager = SharedMemoryFrameManager()
+
+ # create communication for review segments
+ self.requestor = InterProcessRequestor()
+ self.config_subscriber = ConfigSubscriber("config/record/")
+ self.detection_subscriber = DetectionSubscriber(DetectionTypeEnum.all)
+
+ self.stop_event = stop_event
+
+ def end_segment(self, segment: PendingReviewSegment) -> None:
+ """End segment."""
+ seg_data = segment.end()
+ self.requestor.send_data(UPSERT_REVIEW_SEGMENT, seg_data)
+ self.requestor.send_data(
+ "reviews",
+ json.dumps(
+ {"type": "end", "review": {k.name: v for k, v in seg_data.items()}}
+ ),
+ )
+ self.active_review_segments[segment.camera] = None
+
+ def update_existing_segment(
+ self,
+ segment: PendingReviewSegment,
+ frame_time: float,
+ objects: list[TrackedObject],
+ motion: list,
+ ) -> None:
+ """Validate if existing review segment should continue."""
+ camera_config = self.config.cameras[segment.camera]
+ active_objects = get_active_objects(frame_time, camera_config, objects)
+
+ if len(active_objects) > 0:
+ segment.last_update = frame_time
+
+ # update type for this segment now that active objects are detected
+ if segment.severity == SeverityEnum.signification_motion:
+ segment.severity = SeverityEnum.detection
+
+ if len(active_objects) > segment.frame_active_count:
+ frame_id = f"{camera_config.name}{frame_time}"
+ yuv_frame = self.frame_manager.get(
+ frame_id, camera_config.frame_shape_yuv
+ )
+ segment.update_frame(camera_config, yuv_frame, active_objects)
+ self.frame_manager.close(frame_id)
+
+ for object in active_objects:
+ segment.detections.add(object["id"])
+ segment.objects.add(object["label"])
+
+ if object["sub_label"]:
+ segment.sub_labels.add(object["sub_label"][0])
+
+ # if object is alert label and has qualified for recording
+ # mark this review as alert
+ if (
+ segment.severity == SeverityEnum.detection
+ and object["has_clip"]
+ and object["label"] in camera_config.objects.alert
+ ):
+ segment.severity = SeverityEnum.alert
+
+ # keep zones up to date
+ if len(object["current_zones"]) > 0:
+ segment.zones.update(object["current_zones"])
+ elif (
+ segment.severity == SeverityEnum.signification_motion and len(motion) >= 20
+ ):
+ segment.last_update = frame_time
+ else:
+ if segment.severity == SeverityEnum.alert and frame_time > (
+ segment.last_update + 60
+ ):
+ self.end_segment(segment)
+ elif frame_time > (segment.last_update + 10):
+ self.end_segment(segment)
+
+ def check_if_new_segment(
+ self,
+ camera: str,
+ frame_time: float,
+ objects: list[TrackedObject],
+ motion: list,
+ ) -> None:
+ """Check if a new review segment should be created."""
+ camera_config = self.config.cameras[camera]
+ active_objects = get_active_objects(frame_time, camera_config, objects)
+
+ if len(active_objects) > 0:
+ has_sig_object = False
+ detections: set = set()
+ objects: set = set()
+ sub_labels: set = set()
+ zones: set = set()
+
+ for object in active_objects:
+ if (
+ not has_sig_object
+ and object["has_clip"]
+ and object["label"] in camera_config.objects.alert
+ ):
+ has_sig_object = True
+
+ detections.add(object["id"])
+ objects.add(object["label"])
+
+ if object["sub_label"]:
+ sub_labels.add(object["sub_label"][0])
+
+ zones.update(object["current_zones"])
+
+ self.active_review_segments[camera] = PendingReviewSegment(
+ camera,
+ frame_time,
+ SeverityEnum.alert if has_sig_object else SeverityEnum.detection,
+ detections,
+ objects=objects,
+ sub_labels=sub_labels,
+ audio=set(),
+ zones=zones,
+ motion=[],
+ )
+
+ frame_id = f"{camera_config.name}{frame_time}"
+ yuv_frame = self.frame_manager.get(frame_id, camera_config.frame_shape_yuv)
+ self.active_review_segments[camera].update_frame(
+ camera_config, yuv_frame, active_objects
+ )
+ self.frame_manager.close(frame_id)
+ elif len(motion) >= 20:
+ self.active_review_segments[camera] = PendingReviewSegment(
+ camera, frame_time, SeverityEnum.signification_motion, motion=motion
+ )
+
+ def run(self) -> None:
+ while not self.stop_event.is_set():
+ # check if there is an updated config
+ while True:
+ (
+ updated_topic,
+ updated_record_config,
+ ) = self.config_subscriber.check_for_update()
+
+ if not updated_topic:
+ break
+
+ camera_name = updated_topic.rpartition("/")[-1]
+ self.config.cameras[camera_name].record = updated_record_config
+
+ (topic, data) = self.detection_subscriber.get_data(timeout=1)
+
+ if not topic:
+ continue
+
+ if topic == DetectionTypeEnum.video:
+ (
+ camera,
+ frame_time,
+ current_tracked_objects,
+ motion_boxes,
+ regions,
+ ) = data
+ elif topic == DetectionTypeEnum.audio:
+ (
+ camera,
+ frame_time,
+ dBFS,
+ audio_detections,
+ ) = data
+
+ if not self.config.cameras[camera].record.enabled:
+ continue
+
+ current_segment = self.active_review_segments.get(camera)
+
+ if current_segment is not None:
+ if topic == DetectionTypeEnum.video:
+ self.update_existing_segment(
+ current_segment,
+ frame_time,
+ current_tracked_objects,
+ motion_boxes,
+ )
+ elif topic == DetectionTypeEnum.audio and len(audio_detections) > 0:
+ current_segment.last_update = frame_time
+ current_segment.audio.update(audio_detections)
+ else:
+ if topic == DetectionTypeEnum.video:
+ self.check_if_new_segment(
+ camera,
+ frame_time,
+ current_tracked_objects,
+ motion_boxes,
+ )
+ elif topic == DetectionTypeEnum.audio and len(audio_detections) > 0:
+ self.active_review_segments[camera] = PendingReviewSegment(
+ camera,
+ frame_time,
+ SeverityEnum.detection,
+ set(),
+ set(),
+ set(),
+ set(),
+ set(audio_detections),
+ [],
+ )
+
+
+def get_active_objects(
+ frame_time: float, camera_config: CameraConfig, all_objects: list[TrackedObject]
+) -> list[TrackedObject]:
+ """get active objects for detection."""
+ return [
+ o
+ for o in all_objects
+ if o["motionless_count"] < camera_config.detect.stationary.threshold
+ and o["position_changes"] > 0
+ and o["frame_time"] == frame_time
+ and not o["false_positive"]
+ ]
diff --git a/frigate/review/review.py b/frigate/review/review.py
new file mode 100644
index 000000000..dafa6c802
--- /dev/null
+++ b/frigate/review/review.py
@@ -0,0 +1,36 @@
+"""Run recording maintainer and cleanup."""
+
+import logging
+import multiprocessing as mp
+import signal
+import threading
+from types import FrameType
+from typing import Optional
+
+from setproctitle import setproctitle
+
+from frigate.config import FrigateConfig
+from frigate.review.maintainer import ReviewSegmentMaintainer
+from frigate.util.services import listen
+
+logger = logging.getLogger(__name__)
+
+
+def manage_review_segments(config: FrigateConfig) -> None:
+ stop_event = mp.Event()
+
+ def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None:
+ stop_event.set()
+
+ signal.signal(signal.SIGTERM, receiveSignal)
+ signal.signal(signal.SIGINT, receiveSignal)
+
+ threading.current_thread().name = "process:review_segment_manager"
+ setproctitle("frigate.review_segment_manager")
+ listen()
+
+ maintainer = ReviewSegmentMaintainer(
+ config,
+ stop_event,
+ )
+ maintainer.start()
diff --git a/frigate/stats/__init__.py b/frigate/stats/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/frigate/stats/emitter.py b/frigate/stats/emitter.py
new file mode 100644
index 000000000..048436514
--- /dev/null
+++ b/frigate/stats/emitter.py
@@ -0,0 +1,61 @@
+"""Emit stats to listeners."""
+
+import json
+import logging
+import threading
+import time
+from multiprocessing.synchronize import Event as MpEvent
+
+from frigate.comms.inter_process import InterProcessRequestor
+from frigate.config import FrigateConfig
+from frigate.stats.util import stats_snapshot
+from frigate.types import StatsTrackingTypes
+
+logger = logging.getLogger(__name__)
+
+
+class StatsEmitter(threading.Thread):
+ def __init__(
+ self,
+ config: FrigateConfig,
+ stats_tracking: StatsTrackingTypes,
+ stop_event: MpEvent,
+ ):
+ threading.Thread.__init__(self)
+ self.name = "frigate_stats_emitter"
+ self.config = config
+ self.stats_tracking = stats_tracking
+ self.stop_event = stop_event
+ self.hwaccel_errors: list[str] = []
+ self.stats_history: list[dict[str, any]] = []
+
+ # create communication for stats
+ self.requestor = InterProcessRequestor()
+
+ def get_latest_stats(self) -> dict[str, any]:
+ """Get latest stats."""
+ if len(self.stats_history) > 0:
+ return self.stats_history[-1]
+ else:
+ stats = stats_snapshot(
+ self.config, self.stats_tracking, self.hwaccel_errors
+ )
+ self.stats_history.append(stats)
+ return stats
+
+ def get_stats_history(self) -> list[dict[str, any]]:
+ """Get stats history."""
+ return self.stats_history
+
+ def run(self) -> None:
+ time.sleep(10)
+ while not self.stop_event.wait(self.config.mqtt.stats_interval):
+ logger.debug("Starting stats collection")
+ stats = stats_snapshot(
+ self.config, self.stats_tracking, self.hwaccel_errors
+ )
+ self.stats_history.append(stats)
+ self.stats_history = self.stats_history[-10:]
+ self.requestor.send_data("stats", json.dumps(stats))
+ logger.debug("Finished stats collection")
+ logger.info("Exiting stats emitter...")
diff --git a/frigate/stats.py b/frigate/stats/util.py
similarity index 87%
rename from frigate/stats.py
rename to frigate/stats/util.py
index addcd4a5b..8eb59e464 100644
--- a/frigate/stats.py
+++ b/frigate/stats/util.py
@@ -1,20 +1,17 @@
+"""Utilities for stats."""
+
import asyncio
-import json
-import logging
import os
import shutil
-import threading
import time
-from multiprocessing.synchronize import Event as MpEvent
from typing import Any, Optional
import psutil
import requests
from requests.exceptions import RequestException
-from frigate.comms.dispatcher import Dispatcher
from frigate.config import FrigateConfig
-from frigate.const import CACHE_DIR, CLIPS_DIR, DRIVER_AMD, DRIVER_ENV_VAR, RECORD_DIR
+from frigate.const import CACHE_DIR, CLIPS_DIR, RECORD_DIR
from frigate.object_detection import ObjectDetectProcess
from frigate.types import CameraMetricsTypes, StatsTrackingTypes
from frigate.util.services import (
@@ -24,11 +21,10 @@ from frigate.util.services import (
get_intel_gpu_stats,
get_jetson_stats,
get_nvidia_gpu_stats,
+ is_vaapi_amd_driver,
)
from frigate.version import VERSION
-logger = logging.getLogger(__name__)
-
def get_latest_version(config: FrigateConfig) -> str:
if not config.telemetry.version_check:
@@ -205,9 +201,7 @@ async def set_gpu_stats(
stats["intel-qsv"] = {"gpu": -1, "mem": -1}
hwaccel_errors.append(args)
elif "vaapi" in args:
- driver = os.environ.get(DRIVER_ENV_VAR)
-
- if driver == DRIVER_AMD:
+ if is_vaapi_amd_driver():
if not config.telemetry.stats.amd_gpu_stats:
continue
@@ -265,7 +259,7 @@ def stats_snapshot(
"process_fps": round(camera_stats["process_fps"].value, 2),
"skipped_fps": round(camera_stats["skipped_fps"].value, 2),
"detection_fps": round(camera_stats["detection_fps"].value, 2),
- "detection_enabled": camera_stats["detection_enabled"].value,
+ "detection_enabled": config.cameras[name].detect.enabled,
"pid": pid,
"capture_pid": cpid,
"ffmpeg_pid": ffmpeg_pid,
@@ -319,31 +313,3 @@ def stats_snapshot(
}
return stats
-
-
-class StatsEmitter(threading.Thread):
- def __init__(
- self,
- config: FrigateConfig,
- stats_tracking: StatsTrackingTypes,
- dispatcher: Dispatcher,
- stop_event: MpEvent,
- ):
- threading.Thread.__init__(self)
- self.name = "frigate_stats_emitter"
- self.config = config
- self.stats_tracking = stats_tracking
- self.dispatcher = dispatcher
- self.stop_event = stop_event
- self.hwaccel_errors: list[str] = []
-
- def run(self) -> None:
- time.sleep(10)
- while not self.stop_event.wait(self.config.mqtt.stats_interval):
- logger.debug("Starting stats collection")
- stats = stats_snapshot(
- self.config, self.stats_tracking, self.hwaccel_errors
- )
- self.dispatcher.publish("stats", json.dumps(stats), retain=False)
- logger.debug("Finished stats collection")
- logger.info("Exiting stats emitter...")
diff --git a/frigate/test/test_camera_pw.py b/frigate/test/test_camera_pw.py
index 137d3aad0..0964f38be 100644
--- a/frigate/test/test_camera_pw.py
+++ b/frigate/test/test_camera_pw.py
@@ -43,7 +43,7 @@ class TestUserPassMasking(unittest.TestCase):
self.rtsp_log_message = "Did you mean file:rtsp://user:password@192.168.1.3:554"
def test_rtsp_in_log_message(self):
- """Test that the rtsp url in a log message is espaced."""
+ """Test that the rtsp url in a log message is escaped."""
escaped = clean_camera_user_pass(self.rtsp_log_message)
print(f"The escaped is {escaped}")
assert escaped == "Did you mean file:rtsp://*:*@192.168.1.3:554"
diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py
index 94863709c..949438540 100644
--- a/frigate/test/test_config.py
+++ b/frigate/test/test_config.py
@@ -1,6 +1,7 @@
import json
import os
import unittest
+from unittest.mock import patch
import numpy as np
from pydantic import ValidationError
@@ -70,7 +71,9 @@ class TestConfig(unittest.TestCase):
assert runtime_config.detectors["cpu"].type == DetectorTypeEnum.cpu
assert runtime_config.detectors["cpu"].model.width == 320
- def test_detector_custom_model_path(self):
+ @patch("frigate.detectors.detector_config.load_labels")
+ def test_detector_custom_model_path(self, mock_labels):
+ mock_labels.return_value = {}
config = {
"detectors": {
"cpu": {
@@ -110,7 +113,7 @@ class TestConfig(unittest.TestCase):
assert runtime_config.detectors["openvino"].model.path == "/etc/hosts"
assert runtime_config.model.width == 512
- assert runtime_config.detectors["cpu"].model.width == 512
+ assert runtime_config.detectors["cpu"].model.width == 320
assert runtime_config.detectors["edgetpu"].model.width == 160
assert runtime_config.detectors["openvino"].model.width == 512
diff --git a/frigate/test/test_ffmpeg_presets.py b/frigate/test/test_ffmpeg_presets.py
index 469c28f1f..ac5e30a2d 100644
--- a/frigate/test/test_ffmpeg_presets.py
+++ b/frigate/test/test_ffmpeg_presets.py
@@ -41,9 +41,9 @@ class TestFfmpegPresets(unittest.TestCase):
assert self.default_ffmpeg == frigate_config.dict(exclude_unset=True)
def test_ffmpeg_hwaccel_preset(self):
- self.default_ffmpeg["cameras"]["back"]["ffmpeg"][
- "hwaccel_args"
- ] = "preset-rpi-64-h264"
+ self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["hwaccel_args"] = (
+ "preset-rpi-64-h264"
+ )
frigate_config = FrigateConfig(**self.default_ffmpeg)
frigate_config.cameras["back"].create_ffmpeg_cmds()
assert "preset-rpi-64-h264" not in (
@@ -54,9 +54,9 @@ class TestFfmpegPresets(unittest.TestCase):
)
def test_ffmpeg_hwaccel_not_preset(self):
- self.default_ffmpeg["cameras"]["back"]["ffmpeg"][
- "hwaccel_args"
- ] = "-other-hwaccel args"
+ self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["hwaccel_args"] = (
+ "-other-hwaccel args"
+ )
frigate_config = FrigateConfig(**self.default_ffmpeg)
frigate_config.cameras["back"].create_ffmpeg_cmds()
assert "-other-hwaccel args" in (
@@ -64,9 +64,9 @@ class TestFfmpegPresets(unittest.TestCase):
)
def test_ffmpeg_hwaccel_scale_preset(self):
- self.default_ffmpeg["cameras"]["back"]["ffmpeg"][
- "hwaccel_args"
- ] = "preset-nvidia-h264"
+ self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["hwaccel_args"] = (
+ "preset-nvidia-h264"
+ )
self.default_ffmpeg["cameras"]["back"]["detect"] = {
"height": 1920,
"width": 2560,
@@ -85,9 +85,9 @@ class TestFfmpegPresets(unittest.TestCase):
def test_default_ffmpeg_input_arg_preset(self):
frigate_config = FrigateConfig(**self.default_ffmpeg)
- self.default_ffmpeg["cameras"]["back"]["ffmpeg"][
- "input_args"
- ] = "preset-rtsp-generic"
+ self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["input_args"] = (
+ "preset-rtsp-generic"
+ )
frigate_preset_config = FrigateConfig(**self.default_ffmpeg)
frigate_config.cameras["back"].create_ffmpeg_cmds()
frigate_preset_config.cameras["back"].create_ffmpeg_cmds()
@@ -98,9 +98,9 @@ class TestFfmpegPresets(unittest.TestCase):
)
def test_ffmpeg_input_preset(self):
- self.default_ffmpeg["cameras"]["back"]["ffmpeg"][
- "input_args"
- ] = "preset-rtmp-generic"
+ self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["input_args"] = (
+ "preset-rtmp-generic"
+ )
frigate_config = FrigateConfig(**self.default_ffmpeg)
frigate_config.cameras["back"].create_ffmpeg_cmds()
assert "preset-rtmp-generic" not in (
@@ -131,9 +131,9 @@ class TestFfmpegPresets(unittest.TestCase):
)
def test_ffmpeg_output_record_preset(self):
- self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["output_args"][
- "record"
- ] = "preset-record-generic-audio-aac"
+ self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["output_args"]["record"] = (
+ "preset-record-generic-audio-aac"
+ )
frigate_config = FrigateConfig(**self.default_ffmpeg)
frigate_config.cameras["back"].create_ffmpeg_cmds()
assert "preset-record-generic-audio-aac" not in (
@@ -144,9 +144,9 @@ class TestFfmpegPresets(unittest.TestCase):
)
def test_ffmpeg_output_record_not_preset(self):
- self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["output_args"][
- "record"
- ] = "-some output"
+ self.default_ffmpeg["cameras"]["back"]["ffmpeg"]["output_args"]["record"] = (
+ "-some output"
+ )
frigate_config = FrigateConfig(**self.default_ffmpeg)
frigate_config.cameras["back"].create_ffmpeg_cmds()
assert "-some output" in (
diff --git a/frigate/test/test_http.py b/frigate/test/test_http.py
index 932a468a3..40f5b2677 100644
--- a/frigate/test/test_http.py
+++ b/frigate/test/test_http.py
@@ -3,7 +3,7 @@ import json
import logging
import os
import unittest
-from unittest.mock import patch
+from unittest.mock import Mock
from peewee_migrate import Router
from playhouse.shortcuts import model_to_dict
@@ -14,6 +14,7 @@ from frigate.config import FrigateConfig
from frigate.http import create_app
from frigate.models import Event, Recordings
from frigate.plus import PlusApi
+from frigate.stats.emitter import StatsEmitter
from frigate.test.const import TEST_DB, TEST_DB_CLEANUPS
@@ -119,8 +120,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
id = "123456.random"
id2 = "7890.random"
@@ -155,8 +156,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
id = "123456.random"
@@ -176,8 +177,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
id = "123456.random"
bad_id = "654321.other"
@@ -196,8 +197,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
id = "123456.random"
@@ -218,8 +219,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
id = "123456.random"
@@ -244,8 +245,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
morning_id = "123456.random"
evening_id = "654321.random"
@@ -282,8 +283,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
id = "123456.random"
sub_label = "sub"
@@ -317,8 +318,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
id = "123456.random"
sub_label = "sub"
@@ -342,8 +343,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
with app.test_client() as client:
@@ -359,8 +360,8 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ None,
)
id = "123456.random"
@@ -370,8 +371,9 @@ class TestHttp(unittest.TestCase):
assert recording
assert recording[0]["id"] == id
- @patch("frigate.http.stats_snapshot")
- def test_stats(self, mock_stats):
+ def test_stats(self):
+ stats = Mock(spec=StatsEmitter)
+ stats.get_latest_stats.return_value = self.test_stats
app = create_app(
FrigateConfig(**self.minimal_config).runtime_config(),
self.db,
@@ -379,14 +381,13 @@ class TestHttp(unittest.TestCase):
None,
None,
None,
- None,
PlusApi(),
+ stats,
)
- mock_stats.return_value = self.test_stats
with app.test_client() as client:
- stats = client.get("/stats").json
- assert stats == self.test_stats
+ full_stats = client.get("/stats").json
+ assert full_stats == self.test_stats
def _insert_mock_event(
diff --git a/frigate/test/test_video.py b/frigate/test/test_video.py
index cba63c950..8612990e2 100644
--- a/frigate/test/test_video.py
+++ b/frigate/test/test_video.py
@@ -148,8 +148,8 @@ class TestRegion(unittest.TestCase):
def test_combine_boxes(self):
boxes = [
- (460, 0, 561, 144),
- (565, 0, 586, 71),
+ (480, 0, 540, 128),
+ (536, 0, 558, 99),
]
# boundary_boxes = [get_cluster_boundary(box) for box in boxes]
@@ -167,8 +167,32 @@ class TestRegion(unittest.TestCase):
# save_clusters_image("combine", boxes, cluster_candidates, regions)
assert len(regions) == 1
+ def test_dont_combine_smaller_boxes(self):
+ boxes = [
+ (460, 0, 561, 144),
+ (565, 0, 586, 71),
+ ]
+
+ # boundary_boxes = [get_cluster_boundary(box) for box in boxes]
+ # save_cluster_boundary_image("combine_bound", boxes, boundary_boxes)
+
+ cluster_candidates = get_cluster_candidates(
+ self.frame_shape, self.min_region_size, boxes
+ )
+
+ regions = [
+ get_cluster_region(self.frame_shape, self.min_region_size, candidate, boxes)
+ for candidate in cluster_candidates
+ ]
+
+ # save_clusters_image("combine", boxes, cluster_candidates, regions)
+ assert len(regions) == 2
+
def test_dont_combine_boxes(self):
- boxes = [(460, 0, 532, 129), (586, 0, 606, 46)]
+ boxes = [
+ (460, 0, 532, 129),
+ (586, 0, 606, 46),
+ ]
# boundary_boxes = [get_cluster_boundary(box) for box in boxes]
# save_cluster_boundary_image("dont_combine_bound", boxes, boundary_boxes)
@@ -287,6 +311,15 @@ class TestObjectBoundingBoxes(unittest.TestCase):
consolidated_detections = reduce_detections(frame_shape, detections)
assert len(consolidated_detections) == len(detections)
+ def test_vert_stacked_cars_not_reduced(self):
+ detections = [
+ ("car", 0.8, (954, 312, 1247, 475), 498512, 1.48, (800, 200, 1400, 600)),
+ ("car", 0.85, (970, 380, 1273, 610), 698752, 1.56, (800, 200, 1400, 700)),
+ ]
+ frame_shape = (720, 1280)
+ consolidated_detections = reduce_detections(frame_shape, detections)
+ assert len(consolidated_detections) == len(detections)
+
class TestRegionGrid(unittest.TestCase):
def setUp(self) -> None:
diff --git a/frigate/track/__init__.py b/frigate/track/__init__.py
index 421a968da..3d9e45da2 100644
--- a/frigate/track/__init__.py
+++ b/frigate/track/__init__.py
@@ -5,9 +5,9 @@ from frigate.config import DetectConfig
class ObjectTracker(ABC):
@abstractmethod
- def __init__(self, config: DetectConfig):
+ def __init__(self, config: DetectConfig) -> None:
pass
@abstractmethod
- def match_and_update(self, detections):
+ def match_and_update(self, frame_time: float, detections) -> None:
pass
diff --git a/frigate/track/norfair_tracker.py b/frigate/track/norfair_tracker.py
index 3d7c9c618..04ec21aac 100644
--- a/frigate/track/norfair_tracker.py
+++ b/frigate/track/norfair_tracker.py
@@ -17,10 +17,15 @@ from frigate.ptz.autotrack import PtzMotionEstimator
from frigate.track import ObjectTracker
from frigate.types import PTZMetricsTypes
from frigate.util.image import intersection_over_union
+from frigate.util.object import average_boxes
logger = logging.getLogger(__name__)
+THRESHOLD_STATIONARY_IOU_AVERAGE = 0.6
+MAX_STATIONARY_HISTORY = 10
+
+
# Normalizes distance from estimate relative to object size
# Other ideas:
# - if estimates are inaccurate for first N detections, compare with last_detection (may be fine)
@@ -74,6 +79,7 @@ class NorfairTracker(ObjectTracker):
self.untracked_object_boxes: list[list[int]] = []
self.disappeared = {}
self.positions = {}
+ self.stationary_box_history: dict[str, list[list[int, int, int, int]]] = {}
self.camera_config = config
self.detect_config = config.detect
self.ptz_metrics = ptz_metrics
@@ -127,6 +133,7 @@ class NorfairTracker(ObjectTracker):
"xmax": self.detect_config.width,
"ymax": self.detect_config.height,
}
+ self.stationary_box_history[id] = []
def deregister(self, id, track_id):
del self.tracked_objects[id]
@@ -138,22 +145,24 @@ class NorfairTracker(ObjectTracker):
# tracks the current position of the object based on the last N bounding boxes
# returns False if the object has moved outside its previous position
- def update_position(self, id, box):
+ def update_position(self, id: str, box: list[int, int, int, int]):
position = self.positions[id]
- position_box = (
- position["xmin"],
- position["ymin"],
- position["xmax"],
- position["ymax"],
+ self.stationary_box_history[id].append(box)
+
+ if len(self.stationary_box_history[id]) > MAX_STATIONARY_HISTORY:
+ self.stationary_box_history[id] = self.stationary_box_history[id][
+ -MAX_STATIONARY_HISTORY:
+ ]
+
+ avg_iou = intersection_over_union(
+ box, average_boxes(self.stationary_box_history[id])
)
xmin, ymin, xmax, ymax = box
- iou = intersection_over_union(position_box, box)
-
# if the iou drops below the threshold
# assume the object has moved to a new position and reset the computed box
- if iou < 0.6:
+ if avg_iou < THRESHOLD_STATIONARY_IOU_AVERAGE:
self.positions[id] = {
"xmins": [xmin],
"ymins": [ymin],
@@ -220,6 +229,7 @@ class NorfairTracker(ObjectTracker):
):
self.tracked_objects[id]["position_changes"] += 1
self.tracked_objects[id]["motionless_count"] = 0
+ self.stationary_box_history[id] = []
self.tracked_objects[id].update(obj)
diff --git a/frigate/types.py b/frigate/types.py
index 4963b13db..e93391fb0 100644
--- a/frigate/types.py
+++ b/frigate/types.py
@@ -10,23 +10,16 @@ from frigate.object_detection import ObjectDetectProcess
class CameraMetricsTypes(TypedDict):
camera_fps: Synchronized
capture_process: Optional[Process]
- detection_enabled: Synchronized
detection_fps: Synchronized
detection_frame: Synchronized
ffmpeg_pid: Synchronized
frame_queue: Queue
- motion_enabled: Synchronized
- improve_contrast_enabled: Synchronized
- motion_threshold: Synchronized
- motion_contour_area: Synchronized
process: Optional[Process]
process_fps: Synchronized
read_start: Synchronized
skipped_fps: Synchronized
audio_rms: Synchronized
audio_dBFS: Synchronized
- birdseye_enabled: Synchronized
- birdseye_mode: Synchronized
class PTZMetricsTypes(TypedDict):
@@ -42,11 +35,6 @@ class PTZMetricsTypes(TypedDict):
ptz_min_zoom: Synchronized
-class FeatureMetricsTypes(TypedDict):
- audio_enabled: Synchronized
- record_enabled: Synchronized
-
-
class StatsTrackingTypes(TypedDict):
camera_metrics: dict[str, CameraMetricsTypes]
detectors: dict[str, ObjectDetectProcess]
diff --git a/frigate/util/image.py b/frigate/util/image.py
index 4fc3c2fd8..0afa451b7 100644
--- a/frigate/util/image.py
+++ b/frigate/util/image.py
@@ -211,6 +211,51 @@ def calculate_region(frame_shape, xmin, ymin, xmax, ymax, model_size, multiplier
return (x_offset, y_offset, x_offset + size, y_offset + size)
+def calculate_16_9_crop(frame_shape, xmin, ymin, xmax, ymax, multiplier=1.25):
+ min_size = 200
+
+ # size is the longest edge and divisible by 4
+ x_size = int(xmax - xmin * multiplier)
+
+ if x_size < min_size:
+ x_size = min_size
+
+ y_size = int(ymax - ymin * multiplier)
+
+ if y_size < min_size:
+ y_size = min_size
+
+ # calculate 16x9 using height
+ aspect_y_size = int(9 / 16 * x_size)
+
+ # if 16:9 by height is too small
+ if aspect_y_size < y_size or aspect_y_size > frame_shape[0]:
+ x_size = int((16 / 9) * y_size) // 4 * 4
+
+ if x_size / y_size > 1.8:
+ return None
+ else:
+ y_size = aspect_y_size // 4 * 4
+
+ # x_offset is midpoint of bounding box minus half the size
+ x_offset = int((xmax - xmin) / 2.0 + xmin - x_size / 2.0)
+ # if outside the image
+ if x_offset < 0:
+ x_offset = 0
+ elif x_offset > (frame_shape[1] - x_size):
+ x_offset = max(0, (frame_shape[1] - x_size))
+
+ # y_offset is midpoint of bounding box minus half the size
+ y_offset = int((ymax - ymin) / 2.0 + ymin - y_size / 2.0)
+ # # if outside the image
+ if y_offset < 0:
+ y_offset = 0
+ elif y_offset > (frame_shape[0] - y_size):
+ y_offset = max(0, (frame_shape[0] - y_size))
+
+ return (x_offset, y_offset, x_offset + x_size, y_offset + y_size)
+
+
def get_yuv_crop(frame_shape, crop):
# crop should be (x1,y1,x2,y2)
frame_height = frame_shape[0] // 3 * 2
@@ -347,7 +392,7 @@ def yuv_to_3_channel_yuv(yuv_frame):
# flatten the image into array
yuv_data = yuv_frame.ravel()
- # create a numpy array to hold all the 3 chanel yuv data
+ # create a numpy array to hold all the 3 channel yuv data
all_yuv_data = np.empty((height, width, 3), dtype=np.uint8)
y_count = height * width
@@ -575,7 +620,7 @@ def intersection_over_union(box_a, box_b):
# compute the intersection over union by taking the intersection
# area and dividing it by the sum of prediction + ground-truth
- # areas - the interesection area
+ # areas - the intersection area
iou = inter_area / float(box_a_area + box_b_area - inter_area)
# return the intersection over union value
diff --git a/frigate/util/object.py b/frigate/util/object.py
index 0bf7ea179..81940f303 100644
--- a/frigate/util/object.py
+++ b/frigate/util/object.py
@@ -10,7 +10,12 @@ import numpy as np
from peewee import DoesNotExist
from frigate.config import DetectConfig, ModelConfig
-from frigate.const import LABEL_CONSOLIDATION_DEFAULT, LABEL_CONSOLIDATION_MAP
+from frigate.const import (
+ LABEL_CONSOLIDATION_DEFAULT,
+ LABEL_CONSOLIDATION_MAP,
+ LABEL_NMS_DEFAULT,
+ LABEL_NMS_MAP,
+)
from frigate.detectors.detector_config import PixelFormatEnum
from frigate.models import Event, Regions, Timeline
from frigate.util.image import (
@@ -318,6 +323,22 @@ def reduce_boxes(boxes, iou_threshold=0.0):
return [tuple(c) for c in clusters]
+def average_boxes(boxes: list[list[int, int, int, int]]) -> list[int, int, int, int]:
+ """Return a box that is the average of a list of boxes."""
+ x_mins = []
+ y_mins = []
+ x_max = []
+ y_max = []
+
+ for box in boxes:
+ x_mins.append(box[0])
+ y_mins.append(box[1])
+ x_max.append(box[2])
+ y_max.append(box[3])
+
+ return [np.mean(x_mins), np.mean(y_mins), np.mean(x_max), np.mean(y_max)]
+
+
def intersects_any(box_a, boxes):
for box in boxes:
if box_overlaps(box_a, box):
@@ -414,7 +435,7 @@ def get_cluster_region(frame_shape, min_region, cluster, boxes):
max_x = max(boxes[b][2], max_x)
max_y = max(boxes[b][3], max_y)
return calculate_region(
- frame_shape, min_x, min_y, max_x, max_y, min_region, multiplier=1.2
+ frame_shape, min_x, min_y, max_x, max_y, min_region, multiplier=1.35
)
@@ -466,6 +487,7 @@ def reduce_detections(
selected_objects = []
for group in detected_object_groups.values():
+ label = group[0][0]
# o[2] is the box of the object: xmin, ymin, xmax, ymax
# apply max/min to ensure values do not exceed the known frame size
boxes = [
@@ -483,7 +505,9 @@ def reduce_detections(
# due to min score requirement of NMSBoxes
confidences = [0.6 if clipped(o, frame_shape) else o[1] for o in group]
- idxs = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
+ idxs = cv2.dnn.NMSBoxes(
+ boxes, confidences, 0.5, LABEL_NMS_MAP.get(label, LABEL_NMS_DEFAULT)
+ )
# add objects
for index in idxs:
diff --git a/frigate/util/services.py b/frigate/util/services.py
index 4c22bab2c..ae38b18ac 100644
--- a/frigate/util/services.py
+++ b/frigate/util/services.py
@@ -15,7 +15,12 @@ import psutil
import py3nvml.py3nvml as nvml
import requests
-from frigate.const import FFMPEG_HWACCEL_NVIDIA, FFMPEG_HWACCEL_VAAPI
+from frigate.const import (
+ DRIVER_AMD,
+ DRIVER_ENV_VAR,
+ FFMPEG_HWACCEL_NVIDIA,
+ FFMPEG_HWACCEL_VAAPI,
+)
from frigate.util.builtin import clean_camera_user_pass, escape_special_characters
logger = logging.getLogger(__name__)
@@ -98,8 +103,17 @@ def get_cpu_stats() -> dict[str, dict]:
docker_memlimit = get_docker_memlimit_bytes() / 1024
total_mem = os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES") / 1024
+ system_cpu = psutil.cpu_percent(
+ interval=None
+ ) # no interval as we don't want to be blocking
+ system_mem = psutil.virtual_memory()
+ usages["frigate.full_system"] = {
+ "cpu": str(system_cpu),
+ "mem": str(system_mem.percent),
+ }
+
for process in psutil.process_iter(["pid", "name", "cpu_percent", "cmdline"]):
- pid = process.info["pid"]
+ pid = str(process.info["pid"])
try:
cpu_percent = process.info["cpu_percent"]
cmdline = process.info["cmdline"]
@@ -196,6 +210,25 @@ def get_bandwidth_stats(config) -> dict[str, dict]:
return usages
+def is_vaapi_amd_driver() -> bool:
+ # Use the explicitly configured driver, if available
+ driver = os.environ.get(DRIVER_ENV_VAR)
+ if driver:
+ return driver == DRIVER_AMD
+
+ # Otherwise, ask vainfo what is has autodetected
+ p = vainfo_hwaccel()
+
+ if p.returncode != 0:
+ logger.error(f"Unable to poll vainfo: {p.stderr}")
+ return False
+ else:
+ output = p.stdout.decode("unicode_escape").split("\n")
+
+ # VA Info will print out the friendly name of the driver
+ return any("AMD Radeon Graphics" in line for line in output)
+
+
def get_amd_gpu_stats() -> dict[str, str]:
"""Get stats using radeontop."""
radeontop_command = ["radeontop", "-d", "-", "-l", "1"]
@@ -472,10 +505,20 @@ async def get_video_properties(url, get_duration=False) -> dict[str, any]:
# Get the height of frames in the video stream
height = video.get(cv2.CAP_PROP_FRAME_HEIGHT)
+ # Get the stream encoding
+ fourcc_int = int(video.get(cv2.CAP_PROP_FOURCC))
+ fourcc = (
+ chr((fourcc_int >> 0) & 255)
+ + chr((fourcc_int >> 8) & 255)
+ + chr((fourcc_int >> 16) & 255)
+ + chr((fourcc_int >> 24) & 255)
+ )
+
# Release the video stream
video.release()
result["width"] = round(width)
result["height"] = round(height)
+ result["fourcc"] = fourcc
return result
diff --git a/frigate/video.py b/frigate/video.py
index b5fafec0b..6d6230de7 100755
--- a/frigate/video.py
+++ b/frigate/video.py
@@ -11,6 +11,8 @@ import time
import cv2
from setproctitle import setproctitle
+from frigate.comms.config_updater import ConfigSubscriber
+from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import CameraConfig, DetectConfig, ModelConfig
from frigate.const import (
ALL_ATTRIBUTE_LABELS,
@@ -388,7 +390,6 @@ def track_camera(
detection_queue,
result_connection,
detected_objects_queue,
- inter_process_queue,
process_info,
ptz_metrics,
region_grid,
@@ -406,12 +407,6 @@ def track_camera(
listen()
frame_queue = process_info["frame_queue"]
- region_grid_queue = process_info["region_grid_queue"]
- detection_enabled = process_info["detection_enabled"]
- motion_enabled = process_info["motion_enabled"]
- improve_contrast_enabled = process_info["improve_contrast_enabled"]
- motion_threshold = process_info["motion_threshold"]
- motion_contour_area = process_info["motion_contour_area"]
frame_shape = config.frame_shape
objects_to_track = config.objects.track
@@ -421,9 +416,6 @@ def track_camera(
frame_shape,
config.motion,
config.detect.fps,
- improve_contrast_enabled,
- motion_threshold,
- motion_contour_area,
)
object_detector = RemoteObjectDetector(
name, labelmap, detection_queue, result_connection, model_config, stop_event
@@ -433,11 +425,13 @@ def track_camera(
frame_manager = SharedMemoryFrameManager()
+ # create communication for region grid updates
+ requestor = InterProcessRequestor()
+
process_frames(
name,
- inter_process_queue,
+ requestor,
frame_queue,
- region_grid_queue,
frame_shape,
model_config,
config.detect,
@@ -449,8 +443,6 @@ def track_camera(
process_info,
objects_to_track,
object_filters,
- detection_enabled,
- motion_enabled,
stop_event,
ptz_metrics,
region_grid,
@@ -505,9 +497,8 @@ def detect(
def process_frames(
camera_name: str,
- inter_process_queue: mp.Queue,
+ requestor: InterProcessRequestor,
frame_queue: mp.Queue,
- region_grid_queue: mp.Queue,
frame_shape,
model_config: ModelConfig,
detect_config: DetectConfig,
@@ -519,8 +510,6 @@ def process_frames(
process_info: dict,
objects_to_track: list[str],
object_filters,
- detection_enabled: mp.Value,
- motion_enabled: mp.Value,
stop_event,
ptz_metrics: PTZMetricsTypes,
region_grid,
@@ -530,6 +519,7 @@ def process_frames(
detection_fps = process_info["detection_fps"]
current_frame_time = process_info["detection_frame"]
next_region_update = get_tomorrow_at_time(2)
+ config_subscriber = ConfigSubscriber(f"config/detect/{camera_name}")
fps_tracker = EventsPerSecond()
fps_tracker.start()
@@ -540,17 +530,17 @@ def process_frames(
region_min_size = get_min_region_size(model_config)
while not stop_event.is_set():
+ # check for updated detect config
+ _, updated_detect_config = config_subscriber.check_for_update()
+
+ if updated_detect_config:
+ detect_config = updated_detect_config
+
if (
datetime.datetime.now().astimezone(datetime.timezone.utc)
> next_region_update
):
- inter_process_queue.put((REQUEST_REGION_GRID, camera_name))
-
- try:
- region_grid = region_grid_queue.get(True, 10)
- except queue.Empty:
- logger.error(f"Unable to get updated region grid for {camera_name}")
-
+ region_grid = requestor.send_data(REQUEST_REGION_GRID, camera_name)
next_region_update = get_tomorrow_at_time(2)
try:
@@ -576,13 +566,13 @@ def process_frames(
continue
# look for motion if enabled
- motion_boxes = motion_detector.detect(frame) if motion_enabled.value else []
+ motion_boxes = motion_detector.detect(frame)
regions = []
consolidated_detections = []
# if detection is disabled
- if not detection_enabled.value:
+ if not detect_config.enabled:
object_tracker.match_and_update(frame_time, [])
else:
# get stationary object ids
@@ -826,3 +816,7 @@ def process_frames(
)
detection_fps.value = object_detector.fps.eps()
frame_manager.close(f"{camera_name}{frame_time}")
+
+ motion_detector.stop()
+ requestor.stop()
+ config_subscriber.stop()
diff --git a/migrations/003_create_recordings_table.py b/migrations/003_create_recordings_table.py
index 82b15eb9c..77f9827cf 100644
--- a/migrations/003_create_recordings_table.py
+++ b/migrations/003_create_recordings_table.py
@@ -20,6 +20,7 @@ Some examples (model - class or model name)::
> migrator.add_default(model, field_name, default)
"""
+
import peewee as pw
SQL = pw.SQL
diff --git a/migrations/011_update_indexes.py b/migrations/011_update_indexes.py
index ddb0ba9a6..5c13baa54 100644
--- a/migrations/011_update_indexes.py
+++ b/migrations/011_update_indexes.py
@@ -20,6 +20,7 @@ Some examples (model - class or model name)::
> migrator.add_default(model, field_name, default)
"""
+
import peewee as pw
SQL = pw.SQL
diff --git a/migrations/017_update_indexes.py b/migrations/017_update_indexes.py
index 8aa53f8ee..66d1fcc6a 100644
--- a/migrations/017_update_indexes.py
+++ b/migrations/017_update_indexes.py
@@ -20,6 +20,7 @@ Some examples (model - class or model name)::
> migrator.add_default(model, field_name, default)
"""
+
import peewee as pw
SQL = pw.SQL
diff --git a/migrations/019_create_regions_table.py b/migrations/019_create_regions_table.py
index e1492581b..2900b78d2 100644
--- a/migrations/019_create_regions_table.py
+++ b/migrations/019_create_regions_table.py
@@ -20,6 +20,7 @@ Some examples (model - class or model name)::
> migrator.add_default(model, field_name, default)
"""
+
import peewee as pw
SQL = pw.SQL
diff --git a/migrations/020_update_index_recordings.py b/migrations/020_update_index_recordings.py
index 0aa86572d..7d0c2b860 100644
--- a/migrations/020_update_index_recordings.py
+++ b/migrations/020_update_index_recordings.py
@@ -20,6 +20,7 @@ Some examples (model - class or model name)::
> migrator.add_default(model, field_name, default)
"""
+
import peewee as pw
SQL = pw.SQL
diff --git a/migrations/021_create_previews_table.py b/migrations/021_create_previews_table.py
index 3ad131e0d..1036e7cdd 100644
--- a/migrations/021_create_previews_table.py
+++ b/migrations/021_create_previews_table.py
@@ -20,6 +20,7 @@ Some examples (model - class or model name)::
> migrator.add_default(model, field_name, default)
"""
+
import peewee as pw
SQL = pw.SQL
diff --git a/migrations/022_create_review_segment_table.py b/migrations/022_create_review_segment_table.py
new file mode 100644
index 000000000..681795e37
--- /dev/null
+++ b/migrations/022_create_review_segment_table.py
@@ -0,0 +1,42 @@
+"""Peewee migrations -- 022_create_review_segment_table.py.
+
+Some examples (model - class or model name)::
+
+ > Model = migrator.orm['model_name'] # Return model in current state by name
+
+ > migrator.sql(sql) # Run custom SQL
+ > migrator.python(func, *args, **kwargs) # Run python code
+ > migrator.create_model(Model) # Create a model (could be used as decorator)
+ > migrator.remove_model(model, cascade=True) # Remove a model
+ > migrator.add_fields(model, **fields) # Add fields to a model
+ > migrator.change_fields(model, **fields) # Change fields
+ > migrator.remove_fields(model, *field_names, cascade=True)
+ > migrator.rename_field(model, old_field_name, new_field_name)
+ > migrator.rename_table(model, new_table_name)
+ > migrator.add_index(model, *col_names, unique=False)
+ > migrator.drop_index(model, *col_names)
+ > migrator.add_not_null(model, *field_names)
+ > migrator.drop_not_null(model, *field_names)
+ > migrator.add_default(model, field_name, default)
+
+"""
+
+import peewee as pw
+
+SQL = pw.SQL
+
+
+def migrate(migrator, database, fake=False, **kwargs):
+ migrator.sql(
+ 'CREATE TABLE IF NOT EXISTS "reviewsegment" ("id" VARCHAR(30) NOT NULL PRIMARY KEY, "camera" VARCHAR(20) NOT NULL, "start_time" DATETIME NOT NULL, "end_time" DATETIME, "has_been_reviewed" INTEGER NOT NULL, "severity" VARCHAR(30) NOT NULL, "thumb_path" VARCHAR(255) NOT NULL, "data" JSON NOT NULL)'
+ )
+ migrator.sql(
+ 'CREATE INDEX IF NOT EXISTS "review_segment_camera" ON "reviewsegment" ("camera")'
+ )
+ migrator.sql(
+ 'CREATE INDEX "review_segment_start_time_end_time" ON "reviewsegment" ("start_time" DESC, "end_time" DESC)'
+ )
+
+
+def rollback(migrator, database, fake=False, **kwargs):
+ pass
diff --git a/web-old/.eslintrc b/web-old/.eslintrc
deleted file mode 100644
index 52704be7e..000000000
--- a/web-old/.eslintrc
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "env": {
- "browser": true,
- "es2021": true,
- "vitest-globals/env": true
- },
- "extends": ["eslint:recommended", "plugin:vitest-globals/recommended", "preact", "prettier"],
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "ecmaFeatures": {
- "jsx": true
- },
- "ecmaVersion": "latest",
- "sourceType": "module"
- },
- "settings": {
- "jest": {
- "version": 27
- }
- },
- "ignorePatterns": ["*.d.ts"],
- "rules": {
- "comma-dangle": [
- "error",
- {
- "objects": "always-multiline",
- "arrays": "always-multiline",
- "imports": "always-multiline"
- }
- ],
- "no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
- "no-console": "error"
- },
- "overrides": [
- {
- "files": ["**/*.{ts,tsx}"],
- "parser": "@typescript-eslint/parser",
- "plugins": ["@typescript-eslint"],
- "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"]
- }
- ]
-}
diff --git a/web-old/.gitignore b/web-old/.gitignore
deleted file mode 100644
index c2c07e8d4..000000000
--- a/web-old/.gitignore
+++ /dev/null
@@ -1,25 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
-.npm
\ No newline at end of file
diff --git a/web-old/.prettierrc b/web-old/.prettierrc
deleted file mode 100644
index 32922af63..000000000
--- a/web-old/.prettierrc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "printWidth": 120,
- "trailingComma": "es5",
- "singleQuote": true
-}
diff --git a/web-old/__test__/handlers.js b/web-old/__test__/handlers.js
deleted file mode 100644
index 8cb5279d2..000000000
--- a/web-old/__test__/handlers.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import { rest } from 'msw';
-// import { API_HOST } from '../src/env';
-
-export const handlers = [
- rest.get(`api/config`, (req, res, ctx) => {
- return res(
- ctx.status(200),
- ctx.json({
- mqtt: {
- stats_interval: 60,
- },
- service: {
- version: '0.8.3',
- },
- cameras: {
- front: {
- name: 'front',
- objects: { track: ['taco', 'cat', 'dog'] },
- audio: { enabled: false, enabled_in_config: false },
- record: { enabled: true, enabled_in_config: true },
- detect: { width: 1280, height: 720 },
- snapshots: {},
- restream: { enabled: true, jsmpeg: { height: 720 } },
- ui: { dashboard: true, order: 0 },
- },
- side: {
- name: 'side',
- objects: { track: ['taco', 'cat', 'dog'] },
- audio: { enabled: false, enabled_in_config: false },
- record: { enabled: false, enabled_in_config: true },
- detect: { width: 1280, height: 720 },
- snapshots: {},
- restream: { enabled: true, jsmpeg: { height: 720 } },
- ui: { dashboard: true, order: 1 },
- },
- },
- })
- );
- }),
- rest.get(`api/stats`, (req, res, ctx) => {
- return res(
- ctx.status(200),
- ctx.json({
- cpu_usages: { 74: {cpu: 6, mem: 6}, 64: { cpu: 5, mem: 5 }, 54: { cpu: 4, mem: 4 }, 71: { cpu: 3, mem: 3}, 60: {cpu: 2, mem: 2}, 72: {cpu: 1, mem: 1} },
- detection_fps: 0.0,
- detectors: { coral: { detection_start: 0.0, inference_speed: 8.94, pid: 52 } },
- front: { camera_fps: 5.0, capture_pid: 64, detection_fps: 0.0, pid: 54, process_fps: 0.0, skipped_fps: 0.0, ffmpeg_pid: 72 },
- side: {
- camera_fps: 6.9,
- capture_pid: 71,
- detection_fps: 0.0,
- pid: 60,
- process_fps: 0.0,
- skipped_fps: 0.0,
- ffmpeg_pid: 74,
- },
- service: { uptime: 34812, version: '0.8.1-d376f6b' },
- })
- );
- }),
- rest.get(`api/events`, (req, res, ctx) => {
- return res(
- ctx.status(200),
- ctx.json(
- new Array(12).fill(null).map((v, i) => ({
- end_time: 1613257337 + i,
- has_clip: true,
- has_snapshot: true,
- id: i,
- label: 'person',
- start_time: 1613257326 + i,
- top_score: Math.random(),
- zones: ['front_patio'],
- thumbnail: '/9j/4aa...',
- camera: 'camera_name',
- }))
- )
- );
- }),
- rest.get(`api/sub_labels`, (req, res, ctx) => {
- return res(
- ctx.status(200),
- ctx.json([
- 'one',
- 'two',
- ])
- );
- }),
- rest.get(`api/labels`, (req, res, ctx) => {
- return res(
- ctx.status(200),
- ctx.json([
- 'person',
- 'car',
- ])
- );
- }),
- rest.get(`api/go2rtc`, (req, res, ctx) => {
- return res(
- ctx.status(200),
- ctx.json({"config_path":"/dev/shm/go2rtc.yaml","host":"frigate.yourdomain.local","rtsp":{"listen":"0.0.0.0:8554","default_query":"mp4","PacketSize":0},"version":"1.7.1"})
- );
- }),
-];
diff --git a/web-old/__test__/test-setup.ts b/web-old/__test__/test-setup.ts
deleted file mode 100644
index b153238ae..000000000
--- a/web-old/__test__/test-setup.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import '@testing-library/jest-dom';
-import 'regenerator-runtime/runtime';
-// This creates a fake indexeddb so there is no need to mock idb-keyval
-import "fake-indexeddb/auto";
-import { setupServer } from 'msw/node';
-import { handlers } from './handlers';
-import { vi } from 'vitest';
-
-// This configures a request mocking server with the given request handlers.
-export const server = setupServer(...handlers);
-
-Object.defineProperty(window, 'matchMedia', {
- writable: true,
- value: (query) => ({
- matches: false,
- media: query,
- onchange: null,
- addEventListener: vi.fn(),
- removeEventListener: vi.fn(),
- dispatchEvent: vi.fn(),
- }),
-});
-
-vi.mock('../src/env');
-
-// Establish API mocking before all tests.
-beforeAll(() => server.listen());
-
-// Reset any request handlers that we may add during the tests,
-// so they don't affect other tests.
-afterEach(() => {
- server.resetHandlers();
-});
-
-// Clean up after the tests are finished.
-afterAll(() => server.close());
\ No newline at end of file
diff --git a/web-old/__test__/testing-library.js b/web-old/__test__/testing-library.js
deleted file mode 100644
index 257961aff..000000000
--- a/web-old/__test__/testing-library.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h } from 'preact';
-import { render } from '@testing-library/preact';
-import { ApiProvider } from '../src/api';
-
-const Wrapper = ({ children }) => {
- return (
- new Map(),
- }}
- >
- {children}
-
- );
-};
-
-const customRender = (ui, options) => render(ui, { wrapper: Wrapper, ...options });
-
-// re-export everything
-export * from '@testing-library/preact';
-
-// override render method
-export { customRender as render };
diff --git a/web-old/images/apple-touch-icon.png b/web-old/images/apple-touch-icon.png
deleted file mode 100644
index a0ca9e8eb..000000000
Binary files a/web-old/images/apple-touch-icon.png and /dev/null differ
diff --git a/web-old/images/favicon-16x16.png b/web-old/images/favicon-16x16.png
deleted file mode 100644
index bbe3207ea..000000000
Binary files a/web-old/images/favicon-16x16.png and /dev/null differ
diff --git a/web-old/images/favicon-32x32.png b/web-old/images/favicon-32x32.png
deleted file mode 100644
index 20e64b28a..000000000
Binary files a/web-old/images/favicon-32x32.png and /dev/null differ
diff --git a/web-old/images/favicon.ico b/web-old/images/favicon.ico
deleted file mode 100644
index 1de8ec804..000000000
Binary files a/web-old/images/favicon.ico and /dev/null differ
diff --git a/web-old/images/favicon.png b/web-old/images/favicon.png
deleted file mode 100644
index 60bf469e8..000000000
Binary files a/web-old/images/favicon.png and /dev/null differ
diff --git a/web-old/images/favicon.svg b/web-old/images/favicon.svg
deleted file mode 100644
index 066268a21..000000000
--- a/web-old/images/favicon.svg
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-Created by potrace 1.11, written by Peter Selinger 2001-2013
-
-
-
-
-
diff --git a/web-old/images/marker.png b/web-old/images/marker.png
deleted file mode 100644
index 3591e0aec..000000000
Binary files a/web-old/images/marker.png and /dev/null differ
diff --git a/web-old/images/mstile-150x150.png b/web-old/images/mstile-150x150.png
deleted file mode 100644
index 63ecc6140..000000000
Binary files a/web-old/images/mstile-150x150.png and /dev/null differ
diff --git a/web-old/index.html b/web-old/index.html
deleted file mode 100644
index dd08da893..000000000
--- a/web-old/index.html
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
- Frigate
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- You need to enable JavaScript to run this app.
-
-
-
diff --git a/web-old/package-lock.json b/web-old/package-lock.json
deleted file mode 100644
index ccceb07fe..000000000
--- a/web-old/package-lock.json
+++ /dev/null
@@ -1,16624 +0,0 @@
-{
- "name": "frigate",
- "version": "0.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "frigate",
- "version": "0.0.0",
- "dependencies": {
- "@cycjimmy/jsmpeg-player": "^6.0.5",
- "axios": "^1.5.0",
- "copy-to-clipboard": "3.3.3",
- "date-fns": "^2.30.0",
- "idb-keyval": "^6.2.0",
- "immer": "^10.0.1",
- "monaco-yaml": "^4.0.4",
- "preact": "^10.17.1",
- "preact-async-route": "^2.2.1",
- "preact-router": "^4.1.0",
- "react": "npm:@preact/compat@^17.1.2",
- "react-dom": "npm:@preact/compat@^17.1.2",
- "react-use-websocket": "^3.0.0",
- "strftime": "^0.10.1",
- "swr": "^1.3.0",
- "video.js": "^8.5.2",
- "videojs-playlist": "^5.1.0",
- "vite-plugin-monaco-editor": "^1.1.0"
- },
- "devDependencies": {
- "@preact/preset-vite": "^2.5.0",
- "@tailwindcss/forms": "^0.5.6",
- "@testing-library/jest-dom": "^6.1.2",
- "@testing-library/preact": "^3.2.3",
- "@testing-library/user-event": "^14.4.3",
- "@typescript-eslint/eslint-plugin": "^6.5.0",
- "@typescript-eslint/parser": "^6.5.0",
- "@vitest/coverage-v8": "^0.34.3",
- "@vitest/ui": "^0.34.3",
- "autoprefixer": "^10.4.15",
- "eslint": "^8.48.0",
- "eslint-config-preact": "^1.3.0",
- "eslint-config-prettier": "^9.0.0",
- "eslint-plugin-jest": "^27.2.3",
- "eslint-plugin-prettier": "^5.0.0",
- "eslint-plugin-vitest-globals": "^1.4.0",
- "fake-indexeddb": "^4.0.1",
- "jest-websocket-mock": "^2.5.0",
- "jsdom": "^22.0.0",
- "msw": "^1.2.1",
- "postcss": "^8.4.29",
- "prettier": "^3.0.3",
- "tailwindcss": "^3.3.2",
- "typescript": "^5.2.2",
- "vite": "^4.4.9",
- "vitest": "^0.34.3"
- }
- },
- "node_modules/@aashutoshrathi/word-wrap": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
- "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/@adobe/css-tools": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz",
- "integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==",
- "dev": true
- },
- "node_modules/@alloc/quick-lru": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
- "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@ampproject/remapping": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
- "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
- "dev": true,
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.3.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/code-frame": {
- "version": "7.22.13",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
- "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
- "dev": true,
- "dependencies": {
- "@babel/highlight": "^7.22.13",
- "chalk": "^2.4.2"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/compat-data": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz",
- "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/core": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
- "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
- "dev": true,
- "dependencies": {
- "@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.22.13",
- "@babel/generator": "^7.23.0",
- "@babel/helper-compilation-targets": "^7.22.15",
- "@babel/helper-module-transforms": "^7.23.0",
- "@babel/helpers": "^7.23.2",
- "@babel/parser": "^7.23.0",
- "@babel/template": "^7.22.15",
- "@babel/traverse": "^7.23.2",
- "@babel/types": "^7.23.0",
- "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/core/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/@babel/eslint-parser": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz",
- "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==",
- "dev": true,
- "dependencies": {
- "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
- "eslint-visitor-keys": "^2.1.0",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || >=14.0.0"
- },
- "peerDependencies": {
- "@babel/core": ">=7.11.0",
- "eslint": "^7.5.0 || ^8.0.0"
- }
- },
- "node_modules/@babel/eslint-parser/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/@babel/generator": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
- "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.23.0",
- "@jridgewell/gen-mapping": "^0.3.2",
- "@jridgewell/trace-mapping": "^0.3.17",
- "jsesc": "^2.5.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-annotate-as-pure": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
- "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.22.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-compilation-targets": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
- "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
- "dev": true,
- "dependencies": {
- "@babel/compat-data": "^7.22.9",
- "@babel/helper-validator-option": "^7.22.15",
- "browserslist": "^4.21.9",
- "lru-cache": "^5.1.1",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-compilation-targets/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/@babel/helper-compilation-targets/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/@babel/helper-environment-visitor": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
- "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-function-name": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
- "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
- "dev": true,
- "dependencies": {
- "@babel/template": "^7.22.15",
- "@babel/types": "^7.23.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-hoist-variables": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
- "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.22.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-imports": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
- "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.22.15"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-transforms": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz",
- "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-module-imports": "^7.22.15",
- "@babel/helper-simple-access": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/helper-validator-identifier": "^7.22.20"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-plugin-utils": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
- "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-simple-access": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
- "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.22.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.22.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-string-parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
- "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-option": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
- "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helpers": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz",
- "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==",
- "dev": true,
- "dependencies": {
- "@babel/template": "^7.22.15",
- "@babel/traverse": "^7.23.2",
- "@babel/types": "^7.23.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
- "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.22.20",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/parser": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
- "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
- "dev": true,
- "bin": {
- "parser": "bin/babel-parser.js"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/plugin-syntax-class-properties": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
- "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.12.13"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-decorators": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz",
- "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.19.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-jsx": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz",
- "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.22.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-react-jsx": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz",
- "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-module-imports": "^7.22.15",
- "@babel/helper-plugin-utils": "^7.22.5",
- "@babel/plugin-syntax-jsx": "^7.22.5",
- "@babel/types": "^7.22.15"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-react-jsx-development": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz",
- "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==",
- "dev": true,
- "dependencies": {
- "@babel/plugin-transform-react-jsx": "^7.22.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.21.5",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz",
- "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==",
- "dependencies": {
- "regenerator-runtime": "^0.13.11"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/template": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
- "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.22.13",
- "@babel/parser": "^7.22.15",
- "@babel/types": "^7.22.15"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/traverse": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
- "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.22.13",
- "@babel/generator": "^7.23.0",
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-function-name": "^7.23.0",
- "@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.23.0",
- "@babel/types": "^7.23.0",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/types": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
- "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@bcoe/v8-coverage": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
- "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
- "dev": true
- },
- "node_modules/@cycjimmy/jsmpeg-player": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/@cycjimmy/jsmpeg-player/-/jsmpeg-player-6.0.5.tgz",
- "integrity": "sha512-bVNHQ7VN9ecKT5AI/6RC7zpW/y4ca68a9txeR5Wiin+jKpUn/7buMe+5NPub89A8NNeNnKPQfrD2+c76ch36mA=="
- },
- "node_modules/@esbuild/android-arm": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz",
- "integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz",
- "integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/android-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz",
- "integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz",
- "integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/darwin-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz",
- "integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz",
- "integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/freebsd-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz",
- "integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz",
- "integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz",
- "integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ia32": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz",
- "integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-loong64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz",
- "integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-mips64el": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz",
- "integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-ppc64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz",
- "integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-riscv64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz",
- "integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-s390x": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz",
- "integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/linux-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz",
- "integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/netbsd-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz",
- "integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/openbsd-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz",
- "integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/sunos-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz",
- "integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz",
- "integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-ia32": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz",
- "integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@esbuild/win32-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz",
- "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@eslint-community/eslint-utils": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
- "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
- "dev": true,
- "dependencies": {
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
- }
- },
- "node_modules/@eslint-community/regexpp": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz",
- "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==",
- "dev": true,
- "engines": {
- "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
- "dev": true,
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/globals": {
- "version": "13.23.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
- "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
- "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/@eslint/js": {
- "version": "8.55.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz",
- "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.11.13",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
- "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
- "dev": true,
- "dependencies": {
- "@humanwhocodes/object-schema": "^2.0.1",
- "debug": "^4.1.1",
- "minimatch": "^3.0.5"
- },
- "engines": {
- "node": ">=10.10.0"
- }
- },
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true,
- "engines": {
- "node": ">=12.22"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
- "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
- "dev": true
- },
- "node_modules/@istanbuljs/schema": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
- "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/schemas": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
- "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
- "dev": true,
- "dependencies": {
- "@sinclair/typebox": "^0.27.8"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
- "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
- "dev": true,
- "dependencies": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/resolve-uri": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
- "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
- "dev": true,
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
- "dev": true,
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.14",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
- "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
- "dev": true
- },
- "node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.17",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
- "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
- "dev": true,
- "dependencies": {
- "@jridgewell/resolve-uri": "3.1.0",
- "@jridgewell/sourcemap-codec": "1.4.14"
- }
- },
- "node_modules/@mdn/browser-compat-data": {
- "version": "5.3.6",
- "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.3.6.tgz",
- "integrity": "sha512-sDz0Yjj8m+VTWPiC0TF28rLMCDS2fJTZZmDpFMx5Y0H4NVGzqOs30l4pV8Tpexen4GyT+wYCNjedY8pTNjiW7Q==",
- "dev": true
- },
- "node_modules/@mswjs/cookies": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz",
- "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==",
- "dev": true,
- "dependencies": {
- "@types/set-cookie-parser": "^2.4.0",
- "set-cookie-parser": "^2.4.6"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/@mswjs/interceptors": {
- "version": "0.17.10",
- "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.10.tgz",
- "integrity": "sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw==",
- "dev": true,
- "dependencies": {
- "@open-draft/until": "^1.0.3",
- "@types/debug": "^4.1.7",
- "@xmldom/xmldom": "^0.8.3",
- "debug": "^4.3.3",
- "headers-polyfill": "3.2.5",
- "outvariant": "^1.2.1",
- "strict-event-emitter": "^0.2.4",
- "web-encoding": "^1.1.5"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
- "version": "5.1.1-v1",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
- "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==",
- "dev": true,
- "dependencies": {
- "eslint-scope": "5.1.1"
- }
- },
- "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/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/@nicolo-ribaudo/eslint-scope-5-internals/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/@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/@open-draft/until": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz",
- "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==",
- "dev": true
- },
- "node_modules/@pkgr/utils": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz",
- "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "fast-glob": "^3.3.0",
- "is-glob": "^4.0.3",
- "open": "^9.1.0",
- "picocolors": "^1.0.0",
- "tslib": "^2.6.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/unts"
- }
- },
- "node_modules/@polka/url": {
- "version": "1.0.0-next.21",
- "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
- "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
- "dev": true
- },
- "node_modules/@preact/preset-vite": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.7.0.tgz",
- "integrity": "sha512-m5N0FVtxbCCDxNk55NGhsRpKJChYcupcuQHzMJc/Bll07IKZKn8amwYciyKFS9haU6AgzDAJ/ewvApr6Qg1DHw==",
- "dev": true,
- "dependencies": {
- "@babel/plugin-transform-react-jsx": "^7.22.15",
- "@babel/plugin-transform-react-jsx-development": "^7.22.5",
- "@prefresh/vite": "^2.4.1",
- "@rollup/pluginutils": "^4.1.1",
- "babel-plugin-transform-hook-names": "^1.0.2",
- "debug": "^4.3.4",
- "kolorist": "^1.8.0",
- "resolve": "^1.22.8"
- },
- "peerDependencies": {
- "@babel/core": "7.x",
- "vite": "2.x || 3.x || 4.x || 5.x"
- }
- },
- "node_modules/@prefresh/babel-plugin": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/@prefresh/babel-plugin/-/babel-plugin-0.5.0.tgz",
- "integrity": "sha512-joAwpkUDwo7ZqJnufXRGzUb+udk20RBgfA8oLPBh5aJH2LeStmV1luBfeJTztPdyCscC2j2SmZ/tVxFRMIxAEw==",
- "dev": true
- },
- "node_modules/@prefresh/core": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/@prefresh/core/-/core-1.5.2.tgz",
- "integrity": "sha512-A/08vkaM1FogrCII5PZKCrygxSsc11obExBScm3JF1CryK2uDS3ZXeni7FeKCx1nYdUkj4UcJxzPzc1WliMzZA==",
- "dev": true,
- "peerDependencies": {
- "preact": "^10.0.0"
- }
- },
- "node_modules/@prefresh/utils": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@prefresh/utils/-/utils-1.2.0.tgz",
- "integrity": "sha512-KtC/fZw+oqtwOLUFM9UtiitB0JsVX0zLKNyRTA332sqREqSALIIQQxdUCS1P3xR/jT1e2e8/5rwH6gdcMLEmsQ==",
- "dev": true
- },
- "node_modules/@prefresh/vite": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/@prefresh/vite/-/vite-2.4.1.tgz",
- "integrity": "sha512-vthWmEqu8TZFeyrBNc9YE5SiC3DVSzPgsOCp/WQ7FqdHpOIJi7Z8XvCK06rBPOtG4914S52MjG9Ls22eVAiuqQ==",
- "dev": true,
- "dependencies": {
- "@babel/core": "^7.22.1",
- "@prefresh/babel-plugin": "0.5.0",
- "@prefresh/core": "^1.5.1",
- "@prefresh/utils": "^1.2.0",
- "@rollup/pluginutils": "^4.2.1"
- },
- "peerDependencies": {
- "preact": "^10.4.0",
- "vite": ">=2.0.0"
- }
- },
- "node_modules/@rollup/pluginutils": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
- "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
- "dev": true,
- "dependencies": {
- "estree-walker": "^2.0.1",
- "picomatch": "^2.2.2"
- },
- "engines": {
- "node": ">= 8.0.0"
- }
- },
- "node_modules/@sinclair/typebox": {
- "version": "0.27.8",
- "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
- "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
- "dev": true
- },
- "node_modules/@tailwindcss/forms": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz",
- "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==",
- "dev": true,
- "dependencies": {
- "mini-svg-data-uri": "^1.2.3"
- },
- "peerDependencies": {
- "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1"
- }
- },
- "node_modules/@testing-library/dom": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.0.tgz",
- "integrity": "sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.10.4",
- "@babel/runtime": "^7.12.5",
- "@types/aria-query": "^4.2.0",
- "aria-query": "^5.0.0",
- "chalk": "^4.1.0",
- "dom-accessibility-api": "^0.5.9",
- "lz-string": "^1.4.4",
- "pretty-format": "^27.0.2"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@testing-library/dom/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/@testing-library/dom/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/@testing-library/dom/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/@testing-library/dom/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/@testing-library/dom/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/@testing-library/dom/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/@testing-library/jest-dom": {
- "version": "6.1.5",
- "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.1.5.tgz",
- "integrity": "sha512-3y04JLW+EceVPy2Em3VwNr95dOKqA8DhR0RJHhHKDZNYXcVXnEK7WIrpj4eYU8SVt/qYZ2aRWt/WgQ+grNES8g==",
- "dev": true,
- "dependencies": {
- "@adobe/css-tools": "^4.3.1",
- "@babel/runtime": "^7.9.2",
- "aria-query": "^5.0.0",
- "chalk": "^3.0.0",
- "css.escape": "^1.5.1",
- "dom-accessibility-api": "^0.5.6",
- "lodash": "^4.17.15",
- "redent": "^3.0.0"
- },
- "engines": {
- "node": ">=14",
- "npm": ">=6",
- "yarn": ">=1"
- },
- "peerDependencies": {
- "@jest/globals": ">= 28",
- "@types/jest": ">= 28",
- "jest": ">= 28",
- "vitest": ">= 0.32"
- },
- "peerDependenciesMeta": {
- "@jest/globals": {
- "optional": true
- },
- "@types/jest": {
- "optional": true
- },
- "jest": {
- "optional": true
- },
- "vitest": {
- "optional": true
- }
- }
- },
- "node_modules/@testing-library/jest-dom/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/@testing-library/jest-dom/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/@testing-library/jest-dom/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/@testing-library/jest-dom/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/@testing-library/jest-dom/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/@testing-library/jest-dom/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/@testing-library/preact": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@testing-library/preact/-/preact-3.2.3.tgz",
- "integrity": "sha512-y6Kklp1XK3f1X2fWCbujmJyzkf+1BgLYXNgAx21j9+D4CoqMTz5qC4SQufb1L6q/jxLGACzrQ90ewVOTBvHOfg==",
- "dev": true,
- "dependencies": {
- "@testing-library/dom": "^8.11.1"
- },
- "engines": {
- "node": ">= 12"
- },
- "peerDependencies": {
- "preact": ">=10 || ^10.0.0-alpha.0 || ^10.0.0-beta.0"
- }
- },
- "node_modules/@testing-library/user-event": {
- "version": "14.5.1",
- "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.1.tgz",
- "integrity": "sha512-UCcUKrUYGj7ClomOo2SpNVvx4/fkd/2BbIHDCle8A0ax+P3bU7yJwDBDrS6ZwdTMARWTGODX1hEsCcO+7beJjg==",
- "dev": true,
- "engines": {
- "node": ">=12",
- "npm": ">=6"
- },
- "peerDependencies": {
- "@testing-library/dom": ">=7.21.4"
- }
- },
- "node_modules/@tootallnate/once": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
- "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@tsconfig/node14": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
- "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
- "dev": true
- },
- "node_modules/@types/aria-query": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz",
- "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==",
- "dev": true
- },
- "node_modules/@types/chai": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
- "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==",
- "dev": true
- },
- "node_modules/@types/chai-subset": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz",
- "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==",
- "dev": true,
- "dependencies": {
- "@types/chai": "*"
- }
- },
- "node_modules/@types/concat-stream": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz",
- "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/cookie": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
- "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
- "dev": true
- },
- "node_modules/@types/debug": {
- "version": "4.1.9",
- "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.9.tgz",
- "integrity": "sha512-8Hz50m2eoS56ldRlepxSBa6PWEVCtzUo/92HgLc2qTMnotJNIm7xP+UZhyWoYsyOdd5dxZ+NZLb24rsKyFs2ow==",
- "dev": true,
- "dependencies": {
- "@types/ms": "*"
- }
- },
- "node_modules/@types/form-data": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz",
- "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/istanbul-lib-coverage": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
- "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
- "dev": true
- },
- "node_modules/@types/js-levenshtein": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz",
- "integrity": "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==",
- "dev": true
- },
- "node_modules/@types/json-schema": {
- "version": "7.0.12",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
- "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA=="
- },
- "node_modules/@types/ms": {
- "version": "0.7.31",
- "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",
- "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
- "dev": true
- },
- "node_modules/@types/node": {
- "version": "18.11.9",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
- "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
- "dev": true
- },
- "node_modules/@types/qs": {
- "version": "6.9.7",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
- "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "node_modules/@types/semver": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
- "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==",
- "dev": true
- },
- "node_modules/@types/set-cookie-parser": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz",
- "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==",
- "dev": true,
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz",
- "integrity": "sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==",
- "dev": true,
- "dependencies": {
- "@eslint-community/regexpp": "^4.5.1",
- "@typescript-eslint/scope-manager": "6.13.2",
- "@typescript-eslint/type-utils": "6.13.2",
- "@typescript-eslint/utils": "6.13.2",
- "@typescript-eslint/visitor-keys": "6.13.2",
- "debug": "^4.3.4",
- "graphemer": "^1.4.0",
- "ignore": "^5.2.4",
- "natural-compare": "^1.4.0",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
- "eslint": "^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz",
- "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/utils": "5.62.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
- "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
- "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
- "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
- "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@types/json-schema": "^7.0.9",
- "@types/semver": "^7.3.12",
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/typescript-estree": "5.62.0",
- "eslint-scope": "^5.1.1",
- "semver": "^7.3.7"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
- "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/experimental-utils/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/@typescript-eslint/experimental-utils/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/@typescript-eslint/experimental-utils/node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/parser": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz",
- "integrity": "sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/scope-manager": "6.13.2",
- "@typescript-eslint/types": "6.13.2",
- "@typescript-eslint/typescript-estree": "6.13.2",
- "@typescript-eslint/visitor-keys": "6.13.2",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz",
- "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "6.13.2",
- "@typescript-eslint/visitor-keys": "6.13.2"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/type-utils": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz",
- "integrity": "sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/typescript-estree": "6.13.2",
- "@typescript-eslint/utils": "6.13.2",
- "debug": "^4.3.4",
- "ts-api-utils": "^1.0.1"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz",
- "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==",
- "dev": true,
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz",
- "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "6.13.2",
- "@typescript-eslint/visitor-keys": "6.13.2",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/utils": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz",
- "integrity": "sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@types/json-schema": "^7.0.12",
- "@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "6.13.2",
- "@typescript-eslint/types": "6.13.2",
- "@typescript-eslint/typescript-estree": "6.13.2",
- "semver": "^7.5.4"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz",
- "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "6.13.2",
- "eslint-visitor-keys": "^3.4.1"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@ungap/structured-clone": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
- "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
- "dev": true
- },
- "node_modules/@videojs/http-streaming": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-3.7.0.tgz",
- "integrity": "sha512-5uLFKBL8CvD56dxxJyuxqB5CY0tdoa4SE9KbXakeiAy6iFBUEPvTr2YGLKEWvQ8Lojs1wl+FQndLdv+GO7t9Fw==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "4.0.0",
- "aes-decrypter": "4.0.1",
- "global": "^4.4.0",
- "m3u8-parser": "^7.1.0",
- "mpd-parser": "^1.2.2",
- "mux.js": "7.0.1",
- "video.js": "^7 || ^8"
- },
- "engines": {
- "node": ">=8",
- "npm": ">=5"
- },
- "peerDependencies": {
- "video.js": "^7 || ^8"
- }
- },
- "node_modules/@videojs/http-streaming/node_modules/m3u8-parser": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-7.1.0.tgz",
- "integrity": "sha512-7N+pk79EH4oLKPEYdgRXgAsKDyA/VCo0qCHlUwacttQA0WqsjZQYmNfywMvjlY9MpEBVZEt0jKFd73Kv15EBYQ==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.5",
- "global": "^4.4.0"
- }
- },
- "node_modules/@videojs/http-streaming/node_modules/m3u8-parser/node_modules/@videojs/vhs-utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
- "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- },
- "engines": {
- "node": ">=8",
- "npm": ">=5"
- }
- },
- "node_modules/@videojs/vhs-utils": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-4.0.0.tgz",
- "integrity": "sha512-xJp7Yd4jMLwje2vHCUmi8MOUU76nxiwII3z4Eg3Ucb+6rrkFVGosrXlMgGnaLjq724j3wzNElRZ71D/CKrTtxg==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- },
- "engines": {
- "node": ">=8",
- "npm": ">=5"
- }
- },
- "node_modules/@videojs/xhr": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.6.0.tgz",
- "integrity": "sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q==",
- "dependencies": {
- "@babel/runtime": "^7.5.5",
- "global": "~4.4.0",
- "is-function": "^1.0.1"
- }
- },
- "node_modules/@vitest/coverage-v8": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-0.34.6.tgz",
- "integrity": "sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==",
- "dev": true,
- "dependencies": {
- "@ampproject/remapping": "^2.2.1",
- "@bcoe/v8-coverage": "^0.2.3",
- "istanbul-lib-coverage": "^3.2.0",
- "istanbul-lib-report": "^3.0.1",
- "istanbul-lib-source-maps": "^4.0.1",
- "istanbul-reports": "^3.1.5",
- "magic-string": "^0.30.1",
- "picocolors": "^1.0.0",
- "std-env": "^3.3.3",
- "test-exclude": "^6.0.0",
- "v8-to-istanbul": "^9.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- },
- "peerDependencies": {
- "vitest": ">=0.32.0 <1"
- }
- },
- "node_modules/@vitest/expect": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz",
- "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==",
- "dev": true,
- "dependencies": {
- "@vitest/spy": "0.34.6",
- "@vitest/utils": "0.34.6",
- "chai": "^4.3.10"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/runner": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz",
- "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==",
- "dev": true,
- "dependencies": {
- "@vitest/utils": "0.34.6",
- "p-limit": "^4.0.0",
- "pathe": "^1.1.1"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/runner/node_modules/p-limit": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
- "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^1.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@vitest/runner/node_modules/yocto-queue": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
- "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
- "dev": true,
- "engines": {
- "node": ">=12.20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@vitest/snapshot": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz",
- "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==",
- "dev": true,
- "dependencies": {
- "magic-string": "^0.30.1",
- "pathe": "^1.1.1",
- "pretty-format": "^29.5.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/snapshot/node_modules/ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@vitest/snapshot/node_modules/pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
- "dev": true,
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@vitest/snapshot/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- },
- "node_modules/@vitest/spy": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz",
- "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==",
- "dev": true,
- "dependencies": {
- "tinyspy": "^2.1.1"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/ui": {
- "version": "0.34.7",
- "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.34.7.tgz",
- "integrity": "sha512-iizUu9R5Rsvsq8FtdJ0suMqEfIsIIzziqnasMHe4VH8vG+FnZSA3UAtCHx6rLeRupIFVAVg7bptMmuvMcsn8WQ==",
- "dev": true,
- "dependencies": {
- "@vitest/utils": "0.34.7",
- "fast-glob": "^3.3.0",
- "fflate": "^0.8.0",
- "flatted": "^3.2.7",
- "pathe": "^1.1.1",
- "picocolors": "^1.0.0",
- "sirv": "^2.0.3"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- },
- "peerDependencies": {
- "vitest": ">=0.30.1 <1"
- }
- },
- "node_modules/@vitest/ui/node_modules/@vitest/utils": {
- "version": "0.34.7",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.7.tgz",
- "integrity": "sha512-ziAavQLpCYS9sLOorGrFFKmy2gnfiNU0ZJ15TsMz/K92NAPS/rp9K4z6AJQQk5Y8adCy4Iwpxy7pQumQ/psnRg==",
- "dev": true,
- "dependencies": {
- "diff-sequences": "^29.4.3",
- "loupe": "^2.3.6",
- "pretty-format": "^29.5.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/ui/node_modules/ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@vitest/ui/node_modules/pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
- "dev": true,
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@vitest/ui/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- },
- "node_modules/@vitest/utils": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz",
- "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==",
- "dev": true,
- "dependencies": {
- "diff-sequences": "^29.4.3",
- "loupe": "^2.3.6",
- "pretty-format": "^29.5.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/@vitest/utils/node_modules/ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@vitest/utils/node_modules/pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
- "dev": true,
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@vitest/utils/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- },
- "node_modules/@xmldom/xmldom": {
- "version": "0.8.7",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.7.tgz",
- "integrity": "sha512-sI1Ly2cODlWStkINzqGrZ8K6n+MTSbAeQnAipGyL+KZCXuHaRlj2gyyy8B/9MvsFFqN7XHryQnB2QwhzvJXovg==",
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/@zxing/text-encoding": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
- "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
- "dev": true,
- "optional": true
- },
- "node_modules/abab": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
- "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
- "dev": true
- },
- "node_modules/acorn": {
- "version": "8.10.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
- "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
- "dev": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-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.2.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
- "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
- "dev": true,
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/aes-decrypter": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-4.0.1.tgz",
- "integrity": "sha512-H1nh/P9VZXUf17AA5NQfJML88CFjVBDuGkp5zDHa7oEhYN9TTpNLJknRY1ie0iSKWlDf6JRnJKaZVDSQdPy6Cg==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.5",
- "global": "^4.4.0",
- "pkcs7": "^1.0.4"
- }
- },
- "node_modules/aes-decrypter/node_modules/@videojs/vhs-utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
- "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- },
- "engines": {
- "node": ">=8",
- "npm": ">=5"
- }
- },
- "node_modules/agent-base": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
- "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
- "dev": true,
- "dependencies": {
- "debug": "4"
- },
- "engines": {
- "node": ">= 6.0.0"
- }
- },
- "node_modules/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/ansi-escapes": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
- "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
- "dev": true,
- "dependencies": {
- "type-fest": "^0.21.3"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/ansi-escapes/node_modules/type-fest": {
- "version": "0.21.3",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
- "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "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": "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/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.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
- "dev": true,
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/arg": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
- "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
- "dev": true
- },
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "node_modules/aria-query": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
- "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
- "dev": true,
- "dependencies": {
- "deep-equal": "^2.0.5"
- }
- },
- "node_modules/array-includes": {
- "version": "3.1.6",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
- "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "get-intrinsic": "^1.1.3",
- "is-string": "^1.0.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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/array.prototype.flatmap": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz",
- "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "es-shim-unscopables": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/asap": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
- "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "node_modules/assertion-error": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
- "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/ast-metadata-inferer": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.8.0.tgz",
- "integrity": "sha512-jOMKcHht9LxYIEQu+RVd22vtgrPaVCtDRQ/16IGmurdzxvYbDd5ynxjnyrzLnieG96eTcAyaoj/wN/4/1FyyeA==",
- "dev": true,
- "dependencies": {
- "@mdn/browser-compat-data": "^5.2.34"
- }
- },
- "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/autoprefixer": {
- "version": "10.4.16",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
- "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==",
- "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.21.10",
- "caniuse-lite": "^1.0.30001538",
- "fraction.js": "^4.3.6",
- "normalize-range": "^0.1.2",
- "picocolors": "^1.0.0",
- "postcss-value-parser": "^4.2.0"
- },
- "bin": {
- "autoprefixer": "bin/autoprefixer"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- },
- "peerDependencies": {
- "postcss": "^8.1.0"
- }
- },
- "node_modules/available-typed-arrays": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
- "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/axios": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
- "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
- "dependencies": {
- "follow-redirects": "^1.15.0",
- "form-data": "^4.0.0",
- "proxy-from-env": "^1.1.0"
- }
- },
- "node_modules/axios/node_modules/form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/babel-plugin-transform-hook-names": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-hook-names/-/babel-plugin-transform-hook-names-1.0.2.tgz",
- "integrity": "sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==",
- "dev": true,
- "peerDependencies": {
- "@babel/core": "^7.12.10"
- }
- },
- "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-arraybuffer-es6": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/base64-arraybuffer-es6/-/base64-arraybuffer-es6-0.7.0.tgz",
- "integrity": "sha512-ESyU/U1CFZDJUdr+neHRhNozeCv72Y7Vm0m1DCbjX3KBjT6eYocvAJlSk6+8+HkVwXlT1FNxhGW6q3UKAlCvvw==",
- "dev": true,
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "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/big-integer": {
- "version": "1.6.51",
- "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
- "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
- "dev": true,
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "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/bl/node_modules/readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/bplist-parser": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
- "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==",
- "dev": true,
- "dependencies": {
- "big-integer": "^1.6.44"
- },
- "engines": {
- "node": ">= 5.10.0"
- }
- },
- "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.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "dependencies": {
- "fill-range": "^7.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/browserslist": {
- "version": "4.21.10",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
- "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
- "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.30001517",
- "electron-to-chromium": "^1.4.477",
- "node-releases": "^2.0.13",
- "update-browserslist-db": "^1.0.11"
- },
- "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,
- "optional": true,
- "peer": true
- },
- "node_modules/bundle-name": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
- "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==",
- "dev": true,
- "dependencies": {
- "run-applescript": "^5.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/cac": {
- "version": "6.7.14",
- "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
- "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dev": true,
- "dependencies": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- },
- "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/camelcase-css": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
- "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/caniuse-lite": {
- "version": "1.0.30001538",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz",
- "integrity": "sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==",
- "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/caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "node_modules/chai": {
- "version": "4.3.10",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz",
- "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==",
- "dev": true,
- "dependencies": {
- "assertion-error": "^1.1.0",
- "check-error": "^1.0.3",
- "deep-eql": "^4.1.3",
- "get-func-name": "^2.0.2",
- "loupe": "^2.3.6",
- "pathval": "^1.1.1",
- "type-detect": "^4.0.8"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "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/chardet": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
- "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
- "dev": true
- },
- "node_modules/check-error": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
- "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
- "dev": true,
- "dependencies": {
- "get-func-name": "^2.0.2"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
- ],
- "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"
- },
- "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/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-spinners": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
- "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/cli-width": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
- "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "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/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/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/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": "4.1.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
- "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "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/concat-stream": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
- "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "dev": true,
- "engines": [
- "node >= 0.8"
- ],
- "optional": true,
- "peer": true,
- "dependencies": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^2.2.2",
- "typedarray": "^0.0.6"
- }
- },
- "node_modules/convert-source-map": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
- "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
- "dev": true
- },
- "node_modules/cookie": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
- "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/copy-to-clipboard": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
- "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
- "dependencies": {
- "toggle-selection": "^1.0.6"
- }
- },
- "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,
- "optional": true,
- "peer": true
- },
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/css.escape": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
- "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
- "dev": true
- },
- "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/cssstyle": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
- "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
- "dev": true,
- "dependencies": {
- "rrweb-cssom": "^0.6.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/data-urls": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz",
- "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==",
- "dev": true,
- "dependencies": {
- "abab": "^2.0.6",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^12.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/data-urls/node_modules/tr46": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
- "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.3.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/data-urls/node_modules/whatwg-url": {
- "version": "12.0.1",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
- "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
- "dev": true,
- "dependencies": {
- "tr46": "^4.1.1",
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/date-fns": {
- "version": "2.30.0",
- "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
- "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
- "dependencies": {
- "@babel/runtime": "^7.21.0"
- },
- "engines": {
- "node": ">=0.11"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/date-fns"
- }
- },
- "node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/decimal.js": {
- "version": "10.4.3",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
- "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
- "dev": true
- },
- "node_modules/deep-eql": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
- "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
- "dev": true,
- "dependencies": {
- "type-detect": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/deep-equal": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz",
- "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "es-get-iterator": "^1.1.2",
- "get-intrinsic": "^1.1.3",
- "is-arguments": "^1.1.1",
- "is-date-object": "^1.0.5",
- "is-regex": "^1.1.4",
- "isarray": "^2.0.5",
- "object-is": "^1.1.5",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "side-channel": "^1.0.4",
- "which-boxed-primitive": "^1.0.2",
- "which-collection": "^1.0.1",
- "which-typed-array": "^1.1.8"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/deep-equal/node_modules/isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": 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/default-browser": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz",
- "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==",
- "dev": true,
- "dependencies": {
- "bundle-name": "^3.0.0",
- "default-browser-id": "^3.0.0",
- "execa": "^7.1.1",
- "titleize": "^3.0.0"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser-id": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz",
- "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==",
- "dev": true,
- "dependencies": {
- "bplist-parser": "^0.2.0",
- "untildify": "^4.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "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-lazy-prop": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
- "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "dev": true,
- "dependencies": {
- "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/didyoumean": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
- "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
- "dev": true
- },
- "node_modules/diff-sequences": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
- "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
- "dev": true,
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "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/dlv": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
- "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
- "dev": true
- },
- "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-accessibility-api": {
- "version": "0.5.14",
- "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz",
- "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==",
- "dev": true
- },
- "node_modules/dom-walk": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
- "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
- },
- "node_modules/domexception": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
- "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
- "dev": true,
- "dependencies": {
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/electron-to-chromium": {
- "version": "1.4.508",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz",
- "integrity": "sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg==",
- "dev": true
- },
- "node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "node_modules/entities": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
- "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
- "dev": true,
- "engines": {
- "node": ">=0.12"
- },
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
- "node_modules/es-abstract": {
- "version": "1.20.4",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz",
- "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.1.3",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-property-descriptors": "^1.0.0",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.7",
- "is-negative-zero": "^2.0.2",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.12.2",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "safe-regex-test": "^1.0.0",
- "string.prototype.trimend": "^1.0.5",
- "string.prototype.trimstart": "^1.0.5",
- "unbox-primitive": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/es-get-iterator": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz",
- "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.0",
- "has-symbols": "^1.0.1",
- "is-arguments": "^1.1.0",
- "is-map": "^2.0.2",
- "is-set": "^2.0.2",
- "is-string": "^1.0.5",
- "isarray": "^2.0.5"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/es-get-iterator/node_modules/isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true
- },
- "node_modules/es-shim-unscopables": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
- "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
- "dev": true,
- "dependencies": {
- "has": "^1.0.3"
- }
- },
- "node_modules/es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "dev": true,
- "dependencies": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/esbuild": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz",
- "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==",
- "dev": true,
- "hasInstallScript": true,
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=12"
- },
- "optionalDependencies": {
- "@esbuild/android-arm": "0.18.17",
- "@esbuild/android-arm64": "0.18.17",
- "@esbuild/android-x64": "0.18.17",
- "@esbuild/darwin-arm64": "0.18.17",
- "@esbuild/darwin-x64": "0.18.17",
- "@esbuild/freebsd-arm64": "0.18.17",
- "@esbuild/freebsd-x64": "0.18.17",
- "@esbuild/linux-arm": "0.18.17",
- "@esbuild/linux-arm64": "0.18.17",
- "@esbuild/linux-ia32": "0.18.17",
- "@esbuild/linux-loong64": "0.18.17",
- "@esbuild/linux-mips64el": "0.18.17",
- "@esbuild/linux-ppc64": "0.18.17",
- "@esbuild/linux-riscv64": "0.18.17",
- "@esbuild/linux-s390x": "0.18.17",
- "@esbuild/linux-x64": "0.18.17",
- "@esbuild/netbsd-x64": "0.18.17",
- "@esbuild/openbsd-x64": "0.18.17",
- "@esbuild/sunos-x64": "0.18.17",
- "@esbuild/win32-arm64": "0.18.17",
- "@esbuild/win32-ia32": "0.18.17",
- "@esbuild/win32-x64": "0.18.17"
- }
- },
- "node_modules/escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/escape-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/eslint": {
- "version": "8.55.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz",
- "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.55.0",
- "@humanwhocodes/config-array": "^0.11.13",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
- "ajv": "^6.12.4",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.3.2",
- "doctrine": "^3.0.0",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "esquery": "^1.4.2",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
- "ignore": "^5.2.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-config-preact": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-config-preact/-/eslint-config-preact-1.3.0.tgz",
- "integrity": "sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw==",
- "dev": true,
- "dependencies": {
- "@babel/core": "^7.13.16",
- "@babel/eslint-parser": "^7.13.14",
- "@babel/plugin-syntax-class-properties": "^7.12.13",
- "@babel/plugin-syntax-decorators": "^7.12.13",
- "@babel/plugin-syntax-jsx": "^7.12.13",
- "eslint-plugin-compat": "^4.0.0",
- "eslint-plugin-jest": "^25.2.4",
- "eslint-plugin-react": "^7.27.0",
- "eslint-plugin-react-hooks": "^4.3.0"
- },
- "peerDependencies": {
- "eslint": "6.x || 7.x || 8.x"
- }
- },
- "node_modules/eslint-config-preact/node_modules/@typescript-eslint/eslint-plugin": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
- "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@eslint-community/regexpp": "^4.4.0",
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/type-utils": "5.62.0",
- "@typescript-eslint/utils": "5.62.0",
- "debug": "^4.3.4",
- "graphemer": "^1.4.0",
- "ignore": "^5.2.0",
- "natural-compare-lite": "^1.4.0",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "@typescript-eslint/parser": "^5.0.0",
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-config-preact/node_modules/@typescript-eslint/parser": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
- "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/typescript-estree": "5.62.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-config-preact/node_modules/@typescript-eslint/scope-manager": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
- "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/eslint-config-preact/node_modules/@typescript-eslint/type-utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz",
- "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@typescript-eslint/typescript-estree": "5.62.0",
- "@typescript-eslint/utils": "5.62.0",
- "debug": "^4.3.4",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "*"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-config-preact/node_modules/@typescript-eslint/types": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
- "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
- "dev": true,
- "optional": true,
- "peer": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/eslint-config-preact/node_modules/@typescript-eslint/typescript-estree": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
- "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-config-preact/node_modules/@typescript-eslint/utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
- "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@types/json-schema": "^7.0.9",
- "@types/semver": "^7.3.12",
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/typescript-estree": "5.62.0",
- "eslint-scope": "^5.1.1",
- "semver": "^7.3.7"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/eslint-config-preact/node_modules/@typescript-eslint/visitor-keys": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
- "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/eslint-config-preact/node_modules/eslint-plugin-jest": {
- "version": "25.7.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz",
- "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/experimental-utils": "^5.0.0"
- },
- "engines": {
- "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
- },
- "peerDependencies": {
- "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0",
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "@typescript-eslint/eslint-plugin": {
- "optional": true
- },
- "jest": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-config-preact/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,
- "optional": true,
- "peer": true,
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/eslint-config-preact/node_modules/estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/eslint-config-preact/node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint-config-prettier": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
- "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
- "dev": true,
- "bin": {
- "eslint-config-prettier": "bin/cli.js"
- },
- "peerDependencies": {
- "eslint": ">=7.0.0"
- }
- },
- "node_modules/eslint-plugin-compat": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-4.1.4.tgz",
- "integrity": "sha512-RxySWBmzfIROLFKgeJBJue2BU/6vM2KJWXWAUq+oW4QtrsZXRxbjgxmO1OfF3sHcRuuIenTS/wgo3GyUWZF24w==",
- "dev": true,
- "dependencies": {
- "@mdn/browser-compat-data": "^5.2.47",
- "@tsconfig/node14": "^1.0.3",
- "ast-metadata-inferer": "^0.8.0",
- "browserslist": "^4.21.5",
- "caniuse-lite": "^1.0.30001473",
- "find-up": "^5.0.0",
- "lodash.memoize": "4.1.2",
- "semver": "7.3.8"
- },
- "engines": {
- "node": ">=14.x"
- },
- "peerDependencies": {
- "eslint": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/eslint-plugin-compat/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint-plugin-jest": {
- "version": "27.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.0.tgz",
- "integrity": "sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/utils": "^5.10.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0",
- "eslint": "^7.0.0 || ^8.0.0",
- "jest": "*"
- },
- "peerDependenciesMeta": {
- "@typescript-eslint/eslint-plugin": {
- "optional": true
- },
- "jest": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
- "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
- "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/typescript-estree": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
- "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
- "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@types/json-schema": "^7.0.9",
- "@types/semver": "^7.3.12",
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/typescript-estree": "5.62.0",
- "eslint-scope": "^5.1.1",
- "semver": "^7.3.7"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
- "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.62.0",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/eslint-plugin-jest/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-plugin-jest/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/eslint-plugin-jest/node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint-plugin-prettier": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz",
- "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==",
- "dev": true,
- "dependencies": {
- "prettier-linter-helpers": "^1.0.0",
- "synckit": "^0.8.5"
- },
- "engines": {
- "node": "^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/prettier"
- },
- "peerDependencies": {
- "@types/eslint": ">=8.0.0",
- "eslint": ">=8.0.0",
- "prettier": ">=3.0.0"
- },
- "peerDependenciesMeta": {
- "@types/eslint": {
- "optional": true
- },
- "eslint-config-prettier": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-plugin-react": {
- "version": "7.31.10",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz",
- "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==",
- "dev": true,
- "dependencies": {
- "array-includes": "^3.1.5",
- "array.prototype.flatmap": "^1.3.0",
- "doctrine": "^2.1.0",
- "estraverse": "^5.3.0",
- "jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "minimatch": "^3.1.2",
- "object.entries": "^1.1.5",
- "object.fromentries": "^2.0.5",
- "object.hasown": "^1.1.1",
- "object.values": "^1.1.5",
- "prop-types": "^15.8.1",
- "resolve": "^2.0.0-next.3",
- "semver": "^6.3.0",
- "string.prototype.matchall": "^4.0.7"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
- }
- },
- "node_modules/eslint-plugin-react-hooks": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
- "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/resolve": {
- "version": "2.0.0-next.4",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
- "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/eslint-plugin-vitest-globals": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vitest-globals/-/eslint-plugin-vitest-globals-1.4.0.tgz",
- "integrity": "sha512-WE+YlK9X9s4vf5EaYRU0Scw7WItDZStm+PapFSYlg2ABNtaQ4zIG7wEqpoUB3SlfM+SgkhgmzR0TeJOO5k3/Nw==",
- "dev": true
- },
- "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/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/eslint/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/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/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/eslint/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/eslint/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/node_modules/globals": {
- "version": "13.19.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
- "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
- "dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/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/eslint/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/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": "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/esquery": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
- "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "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/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/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==",
- "dev": true
- },
- "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/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": "7.2.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz",
- "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.1",
- "human-signals": "^4.3.0",
- "is-stream": "^3.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^5.1.0",
- "onetime": "^6.0.0",
- "signal-exit": "^3.0.7",
- "strip-final-newline": "^3.0.0"
- },
- "engines": {
- "node": "^14.18.0 || ^16.14.0 || >=18.0.0"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/execa?sponsor=1"
- }
- },
- "node_modules/execa/node_modules/mimic-fn": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
- "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/execa/node_modules/onetime": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
- "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
- "dev": true,
- "dependencies": {
- "mimic-fn": "^4.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/external-editor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
- "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
- "dev": true,
- "dependencies": {
- "chardet": "^0.7.0",
- "iconv-lite": "^0.4.24",
- "tmp": "^0.0.33"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/external-editor/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/fake-indexeddb": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/fake-indexeddb/-/fake-indexeddb-4.0.2.tgz",
- "integrity": "sha512-SdTwEhnakbgazc7W3WUXOJfGmhH0YfG4d+dRPOFoYDRTL6U5t8tvrmkf2W/C3W1jk2ylV7Wrnj44RASqpX/lEw==",
- "dev": true,
- "dependencies": {
- "realistic-structured-clone": "^3.0.0"
- }
- },
- "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-diff": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
- "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
- "dev": true
- },
- "node_modules/fast-glob": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
- "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.4"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/fast-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/fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "dev": true,
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/fflate": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.0.tgz",
- "integrity": "sha512-FAdS4qMuFjsJj6XHbBaZeXOgaypXp8iw/Tpyuq/w3XA41jjLHT8NPA+n7czH/DDhdncq0nAyDZmPeWXh2qmdIg==",
- "dev": true
- },
- "node_modules/figures": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
- "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
- "dev": true,
- "dependencies": {
- "escape-string-regexp": "^1.0.5"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "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.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dev": true,
- "dependencies": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
- "dev": true
- },
- "node_modules/follow-redirects": {
- "version": "1.15.2",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
- "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/RubenVerborgh"
- }
- ],
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- },
- "node_modules/for-each": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
- "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
- "dev": true,
- "dependencies": {
- "is-callable": "^1.1.3"
- }
- },
- "node_modules/form-data": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
- "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 0.12"
- }
- },
- "node_modules/fraction.js": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz",
- "integrity": "sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==",
- "dev": true,
- "engines": {
- "node": "*"
- },
- "funding": {
- "type": "patreon",
- "url": "https://github.com/sponsors/rawify"
- }
- },
- "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.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "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.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "node_modules/function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0",
- "functions-have-names": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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-func-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
- "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
- "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
- "dev": true,
- "dependencies": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-port": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz",
- "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==",
- "dev": true,
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=4"
- }
- },
- "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/get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/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/global": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
- "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
- "dependencies": {
- "min-document": "^2.19.0",
- "process": "^0.11.10"
- }
- },
- "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/gopd": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
- "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
- "dev": true,
- "dependencies": {
- "get-intrinsic": "^1.1.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/graphemer": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true
- },
- "node_modules/graphql": {
- "version": "16.8.1",
- "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
- "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
- }
- },
- "node_modules/happy-dom": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-7.6.7.tgz",
- "integrity": "sha512-9pOslsClyF5JX9ZM3dzRhLjTHqc4dha7v+ZB94u4PHMVTdLplXAnh5e5WXtPUU1n0J4tDUavslJqitqt/1W45g==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "css.escape": "^1.5.1",
- "he": "^1.2.0",
- "node-fetch": "^2.x.x",
- "sync-request": "^6.1.0",
- "webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^2.0.0",
- "whatwg-mimetype": "^3.0.0"
- }
- },
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dev": true,
- "dependencies": {
- "function-bind": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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/has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "dev": true,
- "dependencies": {
- "get-intrinsic": "^1.1.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "dev": true,
- "dependencies": {
- "has-symbols": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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,
- "optional": true,
- "peer": true,
- "bin": {
- "he": "bin/he"
- }
- },
- "node_modules/headers-polyfill": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.2.5.tgz",
- "integrity": "sha512-tUCGvt191vNSQgttSyJoibR+VO+I6+iCHIUdhzEMJKE+EAL8BwCN7fUOZlY4ofOelNHsK+gEjxB/B+9N3EWtdA==",
- "dev": true
- },
- "node_modules/html-encoding-sniffer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
- "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
- "dev": true,
- "dependencies": {
- "whatwg-encoding": "^2.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "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/http-basic": {
- "version": "8.1.3",
- "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",
- "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "caseless": "^0.12.0",
- "concat-stream": "^1.6.2",
- "http-response-object": "^3.0.1",
- "parse-cache-control": "^1.0.1"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/http-proxy-agent": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
- "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
- "dev": true,
- "dependencies": {
- "@tootallnate/once": "2",
- "agent-base": "6",
- "debug": "4"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/http-response-object": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
- "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@types/node": "^10.0.3"
- }
- },
- "node_modules/http-response-object/node_modules/@types/node": {
- "version": "10.17.60",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
- "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "node_modules/https-proxy-agent": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
- "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
- "dev": true,
- "dependencies": {
- "agent-base": "6",
- "debug": "4"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/human-signals": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
- "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
- "dev": true,
- "engines": {
- "node": ">=14.18.0"
- }
- },
- "node_modules/iconv-lite": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dev": true,
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/idb-keyval": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
- "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
- },
- "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": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
- "dev": true,
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/immer": {
- "version": "10.0.3",
- "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz",
- "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/immer"
- }
- },
- "node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "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/indent-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/individual": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz",
- "integrity": "sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g=="
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "node_modules/inquirer": {
- "version": "8.2.5",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz",
- "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==",
- "dev": true,
- "dependencies": {
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.1.1",
- "cli-cursor": "^3.1.0",
- "cli-width": "^3.0.0",
- "external-editor": "^3.0.3",
- "figures": "^3.0.0",
- "lodash": "^4.17.21",
- "mute-stream": "0.0.8",
- "ora": "^5.4.1",
- "run-async": "^2.4.0",
- "rxjs": "^7.5.5",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0",
- "through": "^2.3.6",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/inquirer/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/inquirer/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/inquirer/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/inquirer/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/inquirer/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/inquirer/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/internal-slot": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
- "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
- "dev": true,
- "dependencies": {
- "get-intrinsic": "^1.1.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/is-arguments": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
- "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "dev": true,
- "dependencies": {
- "has-bigints": "^1.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
- "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
- "dev": true,
- "dependencies": {
- "has": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-docker": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
- "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
- "dev": true,
- "bin": {
- "is-docker": "cli.js"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "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-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-function": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
- "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ=="
- },
- "node_modules/is-generator-function": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
- "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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-inside-container": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
- "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
- "dev": true,
- "dependencies": {
- "is-docker": "^3.0.0"
- },
- "bin": {
- "is-inside-container": "cli.js"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "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-map": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
- "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-negative-zero": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
- "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-node-process": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
- "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==",
- "dev": true
- },
- "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-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-potential-custom-element-name": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
- "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
- "dev": true
- },
- "node_modules/is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-set": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
- "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-shared-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
- "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-stream": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
- "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
- "dev": true,
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
- "dev": true,
- "dependencies": {
- "has-symbols": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-typed-array": {
- "version": "1.1.10",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz",
- "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==",
- "dev": true,
- "dependencies": {
- "available-typed-arrays": "^1.0.5",
- "call-bind": "^1.0.2",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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-weakmap": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
- "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakset": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
- "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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/is-wsl/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/isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
- "dev": true,
- "optional": true,
- "peer": 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/istanbul-lib-coverage": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
- "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-report": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
- "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
- "dev": true,
- "dependencies": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^4.0.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/istanbul-lib-report/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/istanbul-lib-report/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/istanbul-lib-source-maps": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
- "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
- "dev": true,
- "dependencies": {
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/istanbul-reports": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
- "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
- "dev": true,
- "dependencies": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-diff": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
- "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.0.0",
- "diff-sequences": "^29.6.3",
- "jest-get-type": "^29.6.3",
- "pretty-format": "^29.7.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-diff/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/jest-diff/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/jest-diff/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/jest-diff/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/jest-diff/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/jest-diff/node_modules/pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
- "dev": true,
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-diff/node_modules/pretty-format/node_modules/ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-diff/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- },
- "node_modules/jest-diff/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/jest-get-type": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
- "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
- "dev": true,
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-websocket-mock": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.5.0.tgz",
- "integrity": "sha512-a+UJGfowNIWvtIKIQBHoEWIUqRxxQHFx4CXT+R5KxxKBtEQ5rS3pPOV/5299sHzqbmeCzxxY5qE4+yfXePePig==",
- "dev": true,
- "dependencies": {
- "jest-diff": "^29.2.0",
- "mock-socket": "^9.3.0"
- }
- },
- "node_modules/jiti": {
- "version": "1.21.0",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
- "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
- "dev": true,
- "bin": {
- "jiti": "bin/jiti.js"
- }
- },
- "node_modules/js-levenshtein": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
- "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.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": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/jsdom": {
- "version": "22.1.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
- "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
- "dev": true,
- "dependencies": {
- "abab": "^2.0.6",
- "cssstyle": "^3.0.0",
- "data-urls": "^4.0.0",
- "decimal.js": "^10.4.3",
- "domexception": "^4.0.0",
- "form-data": "^4.0.0",
- "html-encoding-sniffer": "^3.0.0",
- "http-proxy-agent": "^5.0.0",
- "https-proxy-agent": "^5.0.1",
- "is-potential-custom-element-name": "^1.0.1",
- "nwsapi": "^2.2.4",
- "parse5": "^7.1.2",
- "rrweb-cssom": "^0.6.0",
- "saxes": "^6.0.0",
- "symbol-tree": "^3.2.4",
- "tough-cookie": "^4.1.2",
- "w3c-xmlserializer": "^4.0.0",
- "webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^2.0.0",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^12.0.1",
- "ws": "^8.13.0",
- "xml-name-validator": "^4.0.0"
- },
- "engines": {
- "node": ">=16"
- },
- "peerDependencies": {
- "canvas": "^2.5.0"
- },
- "peerDependenciesMeta": {
- "canvas": {
- "optional": true
- }
- }
- },
- "node_modules/jsdom/node_modules/form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dev": true,
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/jsdom/node_modules/tr46": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
- "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.3.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/jsdom/node_modules/whatwg-url": {
- "version": "12.0.1",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
- "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
- "dev": true,
- "dependencies": {
- "tr46": "^4.1.1",
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "dev": true,
- "bin": {
- "jsesc": "bin/jsesc"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "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/jsonc-parser": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
- "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w=="
- },
- "node_modules/jsx-ast-utils": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz",
- "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==",
- "dev": true,
- "dependencies": {
- "array-includes": "^3.1.5",
- "object.assign": "^4.1.3"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/keycode": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
- "integrity": "sha512-ps3I9jAdNtRpJrbBvQjpzyFbss/skHqzS+eu4RxKLaEAtFqkjZaB6TZMSivPbLxf4K7VI4SjR0P5mRCX5+Q25A=="
- },
- "node_modules/kolorist": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
- "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
- "dev": true
- },
- "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/local-pkg": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
- "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==",
- "dev": true,
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
- "node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
- },
- "node_modules/lodash.memoize": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
- "dev": true
- },
- "node_modules/lodash.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/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/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/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-symbols/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/log-symbols/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/log-symbols/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/log-symbols/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/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/loupe": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
- "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
- "dev": true,
- "dependencies": {
- "get-func-name": "^2.0.0"
- }
- },
- "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/lz-string": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
- "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==",
- "dev": true,
- "bin": {
- "lz-string": "bin/bin.js"
- }
- },
- "node_modules/m3u8-parser": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-6.2.0.tgz",
- "integrity": "sha512-qlC00JTxYOxawcqg+RB8jbyNwL3foY/nCY61kyWP+RCuJE9APLeqB/nSlTjb4Mg0yRmyERgjswpdQxMvkeoDrg==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.5",
- "global": "^4.4.0"
- }
- },
- "node_modules/m3u8-parser/node_modules/@videojs/vhs-utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
- "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- },
- "engines": {
- "node": ">=8",
- "npm": ">=5"
- }
- },
- "node_modules/magic-string": {
- "version": "0.30.2",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz",
- "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==",
- "dev": true,
- "dependencies": {
- "@jridgewell/sourcemap-codec": "^1.4.15"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/magic-string/node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
- "dev": true
- },
- "node_modules/make-dir": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
- "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
- "dev": true,
- "dependencies": {
- "semver": "^7.5.3"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/make-dir/node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
- "dev": true
- },
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
- "dev": true,
- "dependencies": {
- "braces": "^3.0.2",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "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/min-document": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
- "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==",
- "dependencies": {
- "dom-walk": "^0.1.0"
- }
- },
- "node_modules/min-indent": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
- "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mini-svg-data-uri": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
- "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
- "dev": true,
- "bin": {
- "mini-svg-data-uri": "cli.js"
- }
- },
- "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/mlly": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz",
- "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==",
- "dev": true,
- "dependencies": {
- "acorn": "^8.10.0",
- "pathe": "^1.1.1",
- "pkg-types": "^1.0.3",
- "ufo": "^1.3.0"
- }
- },
- "node_modules/mock-socket": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz",
- "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/monaco-editor": {
- "version": "0.34.1",
- "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.34.1.tgz",
- "integrity": "sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ==",
- "peer": true
- },
- "node_modules/monaco-marker-data-provider": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/monaco-marker-data-provider/-/monaco-marker-data-provider-1.1.1.tgz",
- "integrity": "sha512-PGB7TJSZE5tmHzkxv/OEwK2RGNC2A7dcq4JRJnnj31CUAsfmw0Gl+1QTrH0W0deKhcQmQM0YVPaqgQ+0wCt8Mg==",
- "funding": {
- "url": "https://github.com/sponsors/remcohaszing"
- },
- "peerDependencies": {
- "monaco-editor": ">=0.30.0"
- }
- },
- "node_modules/monaco-worker-manager": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/monaco-worker-manager/-/monaco-worker-manager-2.0.1.tgz",
- "integrity": "sha512-kdPL0yvg5qjhKPNVjJoym331PY/5JC11aPJXtCZNwWRvBr6jhkIamvYAyiY5P1AWFmNOy0aRDRoMdZfa71h8kg==",
- "peerDependencies": {
- "monaco-editor": ">=0.30.0"
- }
- },
- "node_modules/monaco-yaml": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/monaco-yaml/-/monaco-yaml-4.0.4.tgz",
- "integrity": "sha512-qbM36fY1twpDUs4lhhxoXDQGUPVyYAFCPJi3E0JKgLioD8wzsD/pawgauFFXSzpMa09z8wbt/DTLXjXEehnVFA==",
- "dependencies": {
- "@types/json-schema": "^7.0.0",
- "jsonc-parser": "^3.0.0",
- "monaco-marker-data-provider": "^1.0.0",
- "monaco-worker-manager": "^2.0.0",
- "path-browserify": "^1.0.0",
- "prettier": "^2.0.0",
- "vscode-languageserver-textdocument": "^1.0.0",
- "vscode-languageserver-types": "^3.0.0",
- "vscode-uri": "^3.0.0",
- "yaml": "^2.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/remcohaszing"
- },
- "peerDependencies": {
- "monaco-editor": ">=0.30"
- }
- },
- "node_modules/monaco-yaml/node_modules/prettier": {
- "version": "2.8.8",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
- "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
- "bin": {
- "prettier": "bin-prettier.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/mpd-parser": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.2.2.tgz",
- "integrity": "sha512-QCfB1koOoZw6E5La1cx+W/Yd0EZlRhHMqMr4TAJez0eRTuPDzPM5FWoiOqjyo37W+ISPLzmfJACSbJFEBjbL4Q==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.5",
- "@xmldom/xmldom": "^0.8.3",
- "global": "^4.4.0"
- },
- "bin": {
- "mpd-to-m3u8-json": "bin/parse.js"
- }
- },
- "node_modules/mpd-parser/node_modules/@videojs/vhs-utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
- "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- },
- "engines": {
- "node": ">=8",
- "npm": ">=5"
- }
- },
- "node_modules/mrmime": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
- "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/msw": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/msw/-/msw-1.3.2.tgz",
- "integrity": "sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA==",
- "dev": true,
- "hasInstallScript": true,
- "dependencies": {
- "@mswjs/cookies": "^0.2.2",
- "@mswjs/interceptors": "^0.17.10",
- "@open-draft/until": "^1.0.3",
- "@types/cookie": "^0.4.1",
- "@types/js-levenshtein": "^1.1.1",
- "chalk": "^4.1.1",
- "chokidar": "^3.4.2",
- "cookie": "^0.4.2",
- "graphql": "^16.8.1",
- "headers-polyfill": "3.2.5",
- "inquirer": "^8.2.0",
- "is-node-process": "^1.2.0",
- "js-levenshtein": "^1.1.6",
- "node-fetch": "^2.6.7",
- "outvariant": "^1.4.0",
- "path-to-regexp": "^6.2.0",
- "strict-event-emitter": "^0.4.3",
- "type-fest": "^2.19.0",
- "yargs": "^17.3.1"
- },
- "bin": {
- "msw": "cli/index.js"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mswjs"
- },
- "peerDependencies": {
- "typescript": ">= 4.4.x <= 5.2.x"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/msw/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/msw/node_modules/chalk": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
- "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
- "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/msw/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/msw/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/msw/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/msw/node_modules/strict-event-emitter": {
- "version": "0.4.6",
- "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz",
- "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==",
- "dev": true
- },
- "node_modules/msw/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/mute-stream": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
- "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
- "dev": true
- },
- "node_modules/mux.js": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-7.0.1.tgz",
- "integrity": "sha512-Omz79uHqYpMP1V80JlvEdCiOW1hiw4mBvDh9gaZEpxvB+7WYb2soZSzfuSRrK2Kh9Pm6eugQNrIpY/Bnyhk4hw==",
- "dependencies": {
- "@babel/runtime": "^7.11.2",
- "global": "^4.4.0"
- },
- "bin": {
- "muxjs-transmux": "bin/transmux.js"
- },
- "engines": {
- "node": ">=8",
- "npm": ">=5"
- }
- },
- "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.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/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/natural-compare-lite": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
- "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "node_modules/node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "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-releases": {
- "version": "2.0.13",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
- "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
- "dev": true
- },
- "node_modules/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/npm-run-path": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
- "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
- "dev": true,
- "dependencies": {
- "path-key": "^4.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/npm-run-path/node_modules/path-key": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
- "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/nwsapi": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.4.tgz",
- "integrity": "sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g==",
- "dev": true
- },
- "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-hash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
- "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
- "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object-is": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
- "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
- },
- "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.4",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
- "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "has-symbols": "^1.0.3",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.entries": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz",
- "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.fromentries": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz",
- "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.hasown": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz",
- "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==",
- "dev": true,
- "dependencies": {
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.values": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz",
- "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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": "9.1.0",
- "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz",
- "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==",
- "dev": true,
- "dependencies": {
- "default-browser": "^4.0.0",
- "define-lazy-prop": "^3.0.0",
- "is-inside-container": "^1.0.0",
- "is-wsl": "^2.2.0"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/optionator": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
- "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
- "dev": true,
- "dependencies": {
- "@aashutoshrathi/word-wrap": "^1.2.3",
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0"
- },
- "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/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/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/ora/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/ora/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/ora/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/ora/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/os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/outvariant": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz",
- "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==",
- "dev": true
- },
- "node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/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-cache-control": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
- "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "node_modules/parse5": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
- "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
- "dev": true,
- "dependencies": {
- "entities": "^4.4.0"
- },
- "funding": {
- "url": "https://github.com/inikulin/parse5?sponsor=1"
- }
- },
- "node_modules/path-browserify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
- "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
- },
- "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": "6.2.1",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
- "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==",
- "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/pathe": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz",
- "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==",
- "dev": true
- },
- "node_modules/pathval": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
- "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/pirates": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
- "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/pkcs7": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz",
- "integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==",
- "dependencies": {
- "@babel/runtime": "^7.5.5"
- },
- "bin": {
- "pkcs7": "bin/cli.js"
- }
- },
- "node_modules/pkg-types": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
- "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==",
- "dev": true,
- "dependencies": {
- "jsonc-parser": "^3.2.0",
- "mlly": "^1.2.0",
- "pathe": "^1.1.0"
- }
- },
- "node_modules/postcss": {
- "version": "8.4.32",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
- "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/postcss-import": {
- "version": "15.1.0",
- "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
- "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
- "dev": true,
- "dependencies": {
- "postcss-value-parser": "^4.0.0",
- "read-cache": "^1.0.0",
- "resolve": "^1.1.7"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "peerDependencies": {
- "postcss": "^8.0.0"
- }
- },
- "node_modules/postcss-js": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
- "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
- "dev": true,
- "dependencies": {
- "camelcase-css": "^2.0.1"
- },
- "engines": {
- "node": "^12 || ^14 || >= 16"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- "peerDependencies": {
- "postcss": "^8.4.21"
- }
- },
- "node_modules/postcss-load-config": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
- "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
- "dev": true,
- "dependencies": {
- "lilconfig": "^2.0.5",
- "yaml": "^2.1.1"
- },
- "engines": {
- "node": ">= 14"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- "peerDependencies": {
- "postcss": ">=8.0.9",
- "ts-node": ">=9.0.0"
- },
- "peerDependenciesMeta": {
- "postcss": {
- "optional": true
- },
- "ts-node": {
- "optional": true
- }
- }
- },
- "node_modules/postcss-nested": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
- "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
- "dev": true,
- "dependencies": {
- "postcss-selector-parser": "^6.0.11"
- },
- "engines": {
- "node": ">=12.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- "peerDependencies": {
- "postcss": "^8.2.14"
- }
- },
- "node_modules/postcss-selector-parser": {
- "version": "6.0.11",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
- "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
- "dev": true,
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "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/preact": {
- "version": "10.19.2",
- "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.2.tgz",
- "integrity": "sha512-UA9DX/OJwv6YwP9Vn7Ti/vF80XL+YA5H2l7BpCtUr3ya8LWHFzpiO5R+N7dN16ujpIxhekRFuOOF82bXX7K/lg==",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/preact"
- }
- },
- "node_modules/preact-async-route": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/preact-async-route/-/preact-async-route-2.2.1.tgz",
- "integrity": "sha512-8bg1007akXs3YDmzYT4McaTe6ji2FIzcc0/NTlu+vjJaKPNQ8lNG/HQ6LP+FoIxQ4m/KH5vvJCHJN5ADp2iNGA=="
- },
- "node_modules/preact-router": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/preact-router/-/preact-router-4.1.2.tgz",
- "integrity": "sha512-uICUaUFYh+XQ+6vZtQn1q+X6rSqwq+zorWOCLWPF5FAsQh3EJ+RsDQ9Ee+fjk545YWQHfUxhrBAaemfxEnMOUg==",
- "peerDependencies": {
- "preact": ">=10"
- }
- },
- "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": "3.1.0",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
- "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
- "dev": true,
- "bin": {
- "prettier": "bin/prettier.cjs"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/prettier-linter-helpers": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
- "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
- "dev": true,
- "dependencies": {
- "fast-diff": "^1.1.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/pretty-format": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
- "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1",
- "ansi-styles": "^5.0.0",
- "react-is": "^17.0.1"
- },
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
- }
- },
- "node_modules/pretty-format/node_modules/ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/pretty-format/node_modules/react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "dev": true
- },
- "node_modules/process": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
- "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
- "engines": {
- "node": ">= 0.6.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,
- "optional": true,
- "peer": true
- },
- "node_modules/promise": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
- "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "asap": "~2.0.6"
- }
- },
- "node_modules/prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
- "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/psl": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
- "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
- "dev": true
- },
- "node_modules/punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">=0.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/querystringify": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
- "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
- "dev": true
- },
- "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/react": {
- "name": "@preact/compat",
- "version": "17.1.2",
- "resolved": "https://registry.npmjs.org/@preact/compat/-/compat-17.1.2.tgz",
- "integrity": "sha512-7pOZN9lMDDRQ+6aWvjwTp483KR8/zOpfS83wmOo3zfuLKdngS8/5RLbsFWzFZMGdYlotAhX980hJ75bjOHTwWg==",
- "peerDependencies": {
- "preact": "*"
- }
- },
- "node_modules/react-dom": {
- "name": "@preact/compat",
- "version": "17.1.2",
- "resolved": "https://registry.npmjs.org/@preact/compat/-/compat-17.1.2.tgz",
- "integrity": "sha512-7pOZN9lMDDRQ+6aWvjwTp483KR8/zOpfS83wmOo3zfuLKdngS8/5RLbsFWzFZMGdYlotAhX980hJ75bjOHTwWg==",
- "peerDependencies": {
- "preact": "*"
- }
- },
- "node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- },
- "node_modules/react-use-websocket": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-3.0.0.tgz",
- "integrity": "sha512-BInlbhXYrODBPKIplDAmI0J1VPM+1KhCLN09o+dzgQ8qMyrYs4t5kEYmCrTqyRuMTmpahylHFZWQXpfYyDkqOw==",
- "peerDependencies": {
- "react": ">= 16.8.0",
- "react-dom": ">= 16.8.0"
- }
- },
- "node_modules/read-cache": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
- "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
- "dev": true,
- "dependencies": {
- "pify": "^2.3.0"
- }
- },
- "node_modules/readable-stream": {
- "version": "2.3.7",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
- "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "dev": true,
- "optional": true,
- "peer": 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/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/realistic-structured-clone": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/realistic-structured-clone/-/realistic-structured-clone-3.0.0.tgz",
- "integrity": "sha512-rOjh4nuWkAqf9PWu6JVpOWD4ndI+JHfgiZeMmujYcPi+fvILUu7g6l26TC1K5aBIp34nV+jE1cDO75EKOfHC5Q==",
- "dev": true,
- "dependencies": {
- "domexception": "^1.0.1",
- "typeson": "^6.1.0",
- "typeson-registry": "^1.0.0-alpha.20"
- }
- },
- "node_modules/realistic-structured-clone/node_modules/domexception": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
- "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
- "dev": true,
- "dependencies": {
- "webidl-conversions": "^4.0.2"
- }
- },
- "node_modules/realistic-structured-clone/node_modules/webidl-conversions": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
- "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
- "dev": true
- },
- "node_modules/redent": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
- "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
- "dev": true,
- "dependencies": {
- "indent-string": "^4.0.0",
- "strip-indent": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
- },
- "node_modules/regexp.prototype.flags": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
- "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "functions-have-names": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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/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.8",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
- "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-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/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/rollup": {
- "version": "3.27.2",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.27.2.tgz",
- "integrity": "sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==",
- "dev": true,
- "bin": {
- "rollup": "dist/bin/rollup"
- },
- "engines": {
- "node": ">=14.18.0",
- "npm": ">=8.0.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/rrweb-cssom": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
- "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
- "dev": true
- },
- "node_modules/run-applescript": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz",
- "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==",
- "dev": true,
- "dependencies": {
- "execa": "^5.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/run-applescript/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/run-applescript/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/run-applescript/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/run-applescript/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/run-applescript/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/run-async": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
- "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
- "dev": true,
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "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/rust-result": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz",
- "integrity": "sha512-6cJzSBU+J/RJCF063onnQf0cDUOHs9uZI1oroSGnHOph+CQTIJ5Pp2hK5kEQq1+7yE/EEWfulSNXAQ2jikPthA==",
- "dependencies": {
- "individual": "^2.0.0"
- }
- },
- "node_modules/rxjs": {
- "version": "7.5.7",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
- "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
- "dev": true,
- "dependencies": {
- "tslib": "^2.1.0"
- }
- },
- "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/safe-json-parse": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz",
- "integrity": "sha512-RjZPPHugjK0TOzFrLZ8inw44s9bKox99/0AZW9o/BEQVrJfhI+fIHMErnPyRa89/yRXUUr93q+tiN6zhoVV4wQ==",
- "dependencies": {
- "rust-result": "^1.0.0"
- }
- },
- "node_modules/safe-regex-test": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
- "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "is-regex": "^1.1.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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/saxes": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
- "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
- "dev": true,
- "dependencies": {
- "xmlchars": "^2.2.0"
- },
- "engines": {
- "node": ">=v12.22.7"
- }
- },
- "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/set-cookie-parser": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz",
- "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==",
- "dev": true
- },
- "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/side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/siginfo": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
- "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
- "dev": true
- },
- "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.3",
- "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz",
- "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==",
- "dev": true,
- "dependencies": {
- "@polka/url": "^1.0.0-next.20",
- "mrmime": "^1.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/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/stackback": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
- "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
- "dev": true
- },
- "node_modules/std-env": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.3.tgz",
- "integrity": "sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==",
- "dev": true
- },
- "node_modules/strftime": {
- "version": "0.10.2",
- "resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.2.tgz",
- "integrity": "sha512-Y6IZaTVM80chcMe7j65Gl/0nmlNdtt+KWPle5YeCAjmsBfw+id2qdaJ5MDrxUq+OmHKab+jHe7mUjU/aNMSZZg==",
- "engines": {
- "node": ">=0.2.0"
- }
- },
- "node_modules/strict-event-emitter": {
- "version": "0.2.8",
- "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz",
- "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==",
- "dev": true,
- "dependencies": {
- "events": "^3.3.0"
- }
- },
- "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/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string.prototype.matchall": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz",
- "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "get-intrinsic": "^1.1.3",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "regexp.prototype.flags": "^1.4.3",
- "side-channel": "^1.0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimend": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
- "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimstart": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz",
- "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "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-final-newline": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
- "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/strip-indent": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
- "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
- "dev": true,
- "dependencies": {
- "min-indent": "^1.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/strip-literal": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz",
- "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==",
- "dev": true,
- "dependencies": {
- "acorn": "^8.8.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
- "node_modules/sucrase": {
- "version": "3.32.0",
- "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
- "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==",
- "dev": true,
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.3.2",
- "commander": "^4.0.0",
- "glob": "7.1.6",
- "lines-and-columns": "^1.1.6",
- "mz": "^2.7.0",
- "pirates": "^4.0.1",
- "ts-interface-checker": "^0.1.9"
- },
- "bin": {
- "sucrase": "bin/sucrase",
- "sucrase-node": "bin/sucrase-node"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/sucrase/node_modules/glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "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/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/swr": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/swr/-/swr-1.3.0.tgz",
- "integrity": "sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==",
- "peerDependencies": {
- "react": "^16.11.0 || ^17.0.0 || ^18.0.0"
- }
- },
- "node_modules/symbol-tree": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
- "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
- "dev": true
- },
- "node_modules/sync-request": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz",
- "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "http-response-object": "^3.0.1",
- "sync-rpc": "^1.2.1",
- "then-request": "^6.0.0"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/sync-rpc": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz",
- "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "get-port": "^3.1.0"
- }
- },
- "node_modules/synckit": {
- "version": "0.8.5",
- "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
- "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==",
- "dev": true,
- "dependencies": {
- "@pkgr/utils": "^2.3.1",
- "tslib": "^2.5.0"
- },
- "engines": {
- "node": "^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/unts"
- }
- },
- "node_modules/tailwindcss": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.6.tgz",
- "integrity": "sha512-AKjF7qbbLvLaPieoKeTjG1+FyNZT6KaJMJPFeQyLfIp7l82ggH1fbHJSsYIvnbTFQOlkh+gBYpyby5GT1LIdLw==",
- "dev": true,
- "dependencies": {
- "@alloc/quick-lru": "^5.2.0",
- "arg": "^5.0.2",
- "chokidar": "^3.5.3",
- "didyoumean": "^1.2.2",
- "dlv": "^1.1.3",
- "fast-glob": "^3.3.0",
- "glob-parent": "^6.0.2",
- "is-glob": "^4.0.3",
- "jiti": "^1.19.1",
- "lilconfig": "^2.1.0",
- "micromatch": "^4.0.5",
- "normalize-path": "^3.0.0",
- "object-hash": "^3.0.0",
- "picocolors": "^1.0.0",
- "postcss": "^8.4.23",
- "postcss-import": "^15.1.0",
- "postcss-js": "^4.0.1",
- "postcss-load-config": "^4.0.1",
- "postcss-nested": "^6.0.1",
- "postcss-selector-parser": "^6.0.11",
- "resolve": "^1.22.2",
- "sucrase": "^3.32.0"
- },
- "bin": {
- "tailwind": "lib/cli.js",
- "tailwindcss": "lib/cli.js"
- },
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "node_modules/test-exclude": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
- "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
- "dev": true,
- "dependencies": {
- "@istanbuljs/schema": "^0.1.2",
- "glob": "^7.1.4",
- "minimatch": "^3.0.4"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "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/then-request": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz",
- "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "dependencies": {
- "@types/concat-stream": "^1.6.0",
- "@types/form-data": "0.0.33",
- "@types/node": "^8.0.0",
- "@types/qs": "^6.2.31",
- "caseless": "~0.12.0",
- "concat-stream": "^1.6.0",
- "form-data": "^2.2.0",
- "http-basic": "^8.1.1",
- "http-response-object": "^3.0.1",
- "promise": "^8.0.0",
- "qs": "^6.4.0"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/then-request/node_modules/@types/node": {
- "version": "8.10.66",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz",
- "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==",
- "dev": true,
- "optional": true,
- "peer": 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/through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
- "dev": true
- },
- "node_modules/tinybench": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz",
- "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==",
- "dev": true
- },
- "node_modules/tinypool": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz",
- "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==",
- "dev": true,
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "node_modules/tinyspy": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz",
- "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==",
- "dev": true,
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "node_modules/titleize": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz",
- "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/tmp": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
- "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
- "dev": true,
- "dependencies": {
- "os-tmpdir": "~1.0.2"
- },
- "engines": {
- "node": ">=0.6.0"
- }
- },
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "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/toggle-selection": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
- "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
- },
- "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/tough-cookie": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
- "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
- "dev": true,
- "dependencies": {
- "psl": "^1.1.33",
- "punycode": "^2.1.1",
- "universalify": "^0.2.0",
- "url-parse": "^1.5.3"
- },
- "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/ts-api-utils": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz",
- "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==",
- "dev": true,
- "engines": {
- "node": ">=16.13.0"
- },
- "peerDependencies": {
- "typescript": ">=4.2.0"
- }
- },
- "node_modules/ts-interface-checker": {
- "version": "0.1.13",
- "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
- "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
- "dev": true
- },
- "node_modules/tslib": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
- "dev": true
- },
- "node_modules/tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dev": true,
- "dependencies": {
- "tslib": "^1.8.1"
- },
- "engines": {
- "node": ">= 6"
- },
- "peerDependencies": {
- "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
- }
- },
- "node_modules/tsutils/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- },
- "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-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/type-fest": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
- "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
- "dev": true,
- "engines": {
- "node": ">=12.20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "node_modules/typescript": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
- "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
- "dev": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
- "node_modules/typeson": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/typeson/-/typeson-6.1.0.tgz",
- "integrity": "sha512-6FTtyGr8ldU0pfbvW/eOZrEtEkczHRUtduBnA90Jh9kMPCiFNnXIon3vF41N0S4tV1HHQt4Hk1j4srpESziCaA==",
- "dev": true,
- "engines": {
- "node": ">=0.1.14"
- }
- },
- "node_modules/typeson-registry": {
- "version": "1.0.0-alpha.39",
- "resolved": "https://registry.npmjs.org/typeson-registry/-/typeson-registry-1.0.0-alpha.39.tgz",
- "integrity": "sha512-NeGDEquhw+yfwNhguLPcZ9Oj0fzbADiX4R0WxvoY8nGhy98IbzQy1sezjoEFWOywOboj/DWehI+/aUlRVrJnnw==",
- "dev": true,
- "dependencies": {
- "base64-arraybuffer-es6": "^0.7.0",
- "typeson": "^6.0.0",
- "whatwg-url": "^8.4.0"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/typeson-registry/node_modules/tr46": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz",
- "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/typeson-registry/node_modules/webidl-conversions": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
- "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
- "dev": true,
- "engines": {
- "node": ">=10.4"
- }
- },
- "node_modules/typeson-registry/node_modules/whatwg-url": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz",
- "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==",
- "dev": true,
- "dependencies": {
- "lodash": "^4.7.0",
- "tr46": "^2.1.0",
- "webidl-conversions": "^6.1.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/ufo": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz",
- "integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==",
- "dev": true
- },
- "node_modules/unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/universalify": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
- "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
- "dev": true,
- "engines": {
- "node": ">= 4.0.0"
- }
- },
- "node_modules/untildify": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
- "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/update-browserslist-db": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
- "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "escalade": "^3.1.1",
- "picocolors": "^1.0.0"
- },
- "bin": {
- "update-browserslist-db": "cli.js"
- },
- "peerDependencies": {
- "browserslist": ">= 4.21.0"
- }
- },
- "node_modules/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/url-parse": {
- "version": "1.5.10",
- "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
- "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
- "dev": true,
- "dependencies": {
- "querystringify": "^2.1.1",
- "requires-port": "^1.0.0"
- }
- },
- "node_modules/url-toolkit": {
- "version": "2.2.5",
- "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.5.tgz",
- "integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg=="
- },
- "node_modules/util": {
- "version": "0.12.5",
- "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
- "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "is-arguments": "^1.0.4",
- "is-generator-function": "^1.0.7",
- "is-typed-array": "^1.1.3",
- "which-typed-array": "^1.1.2"
- }
- },
- "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/v8-to-istanbul": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz",
- "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==",
- "dev": true,
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.12",
- "@types/istanbul-lib-coverage": "^2.0.1",
- "convert-source-map": "^1.6.0"
- },
- "engines": {
- "node": ">=10.12.0"
- }
- },
- "node_modules/video.js": {
- "version": "8.6.1",
- "resolved": "https://registry.npmjs.org/video.js/-/video.js-8.6.1.tgz",
- "integrity": "sha512-CNYVJ5WWIZ7bOhbkkfcKqLGoc6WsE3Ft2RfS1lXdQTWk8UiSsPW2Ssk2JzPCA8qnIlUG9os/faCFsYWjyu4JcA==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "@videojs/http-streaming": "3.7.0",
- "@videojs/vhs-utils": "^4.0.0",
- "@videojs/xhr": "2.6.0",
- "aes-decrypter": "^4.0.1",
- "global": "4.4.0",
- "keycode": "2.2.0",
- "m3u8-parser": "^6.0.0",
- "mpd-parser": "^1.0.1",
- "mux.js": "^7.0.1",
- "safe-json-parse": "4.0.0",
- "videojs-contrib-quality-levels": "4.0.0",
- "videojs-font": "4.1.0",
- "videojs-vtt.js": "0.15.5"
- }
- },
- "node_modules/videojs-contrib-quality-levels": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.0.0.tgz",
- "integrity": "sha512-u5rmd8BjLwANp7XwuQ0Q/me34bMe6zg9PQdHfTS7aXgiVRbNTb4djcmfG7aeSrkpZjg+XCLezFNenlJaCjBHKw==",
- "dependencies": {
- "global": "^4.4.0"
- },
- "engines": {
- "node": ">=14",
- "npm": ">=6"
- },
- "peerDependencies": {
- "video.js": "^8"
- }
- },
- "node_modules/videojs-font": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-4.1.0.tgz",
- "integrity": "sha512-X1LuPfLZPisPLrANIAKCknZbZu5obVM/ylfd1CN+SsCmPZQ3UMDPcvLTpPBJxcBuTpHQq2MO1QCFt7p8spnZ/w=="
- },
- "node_modules/videojs-playlist": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/videojs-playlist/-/videojs-playlist-5.1.0.tgz",
- "integrity": "sha512-p5ohld6Kom9meYCcEVYj0JVS2MBL2XxMiU+IDB/xKpDOspFAHrERHrZEBoiJZc/mCfHixZBNgj1vWRgYsVVsrw==",
- "dependencies": {
- "global": "^4.3.2",
- "video.js": "^6 || ^7 || ^8"
- },
- "engines": {
- "node": ">=4.4.0"
- }
- },
- "node_modules/videojs-vtt.js": {
- "version": "0.15.5",
- "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.5.tgz",
- "integrity": "sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==",
- "dependencies": {
- "global": "^4.3.1"
- }
- },
- "node_modules/vite": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
- "integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
- "dev": true,
- "dependencies": {
- "esbuild": "^0.18.10",
- "postcss": "^8.4.27",
- "rollup": "^3.27.1"
- },
- "bin": {
- "vite": "bin/vite.js"
- },
- "engines": {
- "node": "^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/vitejs/vite?sponsor=1"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- },
- "peerDependencies": {
- "@types/node": ">= 14",
- "less": "*",
- "lightningcss": "^1.21.0",
- "sass": "*",
- "stylus": "*",
- "sugarss": "*",
- "terser": "^5.4.0"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- },
- "less": {
- "optional": true
- },
- "lightningcss": {
- "optional": true
- },
- "sass": {
- "optional": true
- },
- "stylus": {
- "optional": true
- },
- "sugarss": {
- "optional": true
- },
- "terser": {
- "optional": true
- }
- }
- },
- "node_modules/vite-node": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz",
- "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==",
- "dev": true,
- "dependencies": {
- "cac": "^6.7.14",
- "debug": "^4.3.4",
- "mlly": "^1.4.0",
- "pathe": "^1.1.1",
- "picocolors": "^1.0.0",
- "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0"
- },
- "bin": {
- "vite-node": "vite-node.mjs"
- },
- "engines": {
- "node": ">=v14.18.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- }
- },
- "node_modules/vite-plugin-monaco-editor": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/vite-plugin-monaco-editor/-/vite-plugin-monaco-editor-1.1.0.tgz",
- "integrity": "sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==",
- "peerDependencies": {
- "monaco-editor": ">=0.33.0"
- }
- },
- "node_modules/vitest": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz",
- "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==",
- "dev": true,
- "dependencies": {
- "@types/chai": "^4.3.5",
- "@types/chai-subset": "^1.3.3",
- "@types/node": "*",
- "@vitest/expect": "0.34.6",
- "@vitest/runner": "0.34.6",
- "@vitest/snapshot": "0.34.6",
- "@vitest/spy": "0.34.6",
- "@vitest/utils": "0.34.6",
- "acorn": "^8.9.0",
- "acorn-walk": "^8.2.0",
- "cac": "^6.7.14",
- "chai": "^4.3.10",
- "debug": "^4.3.4",
- "local-pkg": "^0.4.3",
- "magic-string": "^0.30.1",
- "pathe": "^1.1.1",
- "picocolors": "^1.0.0",
- "std-env": "^3.3.3",
- "strip-literal": "^1.0.1",
- "tinybench": "^2.5.0",
- "tinypool": "^0.7.0",
- "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0",
- "vite-node": "0.34.6",
- "why-is-node-running": "^2.2.2"
- },
- "bin": {
- "vitest": "vitest.mjs"
- },
- "engines": {
- "node": ">=v14.18.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- },
- "peerDependencies": {
- "@edge-runtime/vm": "*",
- "@vitest/browser": "*",
- "@vitest/ui": "*",
- "happy-dom": "*",
- "jsdom": "*",
- "playwright": "*",
- "safaridriver": "*",
- "webdriverio": "*"
- },
- "peerDependenciesMeta": {
- "@edge-runtime/vm": {
- "optional": true
- },
- "@vitest/browser": {
- "optional": true
- },
- "@vitest/ui": {
- "optional": true
- },
- "happy-dom": {
- "optional": true
- },
- "jsdom": {
- "optional": true
- },
- "playwright": {
- "optional": true
- },
- "safaridriver": {
- "optional": true
- },
- "webdriverio": {
- "optional": true
- }
- }
- },
- "node_modules/vscode-languageserver-textdocument": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz",
- "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg=="
- },
- "node_modules/vscode-languageserver-types": {
- "version": "3.17.2",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
- "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
- },
- "node_modules/vscode-uri": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz",
- "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ=="
- },
- "node_modules/w3c-xmlserializer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
- "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
- "dev": true,
- "dependencies": {
- "xml-name-validator": "^4.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "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/web-encoding": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz",
- "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==",
- "dev": true,
- "dependencies": {
- "util": "^0.12.3"
- },
- "optionalDependencies": {
- "@zxing/text-encoding": "0.9.0"
- }
- },
- "node_modules/webidl-conversions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
- "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
- "dev": true,
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/whatwg-encoding": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
- "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
- "dev": true,
- "dependencies": {
- "iconv-lite": "0.6.3"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/whatwg-mimetype": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
- "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
- "dev": true,
- "engines": {
- "node": ">=12"
- }
- },
- "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/whatwg-url/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/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/which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "dev": true,
- "dependencies": {
- "is-bigint": "^1.0.1",
- "is-boolean-object": "^1.1.0",
- "is-number-object": "^1.0.4",
- "is-string": "^1.0.5",
- "is-symbol": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-collection": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
- "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
- "dev": true,
- "dependencies": {
- "is-map": "^2.0.1",
- "is-set": "^2.0.1",
- "is-weakmap": "^2.0.1",
- "is-weakset": "^2.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-typed-array": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
- "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==",
- "dev": true,
- "dependencies": {
- "available-typed-arrays": "^1.0.5",
- "call-bind": "^1.0.2",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-tostringtag": "^1.0.0",
- "is-typed-array": "^1.1.10"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/why-is-node-running": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz",
- "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==",
- "dev": true,
- "dependencies": {
- "siginfo": "^2.0.0",
- "stackback": "0.0.2"
- },
- "bin": {
- "why-is-node-running": "cli.js"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "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/wrap-ansi/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/wrap-ansi/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/wrap-ansi/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/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": "8.13.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
- "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
- "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/xml-name-validator": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
- "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
- "dev": true,
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/xmlchars": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
- "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
- "dev": 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": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/yaml": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
- "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/yargs": {
- "version": "17.6.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz",
- "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==",
- "dev": true,
- "dependencies": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true,
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- }
- },
- "dependencies": {
- "@aashutoshrathi/word-wrap": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
- "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
- "dev": true
- },
- "@adobe/css-tools": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz",
- "integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==",
- "dev": true
- },
- "@alloc/quick-lru": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
- "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
- "dev": true
- },
- "@ampproject/remapping": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
- "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
- "dev": true,
- "requires": {
- "@jridgewell/gen-mapping": "^0.3.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- },
- "@babel/code-frame": {
- "version": "7.22.13",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
- "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.22.13",
- "chalk": "^2.4.2"
- }
- },
- "@babel/compat-data": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz",
- "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==",
- "dev": true
- },
- "@babel/core": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
- "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
- "dev": true,
- "requires": {
- "@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.22.13",
- "@babel/generator": "^7.23.0",
- "@babel/helper-compilation-targets": "^7.22.15",
- "@babel/helper-module-transforms": "^7.23.0",
- "@babel/helpers": "^7.23.2",
- "@babel/parser": "^7.23.0",
- "@babel/template": "^7.22.15",
- "@babel/traverse": "^7.23.2",
- "@babel/types": "^7.23.0",
- "convert-source-map": "^2.0.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.3",
- "semver": "^6.3.1"
- },
- "dependencies": {
- "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
- }
- }
- },
- "@babel/eslint-parser": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz",
- "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==",
- "dev": true,
- "requires": {
- "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
- "eslint-visitor-keys": "^2.1.0",
- "semver": "^6.3.0"
- },
- "dependencies": {
- "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
- }
- }
- },
- "@babel/generator": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
- "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.23.0",
- "@jridgewell/gen-mapping": "^0.3.2",
- "@jridgewell/trace-mapping": "^0.3.17",
- "jsesc": "^2.5.1"
- }
- },
- "@babel/helper-annotate-as-pure": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
- "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.22.5"
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
- "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.22.9",
- "@babel/helper-validator-option": "^7.22.15",
- "browserslist": "^4.21.9",
- "lru-cache": "^5.1.1",
- "semver": "^6.3.1"
- },
- "dependencies": {
- "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"
- }
- },
- "yallist": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
- "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
- "dev": true
- }
- }
- },
- "@babel/helper-environment-visitor": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
- "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
- "dev": true
- },
- "@babel/helper-function-name": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
- "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.22.15",
- "@babel/types": "^7.23.0"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
- "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.22.5"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
- "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.22.15"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz",
- "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-module-imports": "^7.22.15",
- "@babel/helper-simple-access": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/helper-validator-identifier": "^7.22.20"
- }
- },
- "@babel/helper-plugin-utils": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
- "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
- "dev": true
- },
- "@babel/helper-simple-access": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
- "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.22.5"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.22.5"
- }
- },
- "@babel/helper-string-parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
- "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
- "dev": true
- },
- "@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
- "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
- "dev": true
- },
- "@babel/helpers": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz",
- "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.22.15",
- "@babel/traverse": "^7.23.2",
- "@babel/types": "^7.23.0"
- }
- },
- "@babel/highlight": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
- "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.22.20",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/parser": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
- "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
- "dev": true
- },
- "@babel/plugin-syntax-class-properties": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
- "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-syntax-decorators": {
- "version": "7.19.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz",
- "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.19.0"
- }
- },
- "@babel/plugin-syntax-jsx": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz",
- "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.22.5"
- }
- },
- "@babel/plugin-transform-react-jsx": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz",
- "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-module-imports": "^7.22.15",
- "@babel/helper-plugin-utils": "^7.22.5",
- "@babel/plugin-syntax-jsx": "^7.22.5",
- "@babel/types": "^7.22.15"
- }
- },
- "@babel/plugin-transform-react-jsx-development": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz",
- "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==",
- "dev": true,
- "requires": {
- "@babel/plugin-transform-react-jsx": "^7.22.5"
- }
- },
- "@babel/runtime": {
- "version": "7.21.5",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz",
- "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==",
- "requires": {
- "regenerator-runtime": "^0.13.11"
- }
- },
- "@babel/template": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
- "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.22.13",
- "@babel/parser": "^7.22.15",
- "@babel/types": "^7.22.15"
- }
- },
- "@babel/traverse": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
- "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.22.13",
- "@babel/generator": "^7.23.0",
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-function-name": "^7.23.0",
- "@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.23.0",
- "@babel/types": "^7.23.0",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
- "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
- "dev": true,
- "requires": {
- "@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@bcoe/v8-coverage": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
- "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
- "dev": true
- },
- "@cycjimmy/jsmpeg-player": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/@cycjimmy/jsmpeg-player/-/jsmpeg-player-6.0.5.tgz",
- "integrity": "sha512-bVNHQ7VN9ecKT5AI/6RC7zpW/y4ca68a9txeR5Wiin+jKpUn/7buMe+5NPub89A8NNeNnKPQfrD2+c76ch36mA=="
- },
- "@esbuild/android-arm": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz",
- "integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/android-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz",
- "integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/android-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz",
- "integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==",
- "dev": true,
- "optional": true
- },
- "@esbuild/darwin-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz",
- "integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==",
- "dev": true,
- "optional": true
- },
- "@esbuild/darwin-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz",
- "integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==",
- "dev": true,
- "optional": true
- },
- "@esbuild/freebsd-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz",
- "integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/freebsd-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz",
- "integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-arm": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz",
- "integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz",
- "integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-ia32": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz",
- "integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-loong64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz",
- "integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-mips64el": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz",
- "integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-ppc64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz",
- "integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-riscv64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz",
- "integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-s390x": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz",
- "integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/linux-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz",
- "integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/netbsd-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz",
- "integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==",
- "dev": true,
- "optional": true
- },
- "@esbuild/openbsd-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz",
- "integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==",
- "dev": true,
- "optional": true
- },
- "@esbuild/sunos-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz",
- "integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-arm64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz",
- "integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-ia32": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz",
- "integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==",
- "dev": true,
- "optional": true
- },
- "@esbuild/win32-x64": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz",
- "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==",
- "dev": true,
- "optional": true
- },
- "@eslint-community/eslint-utils": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
- "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
- "dev": true,
- "requires": {
- "eslint-visitor-keys": "^3.3.0"
- }
- },
- "@eslint-community/regexpp": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz",
- "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==",
- "dev": true
- },
- "@eslint/eslintrc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
- "dev": true,
- "requires": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "dependencies": {
- "globals": {
- "version": "13.23.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
- "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
- "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
- }
- }
- },
- "@eslint/js": {
- "version": "8.55.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz",
- "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==",
- "dev": true
- },
- "@humanwhocodes/config-array": {
- "version": "0.11.13",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
- "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
- "dev": true,
- "requires": {
- "@humanwhocodes/object-schema": "^2.0.1",
- "debug": "^4.1.1",
- "minimatch": "^3.0.5"
- }
- },
- "@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true
- },
- "@humanwhocodes/object-schema": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
- "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
- "dev": true
- },
- "@istanbuljs/schema": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
- "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
- "dev": true
- },
- "@jest/schemas": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
- "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
- "dev": true,
- "requires": {
- "@sinclair/typebox": "^0.27.8"
- }
- },
- "@jridgewell/gen-mapping": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
- "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
- "dev": true,
- "requires": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- },
- "@jridgewell/resolve-uri": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
- "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
- "dev": true
- },
- "@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
- "dev": true
- },
- "@jridgewell/sourcemap-codec": {
- "version": "1.4.14",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
- "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
- "dev": true
- },
- "@jridgewell/trace-mapping": {
- "version": "0.3.17",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
- "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
- "dev": true,
- "requires": {
- "@jridgewell/resolve-uri": "3.1.0",
- "@jridgewell/sourcemap-codec": "1.4.14"
- }
- },
- "@mdn/browser-compat-data": {
- "version": "5.3.6",
- "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.3.6.tgz",
- "integrity": "sha512-sDz0Yjj8m+VTWPiC0TF28rLMCDS2fJTZZmDpFMx5Y0H4NVGzqOs30l4pV8Tpexen4GyT+wYCNjedY8pTNjiW7Q==",
- "dev": true
- },
- "@mswjs/cookies": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz",
- "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==",
- "dev": true,
- "requires": {
- "@types/set-cookie-parser": "^2.4.0",
- "set-cookie-parser": "^2.4.6"
- }
- },
- "@mswjs/interceptors": {
- "version": "0.17.10",
- "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.10.tgz",
- "integrity": "sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw==",
- "dev": true,
- "requires": {
- "@open-draft/until": "^1.0.3",
- "@types/debug": "^4.1.7",
- "@xmldom/xmldom": "^0.8.3",
- "debug": "^4.3.3",
- "headers-polyfill": "3.2.5",
- "outvariant": "^1.2.1",
- "strict-event-emitter": "^0.2.4",
- "web-encoding": "^1.1.5"
- }
- },
- "@nicolo-ribaudo/eslint-scope-5-internals": {
- "version": "5.1.1-v1",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
- "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==",
- "dev": true,
- "requires": {
- "eslint-scope": "5.1.1"
- },
- "dependencies": {
- "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"
- }
- },
- "estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true
- }
- }
- },
- "@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"
- }
- },
- "@open-draft/until": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz",
- "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==",
- "dev": true
- },
- "@pkgr/utils": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz",
- "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.3",
- "fast-glob": "^3.3.0",
- "is-glob": "^4.0.3",
- "open": "^9.1.0",
- "picocolors": "^1.0.0",
- "tslib": "^2.6.0"
- }
- },
- "@polka/url": {
- "version": "1.0.0-next.21",
- "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
- "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
- "dev": true
- },
- "@preact/preset-vite": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.7.0.tgz",
- "integrity": "sha512-m5N0FVtxbCCDxNk55NGhsRpKJChYcupcuQHzMJc/Bll07IKZKn8amwYciyKFS9haU6AgzDAJ/ewvApr6Qg1DHw==",
- "dev": true,
- "requires": {
- "@babel/plugin-transform-react-jsx": "^7.22.15",
- "@babel/plugin-transform-react-jsx-development": "^7.22.5",
- "@prefresh/vite": "^2.4.1",
- "@rollup/pluginutils": "^4.1.1",
- "babel-plugin-transform-hook-names": "^1.0.2",
- "debug": "^4.3.4",
- "kolorist": "^1.8.0",
- "resolve": "^1.22.8"
- }
- },
- "@prefresh/babel-plugin": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/@prefresh/babel-plugin/-/babel-plugin-0.5.0.tgz",
- "integrity": "sha512-joAwpkUDwo7ZqJnufXRGzUb+udk20RBgfA8oLPBh5aJH2LeStmV1luBfeJTztPdyCscC2j2SmZ/tVxFRMIxAEw==",
- "dev": true
- },
- "@prefresh/core": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/@prefresh/core/-/core-1.5.2.tgz",
- "integrity": "sha512-A/08vkaM1FogrCII5PZKCrygxSsc11obExBScm3JF1CryK2uDS3ZXeni7FeKCx1nYdUkj4UcJxzPzc1WliMzZA==",
- "dev": true,
- "requires": {}
- },
- "@prefresh/utils": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@prefresh/utils/-/utils-1.2.0.tgz",
- "integrity": "sha512-KtC/fZw+oqtwOLUFM9UtiitB0JsVX0zLKNyRTA332sqREqSALIIQQxdUCS1P3xR/jT1e2e8/5rwH6gdcMLEmsQ==",
- "dev": true
- },
- "@prefresh/vite": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/@prefresh/vite/-/vite-2.4.1.tgz",
- "integrity": "sha512-vthWmEqu8TZFeyrBNc9YE5SiC3DVSzPgsOCp/WQ7FqdHpOIJi7Z8XvCK06rBPOtG4914S52MjG9Ls22eVAiuqQ==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.22.1",
- "@prefresh/babel-plugin": "0.5.0",
- "@prefresh/core": "^1.5.1",
- "@prefresh/utils": "^1.2.0",
- "@rollup/pluginutils": "^4.2.1"
- }
- },
- "@rollup/pluginutils": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
- "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
- "dev": true,
- "requires": {
- "estree-walker": "^2.0.1",
- "picomatch": "^2.2.2"
- }
- },
- "@sinclair/typebox": {
- "version": "0.27.8",
- "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
- "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
- "dev": true
- },
- "@tailwindcss/forms": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz",
- "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==",
- "dev": true,
- "requires": {
- "mini-svg-data-uri": "^1.2.3"
- }
- },
- "@testing-library/dom": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.0.tgz",
- "integrity": "sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.10.4",
- "@babel/runtime": "^7.12.5",
- "@types/aria-query": "^4.2.0",
- "aria-query": "^5.0.0",
- "chalk": "^4.1.0",
- "dom-accessibility-api": "^0.5.9",
- "lz-string": "^1.4.4",
- "pretty-format": "^27.0.2"
- },
- "dependencies": {
- "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"
- }
- },
- "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"
- }
- },
- "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
- },
- "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
- },
- "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"
- }
- }
- }
- },
- "@testing-library/jest-dom": {
- "version": "6.1.5",
- "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.1.5.tgz",
- "integrity": "sha512-3y04JLW+EceVPy2Em3VwNr95dOKqA8DhR0RJHhHKDZNYXcVXnEK7WIrpj4eYU8SVt/qYZ2aRWt/WgQ+grNES8g==",
- "dev": true,
- "requires": {
- "@adobe/css-tools": "^4.3.1",
- "@babel/runtime": "^7.9.2",
- "aria-query": "^5.0.0",
- "chalk": "^3.0.0",
- "css.escape": "^1.5.1",
- "dom-accessibility-api": "^0.5.6",
- "lodash": "^4.17.15",
- "redent": "^3.0.0"
- },
- "dependencies": {
- "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"
- }
- },
- "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"
- }
- },
- "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
- },
- "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
- },
- "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"
- }
- }
- }
- },
- "@testing-library/preact": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@testing-library/preact/-/preact-3.2.3.tgz",
- "integrity": "sha512-y6Kklp1XK3f1X2fWCbujmJyzkf+1BgLYXNgAx21j9+D4CoqMTz5qC4SQufb1L6q/jxLGACzrQ90ewVOTBvHOfg==",
- "dev": true,
- "requires": {
- "@testing-library/dom": "^8.11.1"
- }
- },
- "@testing-library/user-event": {
- "version": "14.5.1",
- "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.1.tgz",
- "integrity": "sha512-UCcUKrUYGj7ClomOo2SpNVvx4/fkd/2BbIHDCle8A0ax+P3bU7yJwDBDrS6ZwdTMARWTGODX1hEsCcO+7beJjg==",
- "dev": true,
- "requires": {}
- },
- "@tootallnate/once": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
- "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
- "dev": true
- },
- "@tsconfig/node14": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
- "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
- "dev": true
- },
- "@types/aria-query": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz",
- "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==",
- "dev": true
- },
- "@types/chai": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
- "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==",
- "dev": true
- },
- "@types/chai-subset": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz",
- "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==",
- "dev": true,
- "requires": {
- "@types/chai": "*"
- }
- },
- "@types/concat-stream": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz",
- "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@types/node": "*"
- }
- },
- "@types/cookie": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
- "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
- "dev": true
- },
- "@types/debug": {
- "version": "4.1.9",
- "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.9.tgz",
- "integrity": "sha512-8Hz50m2eoS56ldRlepxSBa6PWEVCtzUo/92HgLc2qTMnotJNIm7xP+UZhyWoYsyOdd5dxZ+NZLb24rsKyFs2ow==",
- "dev": true,
- "requires": {
- "@types/ms": "*"
- }
- },
- "@types/form-data": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz",
- "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@types/node": "*"
- }
- },
- "@types/istanbul-lib-coverage": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
- "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
- "dev": true
- },
- "@types/js-levenshtein": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz",
- "integrity": "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==",
- "dev": true
- },
- "@types/json-schema": {
- "version": "7.0.12",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
- "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA=="
- },
- "@types/ms": {
- "version": "0.7.31",
- "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz",
- "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
- "dev": true
- },
- "@types/node": {
- "version": "18.11.9",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
- "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
- "dev": true
- },
- "@types/qs": {
- "version": "6.9.7",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
- "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "@types/semver": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
- "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==",
- "dev": true
- },
- "@types/set-cookie-parser": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz",
- "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==",
- "dev": true,
- "requires": {
- "@types/node": "*"
- }
- },
- "@typescript-eslint/eslint-plugin": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz",
- "integrity": "sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==",
- "dev": true,
- "requires": {
- "@eslint-community/regexpp": "^4.5.1",
- "@typescript-eslint/scope-manager": "6.13.2",
- "@typescript-eslint/type-utils": "6.13.2",
- "@typescript-eslint/utils": "6.13.2",
- "@typescript-eslint/visitor-keys": "6.13.2",
- "debug": "^4.3.4",
- "graphemer": "^1.4.0",
- "ignore": "^5.2.4",
- "natural-compare": "^1.4.0",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
- },
- "dependencies": {
- "semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "@typescript-eslint/experimental-utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz",
- "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/utils": "5.62.0"
- },
- "dependencies": {
- "@typescript-eslint/scope-manager": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
- "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
- "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
- "dev": true
- },
- "@typescript-eslint/typescript-estree": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
- "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- }
- },
- "@typescript-eslint/utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
- "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
- "dev": true,
- "requires": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@types/json-schema": "^7.0.9",
- "@types/semver": "^7.3.12",
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/typescript-estree": "5.62.0",
- "eslint-scope": "^5.1.1",
- "semver": "^7.3.7"
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
- "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "5.62.0",
- "eslint-visitor-keys": "^3.3.0"
- }
- },
- "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"
- }
- },
- "estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true
- },
- "semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "@typescript-eslint/parser": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz",
- "integrity": "sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==",
- "dev": true,
- "requires": {
- "@typescript-eslint/scope-manager": "6.13.2",
- "@typescript-eslint/types": "6.13.2",
- "@typescript-eslint/typescript-estree": "6.13.2",
- "@typescript-eslint/visitor-keys": "6.13.2",
- "debug": "^4.3.4"
- }
- },
- "@typescript-eslint/scope-manager": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz",
- "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "6.13.2",
- "@typescript-eslint/visitor-keys": "6.13.2"
- }
- },
- "@typescript-eslint/type-utils": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz",
- "integrity": "sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/typescript-estree": "6.13.2",
- "@typescript-eslint/utils": "6.13.2",
- "debug": "^4.3.4",
- "ts-api-utils": "^1.0.1"
- }
- },
- "@typescript-eslint/types": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz",
- "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==",
- "dev": true
- },
- "@typescript-eslint/typescript-estree": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz",
- "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "6.13.2",
- "@typescript-eslint/visitor-keys": "6.13.2",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
- },
- "dependencies": {
- "semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "@typescript-eslint/utils": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz",
- "integrity": "sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==",
- "dev": true,
- "requires": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@types/json-schema": "^7.0.12",
- "@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "6.13.2",
- "@typescript-eslint/types": "6.13.2",
- "@typescript-eslint/typescript-estree": "6.13.2",
- "semver": "^7.5.4"
- },
- "dependencies": {
- "semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "6.13.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz",
- "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "6.13.2",
- "eslint-visitor-keys": "^3.4.1"
- }
- },
- "@ungap/structured-clone": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
- "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
- "dev": true
- },
- "@videojs/http-streaming": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-3.7.0.tgz",
- "integrity": "sha512-5uLFKBL8CvD56dxxJyuxqB5CY0tdoa4SE9KbXakeiAy6iFBUEPvTr2YGLKEWvQ8Lojs1wl+FQndLdv+GO7t9Fw==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "4.0.0",
- "aes-decrypter": "4.0.1",
- "global": "^4.4.0",
- "m3u8-parser": "^7.1.0",
- "mpd-parser": "^1.2.2",
- "mux.js": "7.0.1",
- "video.js": "^7 || ^8"
- },
- "dependencies": {
- "m3u8-parser": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-7.1.0.tgz",
- "integrity": "sha512-7N+pk79EH4oLKPEYdgRXgAsKDyA/VCo0qCHlUwacttQA0WqsjZQYmNfywMvjlY9MpEBVZEt0jKFd73Kv15EBYQ==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.5",
- "global": "^4.4.0"
- },
- "dependencies": {
- "@videojs/vhs-utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
- "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- }
- }
- }
- }
- }
- },
- "@videojs/vhs-utils": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-4.0.0.tgz",
- "integrity": "sha512-xJp7Yd4jMLwje2vHCUmi8MOUU76nxiwII3z4Eg3Ucb+6rrkFVGosrXlMgGnaLjq724j3wzNElRZ71D/CKrTtxg==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- }
- },
- "@videojs/xhr": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.6.0.tgz",
- "integrity": "sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q==",
- "requires": {
- "@babel/runtime": "^7.5.5",
- "global": "~4.4.0",
- "is-function": "^1.0.1"
- }
- },
- "@vitest/coverage-v8": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-0.34.6.tgz",
- "integrity": "sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==",
- "dev": true,
- "requires": {
- "@ampproject/remapping": "^2.2.1",
- "@bcoe/v8-coverage": "^0.2.3",
- "istanbul-lib-coverage": "^3.2.0",
- "istanbul-lib-report": "^3.0.1",
- "istanbul-lib-source-maps": "^4.0.1",
- "istanbul-reports": "^3.1.5",
- "magic-string": "^0.30.1",
- "picocolors": "^1.0.0",
- "std-env": "^3.3.3",
- "test-exclude": "^6.0.0",
- "v8-to-istanbul": "^9.1.0"
- }
- },
- "@vitest/expect": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz",
- "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==",
- "dev": true,
- "requires": {
- "@vitest/spy": "0.34.6",
- "@vitest/utils": "0.34.6",
- "chai": "^4.3.10"
- }
- },
- "@vitest/runner": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz",
- "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==",
- "dev": true,
- "requires": {
- "@vitest/utils": "0.34.6",
- "p-limit": "^4.0.0",
- "pathe": "^1.1.1"
- },
- "dependencies": {
- "p-limit": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
- "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^1.0.0"
- }
- },
- "yocto-queue": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
- "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
- "dev": true
- }
- }
- },
- "@vitest/snapshot": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz",
- "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==",
- "dev": true,
- "requires": {
- "magic-string": "^0.30.1",
- "pathe": "^1.1.1",
- "pretty-format": "^29.5.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true
- },
- "pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
- "dev": true,
- "requires": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- }
- },
- "react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- }
- }
- },
- "@vitest/spy": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz",
- "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==",
- "dev": true,
- "requires": {
- "tinyspy": "^2.1.1"
- }
- },
- "@vitest/ui": {
- "version": "0.34.7",
- "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.34.7.tgz",
- "integrity": "sha512-iizUu9R5Rsvsq8FtdJ0suMqEfIsIIzziqnasMHe4VH8vG+FnZSA3UAtCHx6rLeRupIFVAVg7bptMmuvMcsn8WQ==",
- "dev": true,
- "requires": {
- "@vitest/utils": "0.34.7",
- "fast-glob": "^3.3.0",
- "fflate": "^0.8.0",
- "flatted": "^3.2.7",
- "pathe": "^1.1.1",
- "picocolors": "^1.0.0",
- "sirv": "^2.0.3"
- },
- "dependencies": {
- "@vitest/utils": {
- "version": "0.34.7",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.7.tgz",
- "integrity": "sha512-ziAavQLpCYS9sLOorGrFFKmy2gnfiNU0ZJ15TsMz/K92NAPS/rp9K4z6AJQQk5Y8adCy4Iwpxy7pQumQ/psnRg==",
- "dev": true,
- "requires": {
- "diff-sequences": "^29.4.3",
- "loupe": "^2.3.6",
- "pretty-format": "^29.5.0"
- }
- },
- "ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true
- },
- "pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
- "dev": true,
- "requires": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- }
- },
- "react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- }
- }
- },
- "@vitest/utils": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz",
- "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==",
- "dev": true,
- "requires": {
- "diff-sequences": "^29.4.3",
- "loupe": "^2.3.6",
- "pretty-format": "^29.5.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true
- },
- "pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
- "dev": true,
- "requires": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- }
- },
- "react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- }
- }
- },
- "@xmldom/xmldom": {
- "version": "0.8.7",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.7.tgz",
- "integrity": "sha512-sI1Ly2cODlWStkINzqGrZ8K6n+MTSbAeQnAipGyL+KZCXuHaRlj2gyyy8B/9MvsFFqN7XHryQnB2QwhzvJXovg=="
- },
- "@zxing/text-encoding": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
- "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
- "dev": true,
- "optional": true
- },
- "abab": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
- "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
- "dev": true
- },
- "acorn": {
- "version": "8.10.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
- "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
- "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.2.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
- "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
- "dev": true
- },
- "aes-decrypter": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-4.0.1.tgz",
- "integrity": "sha512-H1nh/P9VZXUf17AA5NQfJML88CFjVBDuGkp5zDHa7oEhYN9TTpNLJknRY1ie0iSKWlDf6JRnJKaZVDSQdPy6Cg==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.5",
- "global": "^4.4.0",
- "pkcs7": "^1.0.4"
- },
- "dependencies": {
- "@videojs/vhs-utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
- "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- }
- }
- }
- },
- "agent-base": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
- "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
- "dev": true,
- "requires": {
- "debug": "4"
- }
- },
- "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"
- }
- },
- "ansi-escapes": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
- "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
- "dev": true,
- "requires": {
- "type-fest": "^0.21.3"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.21.3",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
- "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
- "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": "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"
- }
- },
- "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.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
- "dev": true,
- "requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- }
- },
- "arg": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
- "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
- "dev": true
- },
- "argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "aria-query": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
- "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
- "dev": true,
- "requires": {
- "deep-equal": "^2.0.5"
- }
- },
- "array-includes": {
- "version": "3.1.6",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
- "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "get-intrinsic": "^1.1.3",
- "is-string": "^1.0.7"
- }
- },
- "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
- },
- "array.prototype.flatmap": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz",
- "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "asap": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
- "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "assertion-error": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
- "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
- "dev": true
- },
- "ast-metadata-inferer": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.8.0.tgz",
- "integrity": "sha512-jOMKcHht9LxYIEQu+RVd22vtgrPaVCtDRQ/16IGmurdzxvYbDd5ynxjnyrzLnieG96eTcAyaoj/wN/4/1FyyeA==",
- "dev": true,
- "requires": {
- "@mdn/browser-compat-data": "^5.2.34"
- }
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
- },
- "autoprefixer": {
- "version": "10.4.16",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
- "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==",
- "dev": true,
- "requires": {
- "browserslist": "^4.21.10",
- "caniuse-lite": "^1.0.30001538",
- "fraction.js": "^4.3.6",
- "normalize-range": "^0.1.2",
- "picocolors": "^1.0.0",
- "postcss-value-parser": "^4.2.0"
- }
- },
- "available-typed-arrays": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
- "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
- "dev": true
- },
- "axios": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
- "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
- "requires": {
- "follow-redirects": "^1.15.0",
- "form-data": "^4.0.0",
- "proxy-from-env": "^1.1.0"
- },
- "dependencies": {
- "form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- }
- }
- }
- },
- "babel-plugin-transform-hook-names": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-hook-names/-/babel-plugin-transform-hook-names-1.0.2.tgz",
- "integrity": "sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==",
- "dev": true,
- "requires": {}
- },
- "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-arraybuffer-es6": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/base64-arraybuffer-es6/-/base64-arraybuffer-es6-0.7.0.tgz",
- "integrity": "sha512-ESyU/U1CFZDJUdr+neHRhNozeCv72Y7Vm0m1DCbjX3KBjT6eYocvAJlSk6+8+HkVwXlT1FNxhGW6q3UKAlCvvw==",
- "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
- },
- "big-integer": {
- "version": "1.6.51",
- "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
- "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
- "dev": true
- },
- "binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "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"
- },
- "dependencies": {
- "readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- }
- }
- },
- "bplist-parser": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
- "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==",
- "dev": true,
- "requires": {
- "big-integer": "^1.6.44"
- }
- },
- "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.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "browserslist": {
- "version": "4.21.10",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
- "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001517",
- "electron-to-chromium": "^1.4.477",
- "node-releases": "^2.0.13",
- "update-browserslist-db": "^1.0.11"
- }
- },
- "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,
- "optional": true,
- "peer": true
- },
- "bundle-name": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
- "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==",
- "dev": true,
- "requires": {
- "run-applescript": "^5.0.0"
- }
- },
- "cac": {
- "version": "6.7.14",
- "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
- "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
- "dev": true
- },
- "call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- }
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true
- },
- "camelcase-css": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
- "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
- "dev": true
- },
- "caniuse-lite": {
- "version": "1.0.30001538",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz",
- "integrity": "sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==",
- "dev": true
- },
- "caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "chai": {
- "version": "4.3.10",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz",
- "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==",
- "dev": true,
- "requires": {
- "assertion-error": "^1.1.0",
- "check-error": "^1.0.3",
- "deep-eql": "^4.1.3",
- "get-func-name": "^2.0.2",
- "loupe": "^2.3.6",
- "pathval": "^1.1.1",
- "type-detect": "^4.0.8"
- }
- },
- "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"
- }
- },
- "chardet": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
- "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
- "dev": true
- },
- "check-error": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
- "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
- "dev": true,
- "requires": {
- "get-func-name": "^2.0.2"
- }
- },
- "chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "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"
- }
- }
- }
- },
- "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-spinners": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
- "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==",
- "dev": true
- },
- "cli-width": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
- "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
- "dev": true
- },
- "cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "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
- },
- "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
- },
- "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": "4.1.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
- "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
- "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
- },
- "concat-stream": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
- "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^2.2.2",
- "typedarray": "^0.0.6"
- }
- },
- "convert-source-map": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
- "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
- "dev": true
- },
- "cookie": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
- "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
- "dev": true
- },
- "copy-to-clipboard": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
- "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
- "requires": {
- "toggle-selection": "^1.0.6"
- }
- },
- "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,
- "optional": true,
- "peer": true
- },
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "css.escape": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
- "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
- "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
- },
- "cssstyle": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
- "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
- "dev": true,
- "requires": {
- "rrweb-cssom": "^0.6.0"
- }
- },
- "data-urls": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz",
- "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==",
- "dev": true,
- "requires": {
- "abab": "^2.0.6",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^12.0.0"
- },
- "dependencies": {
- "tr46": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
- "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
- "dev": true,
- "requires": {
- "punycode": "^2.3.0"
- }
- },
- "whatwg-url": {
- "version": "12.0.1",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
- "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
- "dev": true,
- "requires": {
- "tr46": "^4.1.1",
- "webidl-conversions": "^7.0.0"
- }
- }
- }
- },
- "date-fns": {
- "version": "2.30.0",
- "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
- "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
- "requires": {
- "@babel/runtime": "^7.21.0"
- }
- },
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "decimal.js": {
- "version": "10.4.3",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
- "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
- "dev": true
- },
- "deep-eql": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
- "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
- "dev": true,
- "requires": {
- "type-detect": "^4.0.0"
- }
- },
- "deep-equal": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz",
- "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-get-iterator": "^1.1.2",
- "get-intrinsic": "^1.1.3",
- "is-arguments": "^1.1.1",
- "is-date-object": "^1.0.5",
- "is-regex": "^1.1.4",
- "isarray": "^2.0.5",
- "object-is": "^1.1.5",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "side-channel": "^1.0.4",
- "which-boxed-primitive": "^1.0.2",
- "which-collection": "^1.0.1",
- "which-typed-array": "^1.1.8"
- },
- "dependencies": {
- "isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true
- }
- }
- },
- "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
- },
- "default-browser": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz",
- "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==",
- "dev": true,
- "requires": {
- "bundle-name": "^3.0.0",
- "default-browser-id": "^3.0.0",
- "execa": "^7.1.1",
- "titleize": "^3.0.0"
- }
- },
- "default-browser-id": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz",
- "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==",
- "dev": true,
- "requires": {
- "bplist-parser": "^0.2.0",
- "untildify": "^4.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-lazy-prop": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
- "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
- "dev": true
- },
- "define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "dev": true,
- "requires": {
- "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=="
- },
- "didyoumean": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
- "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
- "dev": true
- },
- "diff-sequences": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
- "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
- "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"
- }
- },
- "dlv": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
- "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
- "dev": true
- },
- "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-accessibility-api": {
- "version": "0.5.14",
- "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz",
- "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==",
- "dev": true
- },
- "dom-walk": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
- "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
- },
- "domexception": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
- "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
- "dev": true,
- "requires": {
- "webidl-conversions": "^7.0.0"
- }
- },
- "electron-to-chromium": {
- "version": "1.4.508",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz",
- "integrity": "sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg==",
- "dev": true
- },
- "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
- },
- "entities": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
- "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
- "dev": true
- },
- "es-abstract": {
- "version": "1.20.4",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz",
- "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.1.3",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-property-descriptors": "^1.0.0",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.7",
- "is-negative-zero": "^2.0.2",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.12.2",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "safe-regex-test": "^1.0.0",
- "string.prototype.trimend": "^1.0.5",
- "string.prototype.trimstart": "^1.0.5",
- "unbox-primitive": "^1.0.2"
- }
- },
- "es-get-iterator": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz",
- "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.0",
- "has-symbols": "^1.0.1",
- "is-arguments": "^1.1.0",
- "is-map": "^2.0.2",
- "is-set": "^2.0.2",
- "is-string": "^1.0.5",
- "isarray": "^2.0.5"
- },
- "dependencies": {
- "isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true
- }
- }
- },
- "es-shim-unscopables": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
- "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
- "dev": true,
- "requires": {
- "has": "^1.0.3"
- }
- },
- "es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "dev": true,
- "requires": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- }
- },
- "esbuild": {
- "version": "0.18.17",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz",
- "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==",
- "dev": true,
- "requires": {
- "@esbuild/android-arm": "0.18.17",
- "@esbuild/android-arm64": "0.18.17",
- "@esbuild/android-x64": "0.18.17",
- "@esbuild/darwin-arm64": "0.18.17",
- "@esbuild/darwin-x64": "0.18.17",
- "@esbuild/freebsd-arm64": "0.18.17",
- "@esbuild/freebsd-x64": "0.18.17",
- "@esbuild/linux-arm": "0.18.17",
- "@esbuild/linux-arm64": "0.18.17",
- "@esbuild/linux-ia32": "0.18.17",
- "@esbuild/linux-loong64": "0.18.17",
- "@esbuild/linux-mips64el": "0.18.17",
- "@esbuild/linux-ppc64": "0.18.17",
- "@esbuild/linux-riscv64": "0.18.17",
- "@esbuild/linux-s390x": "0.18.17",
- "@esbuild/linux-x64": "0.18.17",
- "@esbuild/netbsd-x64": "0.18.17",
- "@esbuild/openbsd-x64": "0.18.17",
- "@esbuild/sunos-x64": "0.18.17",
- "@esbuild/win32-arm64": "0.18.17",
- "@esbuild/win32-ia32": "0.18.17",
- "@esbuild/win32-x64": "0.18.17"
- }
- },
- "escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "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
- },
- "eslint": {
- "version": "8.55.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz",
- "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==",
- "dev": true,
- "requires": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.55.0",
- "@humanwhocodes/config-array": "^0.11.13",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
- "ajv": "^6.12.4",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.3.2",
- "doctrine": "^3.0.0",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "esquery": "^1.4.2",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
- "ignore": "^5.2.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
- },
- "dependencies": {
- "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"
- }
- },
- "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"
- }
- },
- "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
- },
- "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
- },
- "globals": {
- "version": "13.19.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
- "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
- "dev": true,
- "requires": {
- "type-fest": "^0.20.2"
- }
- },
- "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
- },
- "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"
- }
- },
- "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-config-preact": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-config-preact/-/eslint-config-preact-1.3.0.tgz",
- "integrity": "sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.13.16",
- "@babel/eslint-parser": "^7.13.14",
- "@babel/plugin-syntax-class-properties": "^7.12.13",
- "@babel/plugin-syntax-decorators": "^7.12.13",
- "@babel/plugin-syntax-jsx": "^7.12.13",
- "eslint-plugin-compat": "^4.0.0",
- "eslint-plugin-jest": "^25.2.4",
- "eslint-plugin-react": "^7.27.0",
- "eslint-plugin-react-hooks": "^4.3.0"
- },
- "dependencies": {
- "@typescript-eslint/eslint-plugin": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
- "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@eslint-community/regexpp": "^4.4.0",
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/type-utils": "5.62.0",
- "@typescript-eslint/utils": "5.62.0",
- "debug": "^4.3.4",
- "graphemer": "^1.4.0",
- "ignore": "^5.2.0",
- "natural-compare-lite": "^1.4.0",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- }
- },
- "@typescript-eslint/parser": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
- "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/typescript-estree": "5.62.0",
- "debug": "^4.3.4"
- }
- },
- "@typescript-eslint/scope-manager": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
- "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0"
- }
- },
- "@typescript-eslint/type-utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz",
- "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@typescript-eslint/typescript-estree": "5.62.0",
- "@typescript-eslint/utils": "5.62.0",
- "debug": "^4.3.4",
- "tsutils": "^3.21.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
- "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "@typescript-eslint/typescript-estree": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
- "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- }
- },
- "@typescript-eslint/utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
- "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@types/json-schema": "^7.0.9",
- "@types/semver": "^7.3.12",
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/typescript-estree": "5.62.0",
- "eslint-scope": "^5.1.1",
- "semver": "^7.3.7"
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
- "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@typescript-eslint/types": "5.62.0",
- "eslint-visitor-keys": "^3.3.0"
- }
- },
- "eslint-plugin-jest": {
- "version": "25.7.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz",
- "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==",
- "dev": true,
- "requires": {
- "@typescript-eslint/experimental-utils": "^5.0.0"
- }
- },
- "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,
- "optional": true,
- "peer": true,
- "requires": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- }
- },
- "estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "eslint-config-prettier": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
- "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
- "dev": true,
- "requires": {}
- },
- "eslint-plugin-compat": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-4.1.4.tgz",
- "integrity": "sha512-RxySWBmzfIROLFKgeJBJue2BU/6vM2KJWXWAUq+oW4QtrsZXRxbjgxmO1OfF3sHcRuuIenTS/wgo3GyUWZF24w==",
- "dev": true,
- "requires": {
- "@mdn/browser-compat-data": "^5.2.47",
- "@tsconfig/node14": "^1.0.3",
- "ast-metadata-inferer": "^0.8.0",
- "browserslist": "^4.21.5",
- "caniuse-lite": "^1.0.30001473",
- "find-up": "^5.0.0",
- "lodash.memoize": "4.1.2",
- "semver": "7.3.8"
- },
- "dependencies": {
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "eslint-plugin-jest": {
- "version": "27.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.0.tgz",
- "integrity": "sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==",
- "dev": true,
- "requires": {
- "@typescript-eslint/utils": "^5.10.0"
- },
- "dependencies": {
- "@typescript-eslint/scope-manager": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
- "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
- "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
- "dev": true
- },
- "@typescript-eslint/typescript-estree": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
- "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/visitor-keys": "5.62.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- }
- },
- "@typescript-eslint/utils": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
- "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
- "dev": true,
- "requires": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@types/json-schema": "^7.0.9",
- "@types/semver": "^7.3.12",
- "@typescript-eslint/scope-manager": "5.62.0",
- "@typescript-eslint/types": "5.62.0",
- "@typescript-eslint/typescript-estree": "5.62.0",
- "eslint-scope": "^5.1.1",
- "semver": "^7.3.7"
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "5.62.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
- "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "5.62.0",
- "eslint-visitor-keys": "^3.3.0"
- }
- },
- "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"
- }
- },
- "estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true
- },
- "semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "eslint-plugin-prettier": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz",
- "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==",
- "dev": true,
- "requires": {
- "prettier-linter-helpers": "^1.0.0",
- "synckit": "^0.8.5"
- }
- },
- "eslint-plugin-react": {
- "version": "7.31.10",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz",
- "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==",
- "dev": true,
- "requires": {
- "array-includes": "^3.1.5",
- "array.prototype.flatmap": "^1.3.0",
- "doctrine": "^2.1.0",
- "estraverse": "^5.3.0",
- "jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "minimatch": "^3.1.2",
- "object.entries": "^1.1.5",
- "object.fromentries": "^2.0.5",
- "object.hasown": "^1.1.1",
- "object.values": "^1.1.5",
- "prop-types": "^15.8.1",
- "resolve": "^2.0.0-next.3",
- "semver": "^6.3.0",
- "string.prototype.matchall": "^4.0.7"
- },
- "dependencies": {
- "doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "resolve": {
- "version": "2.0.0-next.4",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
- "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
- "dev": true,
- "requires": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- }
- }
- }
- },
- "eslint-plugin-react-hooks": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
- "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
- "dev": true,
- "requires": {}
- },
- "eslint-plugin-vitest-globals": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vitest-globals/-/eslint-plugin-vitest-globals-1.4.0.tgz",
- "integrity": "sha512-WE+YlK9X9s4vf5EaYRU0Scw7WItDZStm+PapFSYlg2ABNtaQ4zIG7wEqpoUB3SlfM+SgkhgmzR0TeJOO5k3/Nw==",
- "dev": true
- },
- "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"
- }
- },
- "esquery": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
- "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
- "dev": true,
- "requires": {
- "estraverse": "^5.1.0"
- }
- },
- "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"
- }
- },
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "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==",
- "dev": true
- },
- "esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "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": "7.2.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz",
- "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.1",
- "human-signals": "^4.3.0",
- "is-stream": "^3.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^5.1.0",
- "onetime": "^6.0.0",
- "signal-exit": "^3.0.7",
- "strip-final-newline": "^3.0.0"
- },
- "dependencies": {
- "mimic-fn": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
- "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
- "dev": true
- },
- "onetime": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
- "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
- "dev": true,
- "requires": {
- "mimic-fn": "^4.0.0"
- }
- }
- }
- },
- "external-editor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
- "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
- "dev": true,
- "requires": {
- "chardet": "^0.7.0",
- "iconv-lite": "^0.4.24",
- "tmp": "^0.0.33"
- },
- "dependencies": {
- "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"
- }
- }
- }
- },
- "fake-indexeddb": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/fake-indexeddb/-/fake-indexeddb-4.0.2.tgz",
- "integrity": "sha512-SdTwEhnakbgazc7W3WUXOJfGmhH0YfG4d+dRPOFoYDRTL6U5t8tvrmkf2W/C3W1jk2ylV7Wrnj44RASqpX/lEw==",
- "dev": true,
- "requires": {
- "realistic-structured-clone": "^3.0.0"
- }
- },
- "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-diff": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
- "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
- "dev": true
- },
- "fast-glob": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
- "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
- "dev": true,
- "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.4"
- },
- "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
- },
- "fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "dev": true,
- "requires": {
- "reusify": "^1.0.4"
- }
- },
- "fflate": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.0.tgz",
- "integrity": "sha512-FAdS4qMuFjsJj6XHbBaZeXOgaypXp8iw/Tpyuq/w3XA41jjLHT8NPA+n7czH/DDhdncq0nAyDZmPeWXh2qmdIg==",
- "dev": true
- },
- "figures": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
- "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
- "dev": true,
- "requires": {
- "escape-string-regexp": "^1.0.5"
- }
- },
- "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.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "requires": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dev": true,
- "requires": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- }
- },
- "flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
- "dev": true
- },
- "follow-redirects": {
- "version": "1.15.2",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
- "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
- },
- "for-each": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
- "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
- "dev": true,
- "requires": {
- "is-callable": "^1.1.3"
- }
- },
- "form-data": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
- "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- }
- },
- "fraction.js": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz",
- "integrity": "sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==",
- "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.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "optional": true
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0",
- "functions-have-names": "^1.2.2"
- }
- },
- "functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "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-func-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
- "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
- "dev": true
- },
- "get-intrinsic": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
- "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- }
- },
- "get-port": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz",
- "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "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
- },
- "get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- }
- },
- "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"
- }
- },
- "global": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
- "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
- "requires": {
- "min-document": "^2.19.0",
- "process": "^0.11.10"
- }
- },
- "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"
- }
- },
- "gopd": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
- "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
- "dev": true,
- "requires": {
- "get-intrinsic": "^1.1.3"
- }
- },
- "graphemer": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true
- },
- "graphql": {
- "version": "16.8.1",
- "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
- "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
- "dev": true
- },
- "happy-dom": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-7.6.7.tgz",
- "integrity": "sha512-9pOslsClyF5JX9ZM3dzRhLjTHqc4dha7v+ZB94u4PHMVTdLplXAnh5e5WXtPUU1n0J4tDUavslJqitqt/1W45g==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "css.escape": "^1.5.1",
- "he": "^1.2.0",
- "node-fetch": "^2.x.x",
- "sync-request": "^6.1.0",
- "webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^2.0.0",
- "whatwg-mimetype": "^3.0.0"
- }
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
- "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
- },
- "has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "dev": true,
- "requires": {
- "get-intrinsic": "^1.1.1"
- }
- },
- "has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "dev": true
- },
- "has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "dev": true,
- "requires": {
- "has-symbols": "^1.0.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,
- "optional": true,
- "peer": true
- },
- "headers-polyfill": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.2.5.tgz",
- "integrity": "sha512-tUCGvt191vNSQgttSyJoibR+VO+I6+iCHIUdhzEMJKE+EAL8BwCN7fUOZlY4ofOelNHsK+gEjxB/B+9N3EWtdA==",
- "dev": true
- },
- "html-encoding-sniffer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
- "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
- "dev": true,
- "requires": {
- "whatwg-encoding": "^2.0.0"
- }
- },
- "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
- },
- "http-basic": {
- "version": "8.1.3",
- "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",
- "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "caseless": "^0.12.0",
- "concat-stream": "^1.6.2",
- "http-response-object": "^3.0.1",
- "parse-cache-control": "^1.0.1"
- }
- },
- "http-proxy-agent": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
- "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
- "dev": true,
- "requires": {
- "@tootallnate/once": "2",
- "agent-base": "6",
- "debug": "4"
- }
- },
- "http-response-object": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
- "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@types/node": "^10.0.3"
- },
- "dependencies": {
- "@types/node": {
- "version": "10.17.60",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
- "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==",
- "dev": true,
- "optional": true,
- "peer": true
- }
- }
- },
- "https-proxy-agent": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
- "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
- "dev": true,
- "requires": {
- "agent-base": "6",
- "debug": "4"
- }
- },
- "human-signals": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
- "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
- "dev": true
- },
- "iconv-lite": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dev": true,
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- }
- },
- "idb-keyval": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
- "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
- },
- "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": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
- "dev": true
- },
- "immer": {
- "version": "10.0.3",
- "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz",
- "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A=="
- },
- "import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "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
- },
- "indent-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
- "dev": true
- },
- "individual": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz",
- "integrity": "sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g=="
- },
- "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
- },
- "inquirer": {
- "version": "8.2.5",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz",
- "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==",
- "dev": true,
- "requires": {
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.1.1",
- "cli-cursor": "^3.1.0",
- "cli-width": "^3.0.0",
- "external-editor": "^3.0.3",
- "figures": "^3.0.0",
- "lodash": "^4.17.21",
- "mute-stream": "0.0.8",
- "ora": "^5.4.1",
- "run-async": "^2.4.0",
- "rxjs": "^7.5.5",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0",
- "through": "^2.3.6",
- "wrap-ansi": "^7.0.0"
- },
- "dependencies": {
- "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"
- }
- },
- "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"
- }
- },
- "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
- },
- "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
- },
- "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"
- }
- }
- }
- },
- "internal-slot": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
- "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
- "dev": true,
- "requires": {
- "get-intrinsic": "^1.1.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
- }
- },
- "is-arguments": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
- "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "dev": true,
- "requires": {
- "has-bigints": "^1.0.1"
- }
- },
- "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-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
- "dev": true
- },
- "is-core-module": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
- "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
- "dev": true,
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-docker": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
- "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
- "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-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-function": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
- "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ=="
- },
- "is-generator-function": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
- "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "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-inside-container": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
- "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
- "dev": true,
- "requires": {
- "is-docker": "^3.0.0"
- }
- },
- "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-map": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
- "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
- "dev": true
- },
- "is-negative-zero": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
- "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
- "dev": true
- },
- "is-node-process": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
- "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==",
- "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-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true
- },
- "is-potential-custom-element-name": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
- "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
- "dev": true
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-set": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
- "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
- "dev": true
- },
- "is-shared-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
- "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2"
- }
- },
- "is-stream": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
- "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
- "dev": true
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
- "dev": true,
- "requires": {
- "has-symbols": "^1.0.2"
- }
- },
- "is-typed-array": {
- "version": "1.1.10",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz",
- "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==",
- "dev": true,
- "requires": {
- "available-typed-arrays": "^1.0.5",
- "call-bind": "^1.0.2",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-tostringtag": "^1.0.0"
- }
- },
- "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-weakmap": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
- "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
- "dev": true
- },
- "is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2"
- }
- },
- "is-weakset": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
- "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- }
- },
- "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"
- },
- "dependencies": {
- "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
- }
- }
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "istanbul-lib-coverage": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
- "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
- "dev": true
- },
- "istanbul-lib-report": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
- "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
- "dev": true,
- "requires": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^4.0.0",
- "supports-color": "^7.1.0"
- },
- "dependencies": {
- "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
- },
- "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"
- }
- }
- }
- },
- "istanbul-lib-source-maps": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
- "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
- "dev": true,
- "requires": {
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
- }
- },
- "istanbul-reports": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
- "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
- "dev": true,
- "requires": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- }
- },
- "jest-diff": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
- "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
- "dev": true,
- "requires": {
- "chalk": "^4.0.0",
- "diff-sequences": "^29.6.3",
- "jest-get-type": "^29.6.3",
- "pretty-format": "^29.7.0"
- },
- "dependencies": {
- "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"
- }
- },
- "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"
- }
- },
- "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
- },
- "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
- },
- "pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
- "dev": true,
- "requires": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true
- }
- }
- },
- "react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- },
- "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"
- }
- }
- }
- },
- "jest-get-type": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
- "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
- "dev": true
- },
- "jest-websocket-mock": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.5.0.tgz",
- "integrity": "sha512-a+UJGfowNIWvtIKIQBHoEWIUqRxxQHFx4CXT+R5KxxKBtEQ5rS3pPOV/5299sHzqbmeCzxxY5qE4+yfXePePig==",
- "dev": true,
- "requires": {
- "jest-diff": "^29.2.0",
- "mock-socket": "^9.3.0"
- }
- },
- "jiti": {
- "version": "1.21.0",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
- "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
- "dev": true
- },
- "js-levenshtein": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
- "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
- "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": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "requires": {
- "argparse": "^2.0.1"
- }
- },
- "jsdom": {
- "version": "22.1.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
- "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
- "dev": true,
- "requires": {
- "abab": "^2.0.6",
- "cssstyle": "^3.0.0",
- "data-urls": "^4.0.0",
- "decimal.js": "^10.4.3",
- "domexception": "^4.0.0",
- "form-data": "^4.0.0",
- "html-encoding-sniffer": "^3.0.0",
- "http-proxy-agent": "^5.0.0",
- "https-proxy-agent": "^5.0.1",
- "is-potential-custom-element-name": "^1.0.1",
- "nwsapi": "^2.2.4",
- "parse5": "^7.1.2",
- "rrweb-cssom": "^0.6.0",
- "saxes": "^6.0.0",
- "symbol-tree": "^3.2.4",
- "tough-cookie": "^4.1.2",
- "w3c-xmlserializer": "^4.0.0",
- "webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^2.0.0",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^12.0.1",
- "ws": "^8.13.0",
- "xml-name-validator": "^4.0.0"
- },
- "dependencies": {
- "form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dev": true,
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- }
- },
- "tr46": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
- "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
- "dev": true,
- "requires": {
- "punycode": "^2.3.0"
- }
- },
- "whatwg-url": {
- "version": "12.0.1",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
- "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
- "dev": true,
- "requires": {
- "tr46": "^4.1.1",
- "webidl-conversions": "^7.0.0"
- }
- }
- }
- },
- "jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "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
- },
- "jsonc-parser": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
- "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w=="
- },
- "jsx-ast-utils": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz",
- "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==",
- "dev": true,
- "requires": {
- "array-includes": "^3.1.5",
- "object.assign": "^4.1.3"
- }
- },
- "keycode": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
- "integrity": "sha512-ps3I9jAdNtRpJrbBvQjpzyFbss/skHqzS+eu4RxKLaEAtFqkjZaB6TZMSivPbLxf4K7VI4SjR0P5mRCX5+Q25A=="
- },
- "kolorist": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
- "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
- "dev": true
- },
- "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
- },
- "local-pkg": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
- "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==",
- "dev": true
- },
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "requires": {
- "p-locate": "^5.0.0"
- }
- },
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "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
- },
- "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": {
- "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"
- }
- },
- "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"
- }
- },
- "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
- },
- "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
- },
- "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"
- }
- }
- }
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "loupe": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
- "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
- "dev": true,
- "requires": {
- "get-func-name": "^2.0.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"
- }
- },
- "lz-string": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
- "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==",
- "dev": true
- },
- "m3u8-parser": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-6.2.0.tgz",
- "integrity": "sha512-qlC00JTxYOxawcqg+RB8jbyNwL3foY/nCY61kyWP+RCuJE9APLeqB/nSlTjb4Mg0yRmyERgjswpdQxMvkeoDrg==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.5",
- "global": "^4.4.0"
- },
- "dependencies": {
- "@videojs/vhs-utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
- "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- }
- }
- }
- },
- "magic-string": {
- "version": "0.30.2",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz",
- "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==",
- "dev": true,
- "requires": {
- "@jridgewell/sourcemap-codec": "^1.4.15"
- },
- "dependencies": {
- "@jridgewell/sourcemap-codec": {
- "version": "1.4.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
- "dev": true
- }
- }
- },
- "make-dir": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
- "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
- "dev": true,
- "requires": {
- "semver": "^7.5.3"
- },
- "dependencies": {
- "semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "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
- },
- "micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
- "dev": true,
- "requires": {
- "braces": "^3.0.2",
- "picomatch": "^2.3.1"
- }
- },
- "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
- },
- "min-document": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
- "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==",
- "requires": {
- "dom-walk": "^0.1.0"
- }
- },
- "min-indent": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
- "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
- "dev": true
- },
- "mini-svg-data-uri": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
- "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
- "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"
- }
- },
- "mlly": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz",
- "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==",
- "dev": true,
- "requires": {
- "acorn": "^8.10.0",
- "pathe": "^1.1.1",
- "pkg-types": "^1.0.3",
- "ufo": "^1.3.0"
- }
- },
- "mock-socket": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz",
- "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==",
- "dev": true
- },
- "monaco-editor": {
- "version": "0.34.1",
- "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.34.1.tgz",
- "integrity": "sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ==",
- "peer": true
- },
- "monaco-marker-data-provider": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/monaco-marker-data-provider/-/monaco-marker-data-provider-1.1.1.tgz",
- "integrity": "sha512-PGB7TJSZE5tmHzkxv/OEwK2RGNC2A7dcq4JRJnnj31CUAsfmw0Gl+1QTrH0W0deKhcQmQM0YVPaqgQ+0wCt8Mg==",
- "requires": {}
- },
- "monaco-worker-manager": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/monaco-worker-manager/-/monaco-worker-manager-2.0.1.tgz",
- "integrity": "sha512-kdPL0yvg5qjhKPNVjJoym331PY/5JC11aPJXtCZNwWRvBr6jhkIamvYAyiY5P1AWFmNOy0aRDRoMdZfa71h8kg==",
- "requires": {}
- },
- "monaco-yaml": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/monaco-yaml/-/monaco-yaml-4.0.4.tgz",
- "integrity": "sha512-qbM36fY1twpDUs4lhhxoXDQGUPVyYAFCPJi3E0JKgLioD8wzsD/pawgauFFXSzpMa09z8wbt/DTLXjXEehnVFA==",
- "requires": {
- "@types/json-schema": "^7.0.0",
- "jsonc-parser": "^3.0.0",
- "monaco-marker-data-provider": "^1.0.0",
- "monaco-worker-manager": "^2.0.0",
- "path-browserify": "^1.0.0",
- "prettier": "^2.0.0",
- "vscode-languageserver-textdocument": "^1.0.0",
- "vscode-languageserver-types": "^3.0.0",
- "vscode-uri": "^3.0.0",
- "yaml": "^2.0.0"
- },
- "dependencies": {
- "prettier": {
- "version": "2.8.8",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
- "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="
- }
- }
- },
- "mpd-parser": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.2.2.tgz",
- "integrity": "sha512-QCfB1koOoZw6E5La1cx+W/Yd0EZlRhHMqMr4TAJez0eRTuPDzPM5FWoiOqjyo37W+ISPLzmfJACSbJFEBjbL4Q==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/vhs-utils": "^3.0.5",
- "@xmldom/xmldom": "^0.8.3",
- "global": "^4.4.0"
- },
- "dependencies": {
- "@videojs/vhs-utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
- "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "global": "^4.4.0",
- "url-toolkit": "^2.2.1"
- }
- }
- }
- },
- "mrmime": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
- "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
- "dev": true
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "msw": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/msw/-/msw-1.3.2.tgz",
- "integrity": "sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA==",
- "dev": true,
- "requires": {
- "@mswjs/cookies": "^0.2.2",
- "@mswjs/interceptors": "^0.17.10",
- "@open-draft/until": "^1.0.3",
- "@types/cookie": "^0.4.1",
- "@types/js-levenshtein": "^1.1.1",
- "chalk": "^4.1.1",
- "chokidar": "^3.4.2",
- "cookie": "^0.4.2",
- "graphql": "^16.8.1",
- "headers-polyfill": "3.2.5",
- "inquirer": "^8.2.0",
- "is-node-process": "^1.2.0",
- "js-levenshtein": "^1.1.6",
- "node-fetch": "^2.6.7",
- "outvariant": "^1.4.0",
- "path-to-regexp": "^6.2.0",
- "strict-event-emitter": "^0.4.3",
- "type-fest": "^2.19.0",
- "yargs": "^17.3.1"
- },
- "dependencies": {
- "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"
- }
- },
- "chalk": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
- "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.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
- },
- "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
- },
- "strict-event-emitter": {
- "version": "0.4.6",
- "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz",
- "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==",
- "dev": true
- },
- "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"
- }
- }
- }
- },
- "mute-stream": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
- "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
- "dev": true
- },
- "mux.js": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-7.0.1.tgz",
- "integrity": "sha512-Omz79uHqYpMP1V80JlvEdCiOW1hiw4mBvDh9gaZEpxvB+7WYb2soZSzfuSRrK2Kh9Pm6eugQNrIpY/Bnyhk4hw==",
- "requires": {
- "@babel/runtime": "^7.11.2",
- "global": "^4.4.0"
- }
- },
- "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.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
- "dev": true
- },
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
- "natural-compare-lite": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
- "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "dev": true,
- "requires": {
- "whatwg-url": "^5.0.0"
- }
- },
- "node-releases": {
- "version": "2.0.13",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
- "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
- "dev": true
- },
- "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
- },
- "npm-run-path": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
- "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
- "dev": true,
- "requires": {
- "path-key": "^4.0.0"
- },
- "dependencies": {
- "path-key": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
- "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
- "dev": true
- }
- }
- },
- "nwsapi": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.4.tgz",
- "integrity": "sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g==",
- "dev": true
- },
- "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-hash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
- "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
- "dev": true
- },
- "object-inspect": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
- "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
- "dev": true
- },
- "object-is": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
- "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
- }
- },
- "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.4",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
- "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "has-symbols": "^1.0.3",
- "object-keys": "^1.1.1"
- }
- },
- "object.entries": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz",
- "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- }
- },
- "object.fromentries": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz",
- "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- }
- },
- "object.hasown": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz",
- "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==",
- "dev": true,
- "requires": {
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- }
- },
- "object.values": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz",
- "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- }
- },
- "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": "9.1.0",
- "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz",
- "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==",
- "dev": true,
- "requires": {
- "default-browser": "^4.0.0",
- "define-lazy-prop": "^3.0.0",
- "is-inside-container": "^1.0.0",
- "is-wsl": "^2.2.0"
- }
- },
- "optionator": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
- "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
- "dev": true,
- "requires": {
- "@aashutoshrathi/word-wrap": "^1.2.3",
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0"
- }
- },
- "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": {
- "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"
- }
- },
- "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"
- }
- },
- "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
- },
- "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
- },
- "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"
- }
- }
- }
- },
- "os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
- "dev": true
- },
- "outvariant": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz",
- "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==",
- "dev": true
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "requires": {
- "p-limit": "^3.0.2"
- }
- },
- "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-cache-control": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
- "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "parse5": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
- "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
- "dev": true,
- "requires": {
- "entities": "^4.4.0"
- }
- },
- "path-browserify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
- "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
- },
- "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": "6.2.1",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
- "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==",
- "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
- },
- "pathe": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz",
- "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==",
- "dev": true
- },
- "pathval": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
- "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
- "dev": true
- },
- "picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
- },
- "picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true
- },
- "pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
- "dev": true
- },
- "pirates": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
- "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
- "dev": true
- },
- "pkcs7": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz",
- "integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==",
- "requires": {
- "@babel/runtime": "^7.5.5"
- }
- },
- "pkg-types": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
- "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==",
- "dev": true,
- "requires": {
- "jsonc-parser": "^3.2.0",
- "mlly": "^1.2.0",
- "pathe": "^1.1.0"
- }
- },
- "postcss": {
- "version": "8.4.32",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
- "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
- "dev": true,
- "requires": {
- "nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- }
- },
- "postcss-import": {
- "version": "15.1.0",
- "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
- "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
- "dev": true,
- "requires": {
- "postcss-value-parser": "^4.0.0",
- "read-cache": "^1.0.0",
- "resolve": "^1.1.7"
- }
- },
- "postcss-js": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
- "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
- "dev": true,
- "requires": {
- "camelcase-css": "^2.0.1"
- }
- },
- "postcss-load-config": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
- "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
- "dev": true,
- "requires": {
- "lilconfig": "^2.0.5",
- "yaml": "^2.1.1"
- }
- },
- "postcss-nested": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
- "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
- "dev": true,
- "requires": {
- "postcss-selector-parser": "^6.0.11"
- }
- },
- "postcss-selector-parser": {
- "version": "6.0.11",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
- "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
- "dev": true,
- "requires": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- }
- },
- "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
- },
- "preact": {
- "version": "10.19.2",
- "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.2.tgz",
- "integrity": "sha512-UA9DX/OJwv6YwP9Vn7Ti/vF80XL+YA5H2l7BpCtUr3ya8LWHFzpiO5R+N7dN16ujpIxhekRFuOOF82bXX7K/lg=="
- },
- "preact-async-route": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/preact-async-route/-/preact-async-route-2.2.1.tgz",
- "integrity": "sha512-8bg1007akXs3YDmzYT4McaTe6ji2FIzcc0/NTlu+vjJaKPNQ8lNG/HQ6LP+FoIxQ4m/KH5vvJCHJN5ADp2iNGA=="
- },
- "preact-router": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/preact-router/-/preact-router-4.1.2.tgz",
- "integrity": "sha512-uICUaUFYh+XQ+6vZtQn1q+X6rSqwq+zorWOCLWPF5FAsQh3EJ+RsDQ9Ee+fjk545YWQHfUxhrBAaemfxEnMOUg==",
- "requires": {}
- },
- "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": "3.1.0",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
- "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
- "dev": true
- },
- "prettier-linter-helpers": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
- "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
- "dev": true,
- "requires": {
- "fast-diff": "^1.1.2"
- }
- },
- "pretty-format": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
- "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1",
- "ansi-styles": "^5.0.0",
- "react-is": "^17.0.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true
- },
- "react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "dev": true
- }
- }
- },
- "process": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
- "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="
- },
- "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,
- "optional": true,
- "peer": true
- },
- "promise": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
- "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "asap": "~2.0.6"
- }
- },
- "prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
- "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=="
- },
- "psl": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
- "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
- "dev": true
- },
- "punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "dev": true
- },
- "qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "side-channel": "^1.0.4"
- }
- },
- "querystringify": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
- "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
- "dev": true
- },
- "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
- },
- "react": {
- "version": "npm:@preact/compat@17.1.2",
- "resolved": "https://registry.npmjs.org/@preact/compat/-/compat-17.1.2.tgz",
- "integrity": "sha512-7pOZN9lMDDRQ+6aWvjwTp483KR8/zOpfS83wmOo3zfuLKdngS8/5RLbsFWzFZMGdYlotAhX980hJ75bjOHTwWg==",
- "requires": {}
- },
- "react-dom": {
- "version": "npm:@preact/compat@17.1.2",
- "resolved": "https://registry.npmjs.org/@preact/compat/-/compat-17.1.2.tgz",
- "integrity": "sha512-7pOZN9lMDDRQ+6aWvjwTp483KR8/zOpfS83wmOo3zfuLKdngS8/5RLbsFWzFZMGdYlotAhX980hJ75bjOHTwWg==",
- "requires": {}
- },
- "react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
- },
- "react-use-websocket": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-3.0.0.tgz",
- "integrity": "sha512-BInlbhXYrODBPKIplDAmI0J1VPM+1KhCLN09o+dzgQ8qMyrYs4t5kEYmCrTqyRuMTmpahylHFZWQXpfYyDkqOw==",
- "requires": {}
- },
- "read-cache": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
- "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
- "dev": true,
- "requires": {
- "pify": "^2.3.0"
- }
- },
- "readable-stream": {
- "version": "2.3.7",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
- "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "dev": true,
- "optional": true,
- "peer": 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"
- }
- },
- "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"
- }
- },
- "realistic-structured-clone": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/realistic-structured-clone/-/realistic-structured-clone-3.0.0.tgz",
- "integrity": "sha512-rOjh4nuWkAqf9PWu6JVpOWD4ndI+JHfgiZeMmujYcPi+fvILUu7g6l26TC1K5aBIp34nV+jE1cDO75EKOfHC5Q==",
- "dev": true,
- "requires": {
- "domexception": "^1.0.1",
- "typeson": "^6.1.0",
- "typeson-registry": "^1.0.0-alpha.20"
- },
- "dependencies": {
- "domexception": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
- "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
- "dev": true,
- "requires": {
- "webidl-conversions": "^4.0.2"
- }
- },
- "webidl-conversions": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
- "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
- "dev": true
- }
- }
- },
- "redent": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
- "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
- "dev": true,
- "requires": {
- "indent-string": "^4.0.0",
- "strip-indent": "^3.0.0"
- }
- },
- "regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
- },
- "regexp.prototype.flags": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
- "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "functions-have-names": "^1.2.2"
- }
- },
- "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
- },
- "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.8",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
- "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
- "dev": true,
- "requires": {
- "is-core-module": "^2.13.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"
- }
- },
- "reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "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"
- }
- },
- "rollup": {
- "version": "3.27.2",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.27.2.tgz",
- "integrity": "sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==",
- "dev": true,
- "requires": {
- "fsevents": "~2.3.2"
- }
- },
- "rrweb-cssom": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
- "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==",
- "dev": true
- },
- "run-applescript": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz",
- "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==",
- "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"
- }
- },
- "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
- },
- "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"
- }
- },
- "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
- }
- }
- },
- "run-async": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
- "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
- "dev": true
- },
- "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"
- }
- },
- "rust-result": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz",
- "integrity": "sha512-6cJzSBU+J/RJCF063onnQf0cDUOHs9uZI1oroSGnHOph+CQTIJ5Pp2hK5kEQq1+7yE/EEWfulSNXAQ2jikPthA==",
- "requires": {
- "individual": "^2.0.0"
- }
- },
- "rxjs": {
- "version": "7.5.7",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz",
- "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==",
- "dev": true,
- "requires": {
- "tslib": "^2.1.0"
- }
- },
- "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
- },
- "safe-json-parse": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz",
- "integrity": "sha512-RjZPPHugjK0TOzFrLZ8inw44s9bKox99/0AZW9o/BEQVrJfhI+fIHMErnPyRa89/yRXUUr93q+tiN6zhoVV4wQ==",
- "requires": {
- "rust-result": "^1.0.0"
- }
- },
- "safe-regex-test": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
- "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "is-regex": "^1.1.4"
- }
- },
- "safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
- },
- "saxes": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
- "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
- "dev": true,
- "requires": {
- "xmlchars": "^2.2.0"
- }
- },
- "semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true
- },
- "set-cookie-parser": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz",
- "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==",
- "dev": true
- },
- "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
- },
- "side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- }
- },
- "siginfo": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
- "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
- "dev": true
- },
- "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.3",
- "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz",
- "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==",
- "dev": true,
- "requires": {
- "@polka/url": "^1.0.0-next.20",
- "mrmime": "^1.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
- },
- "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.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true
- },
- "stackback": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
- "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
- "dev": true
- },
- "std-env": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.3.tgz",
- "integrity": "sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==",
- "dev": true
- },
- "strftime": {
- "version": "0.10.2",
- "resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.2.tgz",
- "integrity": "sha512-Y6IZaTVM80chcMe7j65Gl/0nmlNdtt+KWPle5YeCAjmsBfw+id2qdaJ5MDrxUq+OmHKab+jHe7mUjU/aNMSZZg=="
- },
- "strict-event-emitter": {
- "version": "0.2.8",
- "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz",
- "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==",
- "dev": true,
- "requires": {
- "events": "^3.3.0"
- }
- },
- "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"
- }
- },
- "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"
- }
- },
- "string.prototype.matchall": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz",
- "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "get-intrinsic": "^1.1.3",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "regexp.prototype.flags": "^1.4.3",
- "side-channel": "^1.0.4"
- }
- },
- "string.prototype.trimend": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
- "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- }
- },
- "string.prototype.trimstart": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz",
- "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- }
- },
- "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-final-newline": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
- "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
- "dev": true
- },
- "strip-indent": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
- "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
- "dev": true,
- "requires": {
- "min-indent": "^1.0.0"
- }
- },
- "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
- },
- "strip-literal": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz",
- "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==",
- "dev": true,
- "requires": {
- "acorn": "^8.8.2"
- }
- },
- "sucrase": {
- "version": "3.32.0",
- "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
- "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==",
- "dev": true,
- "requires": {
- "@jridgewell/gen-mapping": "^0.3.2",
- "commander": "^4.0.0",
- "glob": "7.1.6",
- "lines-and-columns": "^1.1.6",
- "mz": "^2.7.0",
- "pirates": "^4.0.1",
- "ts-interface-checker": "^0.1.9"
- },
- "dependencies": {
- "glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- }
- }
- },
- "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"
- }
- },
- "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
- },
- "swr": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/swr/-/swr-1.3.0.tgz",
- "integrity": "sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==",
- "requires": {}
- },
- "symbol-tree": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
- "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
- "dev": true
- },
- "sync-request": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz",
- "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "http-response-object": "^3.0.1",
- "sync-rpc": "^1.2.1",
- "then-request": "^6.0.0"
- }
- },
- "sync-rpc": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz",
- "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "get-port": "^3.1.0"
- }
- },
- "synckit": {
- "version": "0.8.5",
- "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
- "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==",
- "dev": true,
- "requires": {
- "@pkgr/utils": "^2.3.1",
- "tslib": "^2.5.0"
- }
- },
- "tailwindcss": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.6.tgz",
- "integrity": "sha512-AKjF7qbbLvLaPieoKeTjG1+FyNZT6KaJMJPFeQyLfIp7l82ggH1fbHJSsYIvnbTFQOlkh+gBYpyby5GT1LIdLw==",
- "dev": true,
- "requires": {
- "@alloc/quick-lru": "^5.2.0",
- "arg": "^5.0.2",
- "chokidar": "^3.5.3",
- "didyoumean": "^1.2.2",
- "dlv": "^1.1.3",
- "fast-glob": "^3.3.0",
- "glob-parent": "^6.0.2",
- "is-glob": "^4.0.3",
- "jiti": "^1.19.1",
- "lilconfig": "^2.1.0",
- "micromatch": "^4.0.5",
- "normalize-path": "^3.0.0",
- "object-hash": "^3.0.0",
- "picocolors": "^1.0.0",
- "postcss": "^8.4.23",
- "postcss-import": "^15.1.0",
- "postcss-js": "^4.0.1",
- "postcss-load-config": "^4.0.1",
- "postcss-nested": "^6.0.1",
- "postcss-selector-parser": "^6.0.11",
- "resolve": "^1.22.2",
- "sucrase": "^3.32.0"
- }
- },
- "test-exclude": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
- "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
- "dev": true,
- "requires": {
- "@istanbuljs/schema": "^0.1.2",
- "glob": "^7.1.4",
- "minimatch": "^3.0.4"
- }
- },
- "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
- },
- "then-request": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz",
- "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==",
- "dev": true,
- "optional": true,
- "peer": true,
- "requires": {
- "@types/concat-stream": "^1.6.0",
- "@types/form-data": "0.0.33",
- "@types/node": "^8.0.0",
- "@types/qs": "^6.2.31",
- "caseless": "~0.12.0",
- "concat-stream": "^1.6.0",
- "form-data": "^2.2.0",
- "http-basic": "^8.1.1",
- "http-response-object": "^3.0.1",
- "promise": "^8.0.0",
- "qs": "^6.4.0"
- },
- "dependencies": {
- "@types/node": {
- "version": "8.10.66",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz",
- "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==",
- "dev": true,
- "optional": true,
- "peer": 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"
- }
- },
- "through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
- "dev": true
- },
- "tinybench": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz",
- "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==",
- "dev": true
- },
- "tinypool": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz",
- "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==",
- "dev": true
- },
- "tinyspy": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz",
- "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==",
- "dev": true
- },
- "titleize": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz",
- "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==",
- "dev": true
- },
- "tmp": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
- "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
- "dev": true,
- "requires": {
- "os-tmpdir": "~1.0.2"
- }
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "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"
- }
- },
- "toggle-selection": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
- "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
- },
- "totalist": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
- "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
- "dev": true
- },
- "tough-cookie": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
- "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
- "dev": true,
- "requires": {
- "psl": "^1.1.33",
- "punycode": "^2.1.1",
- "universalify": "^0.2.0",
- "url-parse": "^1.5.3"
- }
- },
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
- "dev": true
- },
- "ts-api-utils": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz",
- "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==",
- "dev": true,
- "requires": {}
- },
- "ts-interface-checker": {
- "version": "0.1.13",
- "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
- "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
- "dev": true
- },
- "tslib": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
- "dev": true
- },
- "tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dev": true,
- "requires": {
- "tslib": "^1.8.1"
- },
- "dependencies": {
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- }
- }
- },
- "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-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
- "dev": true
- },
- "type-fest": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
- "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
- "dev": true
- },
- "typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "typescript": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
- "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
- "dev": true
- },
- "typeson": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/typeson/-/typeson-6.1.0.tgz",
- "integrity": "sha512-6FTtyGr8ldU0pfbvW/eOZrEtEkczHRUtduBnA90Jh9kMPCiFNnXIon3vF41N0S4tV1HHQt4Hk1j4srpESziCaA==",
- "dev": true
- },
- "typeson-registry": {
- "version": "1.0.0-alpha.39",
- "resolved": "https://registry.npmjs.org/typeson-registry/-/typeson-registry-1.0.0-alpha.39.tgz",
- "integrity": "sha512-NeGDEquhw+yfwNhguLPcZ9Oj0fzbADiX4R0WxvoY8nGhy98IbzQy1sezjoEFWOywOboj/DWehI+/aUlRVrJnnw==",
- "dev": true,
- "requires": {
- "base64-arraybuffer-es6": "^0.7.0",
- "typeson": "^6.0.0",
- "whatwg-url": "^8.4.0"
- },
- "dependencies": {
- "tr46": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz",
- "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.1"
- }
- },
- "webidl-conversions": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
- "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
- "dev": true
- },
- "whatwg-url": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz",
- "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==",
- "dev": true,
- "requires": {
- "lodash": "^4.7.0",
- "tr46": "^2.1.0",
- "webidl-conversions": "^6.1.0"
- }
- }
- }
- },
- "ufo": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz",
- "integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==",
- "dev": true
- },
- "unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- }
- },
- "universalify": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
- "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
- "dev": true
- },
- "untildify": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
- "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
- "dev": true
- },
- "update-browserslist-db": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
- "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
- "dev": true,
- "requires": {
- "escalade": "^3.1.1",
- "picocolors": "^1.0.0"
- }
- },
- "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"
- }
- },
- "url-parse": {
- "version": "1.5.10",
- "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
- "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
- "dev": true,
- "requires": {
- "querystringify": "^2.1.1",
- "requires-port": "^1.0.0"
- }
- },
- "url-toolkit": {
- "version": "2.2.5",
- "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.5.tgz",
- "integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg=="
- },
- "util": {
- "version": "0.12.5",
- "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
- "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "is-arguments": "^1.0.4",
- "is-generator-function": "^1.0.7",
- "is-typed-array": "^1.1.3",
- "which-typed-array": "^1.1.2"
- }
- },
- "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
- },
- "v8-to-istanbul": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz",
- "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==",
- "dev": true,
- "requires": {
- "@jridgewell/trace-mapping": "^0.3.12",
- "@types/istanbul-lib-coverage": "^2.0.1",
- "convert-source-map": "^1.6.0"
- }
- },
- "video.js": {
- "version": "8.6.1",
- "resolved": "https://registry.npmjs.org/video.js/-/video.js-8.6.1.tgz",
- "integrity": "sha512-CNYVJ5WWIZ7bOhbkkfcKqLGoc6WsE3Ft2RfS1lXdQTWk8UiSsPW2Ssk2JzPCA8qnIlUG9os/faCFsYWjyu4JcA==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@videojs/http-streaming": "3.7.0",
- "@videojs/vhs-utils": "^4.0.0",
- "@videojs/xhr": "2.6.0",
- "aes-decrypter": "^4.0.1",
- "global": "4.4.0",
- "keycode": "2.2.0",
- "m3u8-parser": "^6.0.0",
- "mpd-parser": "^1.0.1",
- "mux.js": "^7.0.1",
- "safe-json-parse": "4.0.0",
- "videojs-contrib-quality-levels": "4.0.0",
- "videojs-font": "4.1.0",
- "videojs-vtt.js": "0.15.5"
- }
- },
- "videojs-contrib-quality-levels": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.0.0.tgz",
- "integrity": "sha512-u5rmd8BjLwANp7XwuQ0Q/me34bMe6zg9PQdHfTS7aXgiVRbNTb4djcmfG7aeSrkpZjg+XCLezFNenlJaCjBHKw==",
- "requires": {
- "global": "^4.4.0"
- }
- },
- "videojs-font": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-4.1.0.tgz",
- "integrity": "sha512-X1LuPfLZPisPLrANIAKCknZbZu5obVM/ylfd1CN+SsCmPZQ3UMDPcvLTpPBJxcBuTpHQq2MO1QCFt7p8spnZ/w=="
- },
- "videojs-playlist": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/videojs-playlist/-/videojs-playlist-5.1.0.tgz",
- "integrity": "sha512-p5ohld6Kom9meYCcEVYj0JVS2MBL2XxMiU+IDB/xKpDOspFAHrERHrZEBoiJZc/mCfHixZBNgj1vWRgYsVVsrw==",
- "requires": {
- "global": "^4.3.2",
- "video.js": "^6 || ^7 || ^8"
- }
- },
- "videojs-vtt.js": {
- "version": "0.15.5",
- "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.5.tgz",
- "integrity": "sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==",
- "requires": {
- "global": "^4.3.1"
- }
- },
- "vite": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
- "integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
- "dev": true,
- "requires": {
- "esbuild": "^0.18.10",
- "fsevents": "~2.3.2",
- "postcss": "^8.4.27",
- "rollup": "^3.27.1"
- }
- },
- "vite-node": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz",
- "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==",
- "dev": true,
- "requires": {
- "cac": "^6.7.14",
- "debug": "^4.3.4",
- "mlly": "^1.4.0",
- "pathe": "^1.1.1",
- "picocolors": "^1.0.0",
- "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0"
- }
- },
- "vite-plugin-monaco-editor": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/vite-plugin-monaco-editor/-/vite-plugin-monaco-editor-1.1.0.tgz",
- "integrity": "sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==",
- "requires": {}
- },
- "vitest": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz",
- "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==",
- "dev": true,
- "requires": {
- "@types/chai": "^4.3.5",
- "@types/chai-subset": "^1.3.3",
- "@types/node": "*",
- "@vitest/expect": "0.34.6",
- "@vitest/runner": "0.34.6",
- "@vitest/snapshot": "0.34.6",
- "@vitest/spy": "0.34.6",
- "@vitest/utils": "0.34.6",
- "acorn": "^8.9.0",
- "acorn-walk": "^8.2.0",
- "cac": "^6.7.14",
- "chai": "^4.3.10",
- "debug": "^4.3.4",
- "local-pkg": "^0.4.3",
- "magic-string": "^0.30.1",
- "pathe": "^1.1.1",
- "picocolors": "^1.0.0",
- "std-env": "^3.3.3",
- "strip-literal": "^1.0.1",
- "tinybench": "^2.5.0",
- "tinypool": "^0.7.0",
- "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0",
- "vite-node": "0.34.6",
- "why-is-node-running": "^2.2.2"
- }
- },
- "vscode-languageserver-textdocument": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz",
- "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg=="
- },
- "vscode-languageserver-types": {
- "version": "3.17.2",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
- "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
- },
- "vscode-uri": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz",
- "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ=="
- },
- "w3c-xmlserializer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
- "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
- "dev": true,
- "requires": {
- "xml-name-validator": "^4.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"
- }
- },
- "web-encoding": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz",
- "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==",
- "dev": true,
- "requires": {
- "@zxing/text-encoding": "0.9.0",
- "util": "^0.12.3"
- }
- },
- "webidl-conversions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
- "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
- "dev": true
- },
- "whatwg-encoding": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
- "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
- "dev": true,
- "requires": {
- "iconv-lite": "0.6.3"
- }
- },
- "whatwg-mimetype": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
- "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
- "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"
- },
- "dependencies": {
- "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
- }
- }
- },
- "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"
- }
- },
- "which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "dev": true,
- "requires": {
- "is-bigint": "^1.0.1",
- "is-boolean-object": "^1.1.0",
- "is-number-object": "^1.0.4",
- "is-string": "^1.0.5",
- "is-symbol": "^1.0.3"
- }
- },
- "which-collection": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
- "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
- "dev": true,
- "requires": {
- "is-map": "^2.0.1",
- "is-set": "^2.0.1",
- "is-weakmap": "^2.0.1",
- "is-weakset": "^2.0.1"
- }
- },
- "which-typed-array": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
- "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==",
- "dev": true,
- "requires": {
- "available-typed-arrays": "^1.0.5",
- "call-bind": "^1.0.2",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-tostringtag": "^1.0.0",
- "is-typed-array": "^1.1.10"
- }
- },
- "why-is-node-running": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz",
- "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==",
- "dev": true,
- "requires": {
- "siginfo": "^2.0.0",
- "stackback": "0.0.2"
- }
- },
- "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"
- },
- "dependencies": {
- "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"
- }
- },
- "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
- }
- }
- },
- "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": "8.13.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
- "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
- "dev": true,
- "requires": {}
- },
- "xml-name-validator": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
- "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
- "dev": true
- },
- "xmlchars": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
- "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
- "dev": true
- },
- "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": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "yaml": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
- "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA=="
- },
- "yargs": {
- "version": "17.6.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz",
- "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==",
- "dev": true,
- "requires": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- }
- },
- "yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true
- },
- "yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true
- }
- }
-}
diff --git a/web-old/package.json b/web-old/package.json
deleted file mode 100644
index 8d84fd664..000000000
--- a/web-old/package.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- "name": "frigate",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite --host",
- "build": "tsc && vite build --base=/BASE_PATH/",
- "lint": "eslint --ext .jsx,.js,.tsx,.ts --ignore-path .gitignore .",
- "prettier:write": "prettier -u -w --ignore-path .gitignore \"*.{ts,tsx,js,jsx,css,html}\"",
- "test": "vitest",
- "coverage": "vitest run --coverage"
- },
- "dependencies": {
- "@cycjimmy/jsmpeg-player": "^6.0.5",
- "axios": "^1.5.0",
- "copy-to-clipboard": "3.3.3",
- "date-fns": "^2.30.0",
- "idb-keyval": "^6.2.0",
- "immer": "^10.0.1",
- "monaco-yaml": "^4.0.4",
- "preact": "^10.17.1",
- "preact-async-route": "^2.2.1",
- "preact-router": "^4.1.0",
- "react": "npm:@preact/compat@^17.1.2",
- "react-dom": "npm:@preact/compat@^17.1.2",
- "react-use-websocket": "^3.0.0",
- "strftime": "^0.10.1",
- "swr": "^1.3.0",
- "video.js": "^8.5.2",
- "videojs-playlist": "^5.1.0",
- "vite-plugin-monaco-editor": "^1.1.0"
- },
- "devDependencies": {
- "@preact/preset-vite": "^2.5.0",
- "@tailwindcss/forms": "^0.5.6",
- "@testing-library/jest-dom": "^6.1.2",
- "@testing-library/preact": "^3.2.3",
- "@testing-library/user-event": "^14.4.3",
- "@typescript-eslint/eslint-plugin": "^6.5.0",
- "@typescript-eslint/parser": "^6.5.0",
- "@vitest/coverage-v8": "^0.34.3",
- "@vitest/ui": "^0.34.3",
- "autoprefixer": "^10.4.15",
- "eslint": "^8.48.0",
- "eslint-config-preact": "^1.3.0",
- "eslint-config-prettier": "^9.0.0",
- "eslint-plugin-jest": "^27.2.3",
- "eslint-plugin-prettier": "^5.0.0",
- "eslint-plugin-vitest-globals": "^1.4.0",
- "fake-indexeddb": "^4.0.1",
- "jest-websocket-mock": "^2.5.0",
- "jsdom": "^22.0.0",
- "msw": "^1.2.1",
- "postcss": "^8.4.29",
- "prettier": "^3.0.3",
- "tailwindcss": "^3.3.2",
- "typescript": "^5.2.2",
- "vite": "^4.4.9",
- "vitest": "^0.34.3"
- }
-}
diff --git a/web-old/postcss.config.cjs b/web-old/postcss.config.cjs
deleted file mode 100644
index 33ad091d2..000000000
--- a/web-old/postcss.config.cjs
+++ /dev/null
@@ -1,6 +0,0 @@
-module.exports = {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
-}
diff --git a/web-old/public/icons/android-chrome-192x192.png b/web-old/public/icons/android-chrome-192x192.png
deleted file mode 100644
index d60b6346d..000000000
Binary files a/web-old/public/icons/android-chrome-192x192.png and /dev/null differ
diff --git a/web-old/public/icons/android-chrome-512x512.png b/web-old/public/icons/android-chrome-512x512.png
deleted file mode 100644
index b2bdfdae9..000000000
Binary files a/web-old/public/icons/android-chrome-512x512.png and /dev/null differ
diff --git a/web-old/site.webmanifest b/web-old/site.webmanifest
deleted file mode 100644
index 1f44b8456..000000000
--- a/web-old/site.webmanifest
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "Frigate",
- "short_name": "Frigate",
- "icons": [
- {
- "src": "/icons/android-chrome-192x192.png",
- "sizes": "192x192",
- "type": "image/png"
- },
- {
- "src": "/icons/android-chrome-512x512.png",
- "sizes": "512x512",
- "type": "image/png"
- }
- ],
- "theme_color": "#ffffff",
- "background_color": "#ffffff",
- "display": "standalone"
-}
diff --git a/web-old/src/AppBar.jsx b/web-old/src/AppBar.jsx
deleted file mode 100644
index 7cc8887a7..000000000
--- a/web-old/src/AppBar.jsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import { h, Fragment } from 'preact';
-import BaseAppBar from './components/AppBar';
-import LinkedLogo from './components/LinkedLogo';
-import Menu, { MenuItem, MenuSeparator } from './components/Menu';
-import AutoAwesomeIcon from './icons/AutoAwesome';
-import LightModeIcon from './icons/LightMode';
-import DarkModeIcon from './icons/DarkMode';
-import FrigateRestartIcon from './icons/FrigateRestart';
-import Prompt from './components/Prompt';
-import { useDarkMode } from './context';
-import { useCallback, useRef, useState } from 'preact/hooks';
-import { useRestart } from './api/ws';
-
-export default function AppBar() {
- const [showMoreMenu, setShowMoreMenu] = useState(false);
- const [showDialog, setShowDialog] = useState(false);
- const [showDialogWait, setShowDialogWait] = useState(false);
- const { setDarkMode } = useDarkMode();
- const { send: sendRestart } = useRestart();
-
- const handleSelectDarkMode = useCallback(
- (value) => {
- setDarkMode(value);
- setShowMoreMenu(false);
- },
- [setDarkMode, setShowMoreMenu]
- );
-
- const moreRef = useRef(null);
-
- const handleShowMenu = useCallback(() => {
- setShowMoreMenu(true);
- }, [setShowMoreMenu]);
-
- const handleDismissMoreMenu = useCallback(() => {
- setShowMoreMenu(false);
- }, [setShowMoreMenu]);
-
- const handleClickRestartDialog = useCallback(() => {
- setShowDialog(false);
- setShowDialogWait(true);
- sendRestart();
- }, [setShowDialog, sendRestart]);
-
- const handleDismissRestartDialog = useCallback(() => {
- setShowDialog(false);
- }, [setShowDialog]);
-
- const handleRestart = useCallback(() => {
- setShowMoreMenu(false);
- setShowDialog(true);
- }, [setShowDialog]);
-
- return (
-
-
- {showMoreMenu ? (
-
-
-
-
-
-
-
-
- ) : null}
- {showDialog ? (
-
- ) : null}
- {showDialogWait ? (
-
- ) : null}
-
- );
-}
diff --git a/web-old/src/Sidebar.jsx b/web-old/src/Sidebar.jsx
deleted file mode 100644
index 96bd5c52a..000000000
--- a/web-old/src/Sidebar.jsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import { h, Fragment } from 'preact';
-import LinkedLogo from './components/LinkedLogo';
-import { Match } from 'preact-router/match';
-import { memo } from 'preact/compat';
-import { ENV } from './env';
-import { useMemo } from 'preact/hooks'
-import useSWR from 'swr';
-import NavigationDrawer, { Destination, Separator } from './components/NavigationDrawer';
-
-export default function Sidebar() {
- const { data: config } = useSWR('config');
-
- const sortedCameras = useMemo(() => {
- if (!config) {
- return [];
- }
-
- return Object.entries(config.cameras)
- .filter(([_, conf]) => conf.ui.dashboard)
- .sort(([_, aConf], [__, bConf]) => aConf.ui.order - bConf.ui.order);
- }, [config]);
-
- if (!config) {
- return null;
- }
- const { birdseye } = config;
-
- return (
- }>
-
-
- {({ matches }) =>
- matches ? (
-
- ) : null
- }
-
-
- {({ matches }) =>
- matches ? (
-
- ) : null
- }
-
- {birdseye?.enabled ? : null}
-
-
-
-
-
-
-
-
-
- {ENV !== 'production' ? (
-
-
-
-
- ) : null}
-
-
-
- );
-}
-
-function CameraSection({ sortedCameras }) {
-
- return (
-
-
-
- {sortedCameras.map(([camera]) => (
-
- ))}
-
-
-
- );
-}
-
-function RecordingSection({ sortedCameras }) {
-
- return (
-
-
-
- {sortedCameras.map(([camera, _]) => {
- return (
-
- );
- })}
-
-
-
- );
-}
-
-const Header = memo(() => {
- return (
-
-
-
- );
-});
\ No newline at end of file
diff --git a/web-old/src/__mocks__/env.js b/web-old/src/__mocks__/env.js
deleted file mode 100644
index b99dd5560..000000000
--- a/web-old/src/__mocks__/env.js
+++ /dev/null
@@ -1 +0,0 @@
-export const ENV = 'test';
diff --git a/web-old/src/__mocks__/styleMock.js b/web-old/src/__mocks__/styleMock.js
deleted file mode 100644
index a09954537..000000000
--- a/web-old/src/__mocks__/styleMock.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = {};
\ No newline at end of file
diff --git a/web-old/src/__tests__/App.test.jsx b/web-old/src/__tests__/App.test.jsx
deleted file mode 100644
index 0ef3c58ea..000000000
--- a/web-old/src/__tests__/App.test.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { h } from 'preact';
-import App from '../app';
-import { render, screen } from 'testing-library';
-
-describe('App', () => {
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('loads the camera dashboard', async () => {
- render( );
- await screen.findByText('Cameras');
- expect(screen.queryByText('front')).toBeInTheDocument();
- });
-});
\ No newline at end of file
diff --git a/web-old/src/__tests__/AppBar.test.jsx b/web-old/src/__tests__/AppBar.test.jsx
deleted file mode 100644
index ec534df41..000000000
--- a/web-old/src/__tests__/AppBar.test.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { h } from 'preact';
-import * as Context from '../context';
-import AppBar from '../AppBar';
-import { fireEvent, render, screen } from '@testing-library/preact';
-
-describe('AppBar', () => {
- beforeEach(() => {
- vi.spyOn(Context, 'useDarkMode').mockImplementation(() => ({
- setDarkMode: vi.fn(),
- }));
- vi.spyOn(Context, 'DarkModeProvider').mockImplementation(({ children }) => {
- return {children}
;
- });
- });
-
- test('shows a menu on overflow click', async () => {
- render(
-
-
-
-
-
- );
-
- const overflowButton = await screen.findByLabelText('More options');
- fireEvent.click(overflowButton);
-
- const menu = await screen.findByRole('listbox');
- expect(menu).toBeInTheDocument();
- });
-
- test('sets dark mode on MenuItem select', async () => {
- const setDarkModeSpy = vi.fn();
- vi.spyOn(Context, 'useDarkMode').mockImplementation(() => ({
- setDarkMode: setDarkModeSpy,
- }));
- render(
-
-
-
-
-
- );
-
- const overflowButton = await screen.findByLabelText('More options');
- fireEvent.click(overflowButton);
-
- await screen.findByRole('listbox');
-
- fireEvent.click(screen.getByText('Light'));
- expect(setDarkModeSpy).toHaveBeenCalledWith('light');
- });
-});
diff --git a/web-old/src/__tests__/Sidebar.test.jsx b/web-old/src/__tests__/Sidebar.test.jsx
deleted file mode 100644
index 5bb89e564..000000000
--- a/web-old/src/__tests__/Sidebar.test.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { h } from 'preact';
-import { DrawerProvider } from '../context';
-import Sidebar from '../Sidebar';
-import { render, screen } from 'testing-library';
-
-describe('Sidebar', () => {
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('does not render cameras by default', async () => {
- const { findByText } = render( );
- await findByText('Cameras');
- expect(screen.queryByRole('link', { name: 'front' })).not.toBeInTheDocument();
- expect(screen.queryByRole('link', { name: 'side' })).not.toBeInTheDocument();
- });
-});
diff --git a/web-old/src/api/__tests__/index.test.jsx b/web-old/src/api/__tests__/index.test.jsx
deleted file mode 100644
index 51a5af74c..000000000
--- a/web-old/src/api/__tests__/index.test.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { h } from 'preact';
-import * as WS from '../ws';
-import { ApiProvider, useApiHost } from '..';
-import { render, screen } from 'testing-library';
-
-describe('useApiHost', () => {
- beforeEach(() => {
- vi.spyOn(WS, 'WsProvider').mockImplementation(({ children }) => children);
- });
-
- test('is set from the baseUrl', async () => {
- function Test() {
- const apiHost = useApiHost();
- return {apiHost}
;
- }
- render(
-
-
-
- );
- expect(screen.queryByText('http://localhost:3000/')).toBeInTheDocument();
- });
-});
diff --git a/web-old/src/api/__tests__/ws.test.jsx b/web-old/src/api/__tests__/ws.test.jsx
deleted file mode 100644
index bee8bfa28..000000000
--- a/web-old/src/api/__tests__/ws.test.jsx
+++ /dev/null
@@ -1,154 +0,0 @@
-/* eslint-disable jest/no-disabled-tests */
-import { h } from 'preact';
-import { WS as frigateWS, WsProvider, useWs } from '../ws';
-import { useCallback, useContext } from 'preact/hooks';
-import { fireEvent, render, screen } from 'testing-library';
-import { WS } from 'jest-websocket-mock';
-
-function Test() {
- const { state } = useContext(frigateWS);
- return state.__connected ? (
-
- {Object.keys(state).map((key) => (
-
- {JSON.stringify(state[key])}
-
- ))}
-
- ) : null;
-}
-
-const TEST_URL = 'ws://test-foo:1234/ws';
-
-describe('WsProvider', () => {
- let wsClient, wsServer;
- beforeEach(async () => {
- wsClient = {
- close: vi.fn(),
- send: vi.fn(),
- };
- wsServer = new WS(TEST_URL);
- });
-
- afterEach(() => {
- WS.clean();
- });
-
- test.skip('connects to the ws server', async () => {
- render(
-
-
-
- );
- await wsServer.connected;
- await screen.findByTestId('data');
- expect(wsClient.args).toEqual([TEST_URL]);
- expect(screen.getByTestId('__connected')).toHaveTextContent('true');
- });
-
- test.skip('receives data through useWs', async () => {
- function Test() {
- const {
- value: { payload, retain },
- connected,
- } = useWs('tacos');
- return connected ? (
-
-
{JSON.stringify(payload)}
-
{JSON.stringify(retain)}
-
- ) : null;
- }
-
- const { rerender } = render(
-
-
-
- );
- await wsServer.connected;
- await screen.findByTestId('payload');
- wsClient.onmessage({
- data: JSON.stringify({ topic: 'tacos', payload: JSON.stringify({ yes: true }), retain: false }),
- });
- rerender(
-
-
-
- );
- expect(screen.getByTestId('payload')).toHaveTextContent('{"yes":true}');
- expect(screen.getByTestId('retain')).toHaveTextContent('false');
- });
-
- test.skip('can send values through useWs', async () => {
- function Test() {
- const { send, connected } = useWs('tacos');
- const handleClick = useCallback(() => {
- send({ yes: true });
- }, [send]);
- return connected ? click me : null;
- }
-
- render(
-
-
-
- );
- await wsServer.connected;
- await screen.findByRole('button');
- fireEvent.click(screen.getByRole('button'));
- await expect(wsClient.send).toHaveBeenCalledWith(
- JSON.stringify({ topic: 'tacos', payload: JSON.stringify({ yes: true }), retain: false })
- );
- });
-
- test.skip('prefills the recordings/detect/snapshots state from config', async () => {
- vi.spyOn(Date, 'now').mockReturnValue(123456);
- const config = {
- cameras: {
- front: {
- name: 'front',
- detect: { enabled: true },
- record: { enabled: false },
- snapshots: { enabled: true },
- audio: { enabled: false },
- },
- side: {
- name: 'side',
- detect: { enabled: false },
- record: { enabled: false },
- snapshots: { enabled: false },
- audio: { enabled: false },
- },
- },
- };
- render(
-
-
-
- );
- await wsServer.connected;
- await screen.findByTestId('data');
- expect(screen.getByTestId('front/detect/state')).toHaveTextContent(
- '{"lastUpdate":123456,"payload":"ON","retain":false}'
- );
- expect(screen.getByTestId('front/recordings/state')).toHaveTextContent(
- '{"lastUpdate":123456,"payload":"OFF","retain":false}'
- );
- expect(screen.getByTestId('front/snapshots/state')).toHaveTextContent(
- '{"lastUpdate":123456,"payload":"ON","retain":false}'
- );
- expect(screen.getByTestId('side/detect/state')).toHaveTextContent(
- '{"lastUpdate":123456,"payload":"OFF","retain":false}'
- );
- expect(screen.getByTestId('side/recordings/state')).toHaveTextContent(
- '{"lastUpdate":123456,"payload":"OFF","retain":false}'
- );
- expect(screen.getByTestId('side/snapshots/state')).toHaveTextContent(
- '{"lastUpdate":123456,"payload":"OFF","retain":false}'
- );
- });
-});
-
-const mockConfig = {
- cameras: {},
-};
diff --git a/web-old/src/api/baseUrl.js b/web-old/src/api/baseUrl.js
deleted file mode 100644
index 1167789d2..000000000
--- a/web-old/src/api/baseUrl.js
+++ /dev/null
@@ -1 +0,0 @@
-export const baseUrl = `${window.location.protocol}//${window.location.host}${window.baseUrl || '/'}`;
diff --git a/web-old/src/api/index.jsx b/web-old/src/api/index.jsx
deleted file mode 100644
index d4113ed2b..000000000
--- a/web-old/src/api/index.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { h } from 'preact';
-import { baseUrl } from './baseUrl';
-import useSWR, { SWRConfig } from 'swr';
-import { WsProvider } from './ws';
-import axios from 'axios';
-
-axios.defaults.baseURL = `${baseUrl}api/`;
-axios.defaults.headers.common = {
- 'X-CSRF-TOKEN': 1,
- 'X-CACHE-BYPASS': 1,
-};
-
-export function ApiProvider({ children, options }) {
- return (
- axios.get(path, { params }).then((res) => res.data),
- ...options,
- }}
- >
- {children}
-
- );
-}
-
-function WsWithConfig({ children }) {
- const { data } = useSWR('config');
- return data ? {children} : children;
-}
-
-export function useApiHost() {
- return baseUrl;
-}
diff --git a/web-old/src/api/ws.jsx b/web-old/src/api/ws.jsx
deleted file mode 100644
index 82acdb2a0..000000000
--- a/web-old/src/api/ws.jsx
+++ /dev/null
@@ -1,134 +0,0 @@
-import { h, createContext } from 'preact';
-import { baseUrl } from './baseUrl';
-import { produce } from 'immer';
-import { useCallback, useContext, useEffect, useReducer } from 'preact/hooks';
-import useWebSocket, { ReadyState } from 'react-use-websocket';
-
-const initialState = Object.freeze({ __connected: false });
-export const WS = createContext({ state: initialState, readyState: null, sendJsonMessage: () => {} });
-
-function reducer(state, { topic, payload, retain }) {
- switch (topic) {
- case '__CLIENT_CONNECTED':
- return produce(state, (draftState) => {
- draftState.__connected = true;
- });
-
- default:
- return produce(state, (draftState) => {
- let parsedPayload = payload;
- try {
- parsedPayload = payload && JSON.parse(payload);
- } catch (e) {}
- draftState[topic] = {
- lastUpdate: Date.now(),
- payload: parsedPayload,
- retain,
- };
- });
- }
-}
-
-export function WsProvider({
- config,
- children,
- wsUrl = `${baseUrl.replace(/^http/, 'ws')}ws`,
-}) {
- const [state, dispatch] = useReducer(reducer, initialState);
-
- const { sendJsonMessage, readyState } = useWebSocket(wsUrl, {
-
- onMessage: (event) => {
- dispatch(JSON.parse(event.data));
- },
- onOpen: () => dispatch({ topic: '__CLIENT_CONNECTED' }),
- shouldReconnect: () => true,
- });
-
- useEffect(() => {
- Object.keys(config.cameras).forEach((camera) => {
- const { name, record, detect, snapshots, audio } = config.cameras[camera];
- dispatch({ topic: `${name}/recordings/state`, payload: record.enabled ? 'ON' : 'OFF', retain: false });
- dispatch({ topic: `${name}/detect/state`, payload: detect.enabled ? 'ON' : 'OFF', retain: false });
- dispatch({ topic: `${name}/snapshots/state`, payload: snapshots.enabled ? 'ON' : 'OFF', retain: false });
- dispatch({ topic: `${name}/audio/state`, payload: audio.enabled ? 'ON' : 'OFF', retain: false });
- });
- }, [config]);
-
- return {children} ;
-}
-
-export function useWs(watchTopic, publishTopic) {
- const { state, readyState, sendJsonMessage } = useContext(WS);
-
- const value = state[watchTopic] || { payload: null };
-
- const send = useCallback(
- (payload, retain = false) => {
- if (readyState === ReadyState.OPEN) {
- sendJsonMessage({
- topic: publishTopic || watchTopic,
- payload,
- retain,
- });
- }
- },
- [sendJsonMessage, readyState, watchTopic, publishTopic]
- );
-
- return { value, send, connected: state.__connected };
-}
-
-export function useDetectState(camera) {
- const {
- value: { payload },
- send,
- connected,
- } = useWs(`${camera}/detect/state`, `${camera}/detect/set`);
- return { payload, send, connected };
-}
-
-export function useRecordingsState(camera) {
- const {
- value: { payload },
- send,
- connected,
- } = useWs(`${camera}/recordings/state`, `${camera}/recordings/set`);
- return { payload, send, connected };
-}
-
-export function useSnapshotsState(camera) {
- const {
- value: { payload },
- send,
- connected,
- } = useWs(`${camera}/snapshots/state`, `${camera}/snapshots/set`);
- return { payload, send, connected };
-}
-
-export function useAudioState(camera) {
- const {
- value: { payload },
- send,
- connected,
- } = useWs(`${camera}/audio/state`, `${camera}/audio/set`);
- return { payload, send, connected };
-}
-
-export function usePtzCommand(camera) {
- const {
- value: { payload },
- send,
- connected,
- } = useWs(`${camera}/ptz`, `${camera}/ptz`);
- return { payload, send, connected };
-}
-
-export function useRestart() {
- const {
- value: { payload },
- send,
- connected,
- } = useWs('restart', 'restart');
- return { payload, send, connected };
-}
diff --git a/web-old/src/app.css b/web-old/src/app.css
deleted file mode 100644
index 088ed3ace..000000000
--- a/web-old/src/app.css
+++ /dev/null
@@ -1,25 +0,0 @@
-#app {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
-}
-
-.logo {
- height: 6em;
- padding: 1.5em;
-}
-.logo:hover {
- filter: drop-shadow(0 0 2em #646cffaa);
-}
-.logo.preact:hover {
- filter: drop-shadow(0 0 2em #673ab8aa);
-}
-
-.card {
- padding: 2em;
-}
-
-.read-the-docs {
- color: #888;
-}
diff --git a/web-old/src/app.tsx b/web-old/src/app.tsx
deleted file mode 100644
index 4e5123563..000000000
--- a/web-old/src/app.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import * as Routes from './routes';
-import { h } from 'preact';
-import ActivityIndicator from './components/ActivityIndicator';
-import AsyncRoute from 'preact-async-route';
-import AppBar from './AppBar';
-import Cameras from './routes/Cameras';
-import { Router } from 'preact-router';
-import Sidebar from './Sidebar';
-import { DarkModeProvider, DrawerProvider } from './context';
-import useSWR from 'swr';
-
-export default function App() {
- const { data: config } = useSWR('config');
- const cameraComponent = config && config.ui?.use_experimental ? Routes.getCameraV2 : Routes.getCamera;
-
- return (
-
-
-
-
- {!config ? (
-
- ) : (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
-
-
- );
-}
diff --git a/web-old/src/assets/preact.svg b/web-old/src/assets/preact.svg
deleted file mode 100644
index 908f17def..000000000
--- a/web-old/src/assets/preact.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/web-old/src/components/ActivityIndicator.jsx b/web-old/src/components/ActivityIndicator.jsx
deleted file mode 100644
index 4d08ce506..000000000
--- a/web-old/src/components/ActivityIndicator.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { h } from 'preact';
-
-const sizes = {
- sm: 'h-4 w-4 border-2 border-t-2',
- md: 'h-8 w-8 border-4 border-t-4',
- lg: 'h-16 w-16 border-8 border-t-8',
-};
-
-export default function ActivityIndicator({ size = 'md' }) {
- return (
-
- );
-}
diff --git a/web-old/src/components/AppBar.jsx b/web-old/src/components/AppBar.jsx
deleted file mode 100644
index 1003fee55..000000000
--- a/web-old/src/components/AppBar.jsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { h } from 'preact';
-import Button from './Button';
-import MenuIcon from '../icons/Menu';
-import MoreIcon from '../icons/More';
-import { useDrawer } from '../context';
-import { useLayoutEffect, useCallback, useState } from 'preact/hooks';
-
-// We would typically preserve these in component state
-// But need to avoid too many re-renders
-let lastScrollY = window.scrollY;
-
-export default function AppBar({ title: Title, overflowRef, onOverflowClick }) {
- const [show, setShow] = useState(true);
- const [atZero, setAtZero] = useState(window.scrollY === 0);
- const { setShowDrawer } = useDrawer();
-
- const scrollListener = useCallback(() => {
- const scrollY = window.scrollY;
-
- window.requestAnimationFrame(() => {
- setShow(scrollY <= 0 || lastScrollY > scrollY);
- setAtZero(scrollY === 0);
- lastScrollY = scrollY;
- });
- }, [setShow]);
-
- useLayoutEffect(() => {
- document.addEventListener('scroll', scrollListener);
- return () => {
- document.removeEventListener('scroll', scrollListener);
- };
- }, [scrollListener]);
-
- const handleShowDrawer = useCallback(() => {
- setShowDrawer(true);
- }, [setShowDrawer]);
-
- return (
-
-
-
-
-
-
-
-
- {overflowRef && onOverflowClick ? (
-
-
-
-
-
- ) : null}
-
-
- );
-}
diff --git a/web-old/src/components/AutoUpdatingCameraImage.jsx b/web-old/src/components/AutoUpdatingCameraImage.jsx
deleted file mode 100644
index 9cc598cd4..000000000
--- a/web-old/src/components/AutoUpdatingCameraImage.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { h } from 'preact';
-import CameraImage from './CameraImage';
-import { useCallback, useState } from 'preact/hooks';
-
-const MIN_LOAD_TIMEOUT_MS = 200;
-
-export default function AutoUpdatingCameraImage({ camera, searchParams = '', showFps = true, className }) {
- const [key, setKey] = useState(Date.now());
- const [fps, setFps] = useState(0);
-
- const handleLoad = useCallback(() => {
- const loadTime = Date.now() - key;
- setFps((1000 / Math.max(loadTime, MIN_LOAD_TIMEOUT_MS)).toFixed(1));
- setTimeout(
- () => {
- setKey(Date.now());
- },
- loadTime > MIN_LOAD_TIMEOUT_MS ? 1 : MIN_LOAD_TIMEOUT_MS
- );
- }, [key, setFps]);
-
- return (
-
-
- {showFps ? Displaying at {fps}fps : null}
-
- );
-}
diff --git a/web-old/src/components/BubbleButton.tsx b/web-old/src/components/BubbleButton.tsx
deleted file mode 100644
index 96712d813..000000000
--- a/web-old/src/components/BubbleButton.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { h, JSX } from 'preact';
-
-interface BubbleButtonProps {
- variant?: 'primary' | 'secondary';
- children?: JSX.Element;
- disabled?: boolean;
- className?: string;
- onClick?: () => void;
-}
-
-export const BubbleButton = ({
- variant = 'primary',
- children,
- onClick,
- disabled = false,
- className = '',
-}: BubbleButtonProps) => {
- const BASE_CLASS = 'rounded-full px-4 py-2';
- const PRIMARY_CLASS = 'text-white bg-blue-500 dark:text-black dark:bg-white';
- const SECONDARY_CLASS = 'text-black dark:text-white bg-transparent';
- let computedClass = BASE_CLASS;
-
- if (disabled) {
- computedClass += ' text-gray-200 dark:text-gray-200';
- } else if (variant === 'primary') {
- computedClass += ` ${PRIMARY_CLASS}`;
- } else if (variant === 'secondary') {
- computedClass += ` ${SECONDARY_CLASS}`;
- }
-
- const onClickHandler = () => {
- if (disabled) {
- return;
- }
-
- if (onClick) {
- onClick();
- }
- };
- return (
-
- {children}
-
- );
-};
diff --git a/web-old/src/components/Button.jsx b/web-old/src/components/Button.jsx
deleted file mode 100644
index 11e469506..000000000
--- a/web-old/src/components/Button.jsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import { h, Fragment } from 'preact';
-import Tooltip from './Tooltip';
-import { useCallback, useRef, useState } from 'preact/hooks';
-
-const ButtonColors = {
- blue: {
- contained: 'bg-blue-500 focus:bg-blue-400 active:bg-blue-600 ring-blue-300',
- outlined:
- 'text-blue-500 border-2 border-blue-500 hover:bg-blue-500 hover:bg-opacity-20 focus:bg-blue-500 focus:bg-opacity-40 active:bg-blue-500 active:bg-opacity-40',
- text: 'text-blue-500 hover:bg-blue-500 hover:bg-opacity-20 focus:bg-blue-500 focus:bg-opacity-40 active:bg-blue-500 active:bg-opacity-40',
- iconOnly: 'text-blue-500 hover:text-blue-200',
- },
- red: {
- contained: 'bg-red-500 focus:bg-red-400 active:bg-red-600 ring-red-300',
- outlined:
- 'text-red-500 border-2 border-red-500 hover:bg-red-500 hover:bg-opacity-20 focus:bg-red-500 focus:bg-opacity-40 active:bg-red-500 active:bg-opacity-40',
- text: 'text-red-500 hover:bg-red-500 hover:bg-opacity-20 focus:bg-red-500 focus:bg-opacity-40 active:bg-red-500 active:bg-opacity-40',
- iconOnly: 'text-red-500 hover:text-red-200',
- },
- yellow: {
- contained: 'bg-yellow-500 focus:bg-yellow-400 active:bg-yellow-600 ring-yellow-300',
- outlined:
- 'text-yellow-500 border-2 border-yellow-500 hover:bg-yellow-500 hover:bg-opacity-20 focus:bg-yellow-500 focus:bg-opacity-40 active:bg-yellow-500 active:bg-opacity-40',
- text: 'text-yellow-500 hover:bg-yellow-500 hover:bg-opacity-20 focus:bg-yellow-500 focus:bg-opacity-40 active:bg-yellow-500 active:bg-opacity-40',
- iconOnly: 'text-yellow-500 hover:text-yellow-200',
- },
- green: {
- contained: 'bg-green-500 focus:bg-green-400 active:bg-green-600 ring-green-300',
- outlined:
- 'text-green-500 border-2 border-green-500 hover:bg-green-500 hover:bg-opacity-20 focus:bg-green-500 focus:bg-opacity-40 active:bg-green-500 active:bg-opacity-40',
- text: 'text-green-500 hover:bg-green-500 hover:bg-opacity-20 focus:bg-green-500 focus:bg-opacity-40 active:bg-green-500 active:bg-opacity-40',
- iconOnly: 'text-green-500 hover:text-green-200',
- },
- gray: {
- contained: 'bg-gray-500 focus:bg-gray-400 active:bg-gray-600 ring-gray-300',
- outlined:
- 'text-gray-500 border-2 border-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
- text: 'text-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
- iconOnly: 'text-gray-500 hover:text-gray-200',
- },
- disabled: {
- contained: 'bg-gray-400',
- outlined:
- 'text-gray-500 border-2 border-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
- text: 'text-gray-500 hover:bg-gray-500 hover:bg-opacity-20 focus:bg-gray-500 focus:bg-opacity-40 active:bg-gray-500 active:bg-opacity-40',
- iconOnly: 'text-gray-500 hover:text-gray-200',
- },
- black: {
- contained: '',
- outlined: '',
- text: 'text-black dark:text-white',
- iconOnly: '',
- },
-};
-
-const ButtonTypes = {
- contained: 'text-white shadow focus:shadow-xl hover:shadow-md',
- outlined: '',
- text: 'transition-opacity',
- iconOnly: 'transition-opacity',
-};
-
-export default function Button({
- children,
- className = '',
- color = 'blue',
- disabled = false,
- ariaCapitalize = false,
- href,
- target,
- type = 'contained',
- ...attrs
-}) {
- const [hovered, setHovered] = useState(false);
- const ref = useRef();
-
- let classes = `whitespace-nowrap flex items-center space-x-1 ${className} ${ButtonTypes[type]} ${
- ButtonColors[disabled ? 'disabled' : color][type]
- } font-sans inline-flex font-bold uppercase text-xs px-1.5 md:px-2 py-2 rounded outline-none focus:outline-none ring-opacity-50 transition-shadow transition-colors ${
- disabled ? 'cursor-not-allowed' : `${type == 'iconOnly' ? '' : 'focus:ring-2'} cursor-pointer`
- }`;
-
- if (disabled) {
- classes = classes.replace(/(?:focus|active|hover):[^ ]+/g, '');
- }
-
- const handleMousenter = useCallback(() => {
- setHovered(true);
- }, []);
-
- const handleMouseleave = useCallback(() => {
- setHovered(false);
- }, []);
-
- const Element = href ? 'a' : 'div';
-
- return (
-
-
- {children}
-
- {hovered && attrs['aria-label'] ? : null}
-
- );
-}
diff --git a/web-old/src/components/ButtonsTabbed.jsx b/web-old/src/components/ButtonsTabbed.jsx
deleted file mode 100644
index e49b9239d..000000000
--- a/web-old/src/components/ButtonsTabbed.jsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { h } from 'preact';
-import { useCallback, useState } from 'preact/hooks';
-
-export default function ButtonsTabbed({
- viewModes = [''],
- currentViewMode = '',
- setViewMode = null,
- setHeader = null,
- headers = [''],
- className = 'text-gray-600 py-0 px-4 block hover:text-gray-500',
- selectedClassName = `${className} focus:outline-none border-b-2 font-medium border-gray-500`,
-}) {
- const [selected, setSelected] = useState(viewModes ? viewModes.indexOf(currentViewMode) : 0);
- const captitalize = (str) => {
- return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
- };
-
- const getHeader = useCallback(
- (i) => {
- return headers.length === viewModes.length ? headers[i] : captitalize(viewModes[i]);
- },
- [headers, viewModes]
- );
-
- const handleClick = useCallback(
- (i) => {
- setSelected(i);
- setViewMode && setViewMode(viewModes[i]);
- setHeader && setHeader(getHeader(i));
- },
- [setViewMode, setHeader, setSelected, viewModes, getHeader]
- );
-
- setHeader && setHeader(getHeader(selected));
- return (
-
- {viewModes.map((item, i) => {
- return (
- handleClick(i)} className={i === selected ? selectedClassName : className}>
- {captitalize(item)}
-
- );
- })}
-
- );
-}
diff --git a/web-old/src/components/Calendar.jsx b/web-old/src/components/Calendar.jsx
deleted file mode 100644
index bfab5d785..000000000
--- a/web-old/src/components/Calendar.jsx
+++ /dev/null
@@ -1,344 +0,0 @@
-import { h } from 'preact';
-import { useEffect, useState, useCallback, useMemo, useRef } from 'preact/hooks';
-import ArrowRight from '../icons/ArrowRight';
-import ArrowRightDouble from '../icons/ArrowRightDouble';
-
-const todayTimestamp = new Date().setHours(0, 0, 0, 0).valueOf();
-
-const Calendar = ({ onChange, calendarRef, close, dateRange, children }) => {
- const keyRef = useRef([]);
-
- const date = new Date();
- const year = date.getFullYear();
- const month = date.getMonth();
-
- const daysMap = useMemo(() => ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], []);
- const monthMap = useMemo(
- () => [
- 'January',
- 'February',
- 'March',
- 'April',
- 'May',
- 'June',
- 'July',
- 'August',
- 'September',
- 'October',
- 'November',
- 'December',
- ],
- []
- );
-
- const [state, setState] = useState({
- getMonthDetails: [],
- year,
- month,
- selectedDay: null,
- timeRange: dateRange,
- monthDetails: null,
- });
-
- const getNumberOfDays = useCallback((year, month) => {
- return 40 - new Date(year, month, 40).getDate();
- }, []);
-
- const getDayDetails = useCallback(
- (args) => {
- const date = args.index - args.firstDay;
- const day = args.index % 7;
- let prevMonth = args.month - 1;
- let prevYear = args.year;
- if (prevMonth < 0) {
- prevMonth = 11;
- prevYear--;
- }
- const prevMonthNumberOfDays = getNumberOfDays(prevYear, prevMonth);
- const _date = (date < 0 ? prevMonthNumberOfDays + date : date % args.numberOfDays) + 1;
- const month = date < 0 ? -1 : date >= args.numberOfDays ? 1 : 0;
- const timestamp = new Date(args.year, args.month, _date).getTime();
- return {
- date: _date,
- day,
- month,
- timestamp,
- dayString: daysMap[day],
- };
- },
- [getNumberOfDays, daysMap]
- );
-
- const getMonthDetails = useCallback(
- (year, month) => {
- const firstDay = new Date(year, month).getDay();
- const numberOfDays = getNumberOfDays(year, month);
- const monthArray = [];
- const rows = 6;
- let currentDay = null;
- let index = 0;
- const cols = 7;
-
- for (let row = 0; row < rows; row++) {
- for (let col = 0; col < cols; col++) {
- currentDay = getDayDetails({
- index,
- numberOfDays,
- firstDay,
- year,
- month,
- });
- monthArray.push(currentDay);
- index++;
- }
- }
- return monthArray;
- },
- [getNumberOfDays, getDayDetails]
- );
-
- useEffect(() => {
- setState((prev) => ({
- ...prev,
- selectedDay: todayTimestamp,
- monthDetails: getMonthDetails(year, month),
- }));
- }, [year, month, getMonthDetails]);
-
- useEffect(() => {
- // add refs for keyboard navigation
- if (state.monthDetails) {
- keyRef.current = keyRef.current.slice(0, state.monthDetails.length);
- }
- // set today date in focus for keyboard navigation
- const todayDate = new Date(todayTimestamp).getDate();
- keyRef.current.find((t) => t.tabIndex === todayDate)?.focus();
- }, [state.monthDetails]);
-
- const isCurrentDay = (day) => day.timestamp === todayTimestamp;
-
- const isSelectedRange = useCallback(
- (day) => {
- if (!state.timeRange.after || !state.timeRange.before) return;
-
- return day.timestamp < state.timeRange.before && day.timestamp >= new Date(state.timeRange.after).setHours(0);
- },
- [state.timeRange]
- );
-
- const isFirstDayInRange = useCallback(
- (day) => {
- if (isCurrentDay(day)) return;
- return new Date(state.timeRange.after).setHours(0) === day.timestamp;
- },
- [state.timeRange.after]
- );
-
- const isLastDayInRange = useCallback(
- (day) => {
- // if the hour is not above 0, we will use 24 hour.
- const beforeHour = new Date(state.timeRange.before).getHours() || 24;
-
- /**
- * When user selects a day in the calendar, the before will be 00:00.
- * When user selects a time in timepicker, the day.timestamp hour must be changed to match the selected end () hour.
- */
- return state.timeRange.before === new Date(day.timestamp).setHours(beforeHour);
- },
- [state.timeRange.before]
- );
-
- const getMonthStr = useCallback(
- (month) => {
- return monthMap[Math.max(Math.min(11, month), 0)] || 'Month';
- },
- [monthMap]
- );
-
- const onDateClick = (day) => {
- const { before, after } = state.timeRange;
- let timeRange = { before: null, after: null };
-
- // user has selected a date < after, reset values
- if (after === null || day.timestamp < after) {
- timeRange = {
- before: new Date(day.timestamp).setHours(24, 0, 0, 0),
- after: day.timestamp,
- };
- }
-
- // user has selected a date > after
- if (after !== null && before !== new Date(day.timestamp).setHours(24, 0, 0, 0) && day.timestamp > after) {
- timeRange = {
- after,
- before:
- day.timestamp >= todayTimestamp
- ? new Date(todayTimestamp).setHours(24, 0, 0, 0)
- : new Date(day.timestamp).setHours(24, 0, 0, 0),
- };
- }
-
- // reset values
- if (before === new Date(day.timestamp).setHours(24, 0, 0, 0)) {
- timeRange = { before: null, after: null };
- }
-
- setState((prev) => ({
- ...prev,
- timeRange,
- selectedDay: day.timestamp,
- }));
-
- if (onChange) {
- onChange(timeRange.after ? { before: timeRange.before / 1000, after: timeRange.after / 1000 } : ['all']);
- }
- };
-
- const setYear = useCallback(
- (offset) => {
- const year = state.year + offset;
- const month = state.month;
- setState((prev) => {
- return {
- ...prev,
- year,
- monthDetails: getMonthDetails(year, month),
- };
- });
- },
- [state.year, state.month, getMonthDetails]
- );
-
- const setMonth = (offset) => {
- let year = state.year;
- let month = state.month + offset;
- if (month === -1) {
- month = 11;
- year--;
- } else if (month === 12) {
- month = 0;
- year++;
- }
- setState((prev) => {
- return {
- ...prev,
- year,
- month,
- monthDetails: getMonthDetails(year, month),
- };
- });
- };
-
- const handleKeydown = (e, day, index) => {
- if ((keyRef.current && e.key === 'Enter') || e.keyCode === 32) {
- e.preventDefault();
- day.month === 0 && onDateClick(day);
- }
- if (e.key === 'ArrowLeft') {
- index > 0 && keyRef.current[index - 1].focus();
- }
- if (e.key === 'ArrowRight') {
- index < 41 && keyRef.current[index + 1].focus();
- }
- if (e.key === 'ArrowUp') {
- e.preventDefault();
- index > 6 && keyRef.current[index - 7].focus();
- }
- if (e.key === 'ArrowDown') {
- e.preventDefault();
- index < 36 && keyRef.current[index + 7].focus();
- }
- if (e.key === 'Escape') {
- close();
- }
- };
-
- const renderCalendar = () => {
- const days =
- state.monthDetails &&
- state.monthDetails.map((day, idx) => {
- return (
- onDateClick(day)}
- onkeydown={(e) => handleKeydown(e, day, idx)}
- ref={(ref) => (keyRef.current[idx] = ref)}
- tabIndex={day.month === 0 ? day.date : null}
- className={`h-12 w-12 float-left flex flex-shrink justify-center items-center cursor-pointer hover:border hover:rounded-md border-gray-600 ${
- day.month !== 0 ? ' opacity-50 bg-gray-700 dark:bg-gray-700 pointer-events-none' : ''
- }
- ${isFirstDayInRange(day) ? ' rounded-l-xl hover:rounded-l-xl' : ''}
- ${isSelectedRange(day) ? ' bg-blue-600 hover:rounded-none' : ''}
- ${isLastDayInRange(day) ? ' rounded-r-xl hover:rounded-r-xl' : ''}
- ${isCurrentDay(day) && !isLastDayInRange(day) ? 'rounded-full bg-gray-100 dark:hover:bg-gray-100 ' : ''}`}
- key={idx}
- >
-
- {day.date}
-
-
- );
- });
-
- return (
-
-
- {['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'].map((d, i) => (
-
- {d}
-
- ))}
-
-
{days}
-
- );
- };
-
- return (
-
-
-
-
-
-
-
{state.year}
-
{getMonthStr(state.month)}
-
-
-
-
-
{renderCalendar()}
-
- {children}
-
- );
-};
-
-export default Calendar;
diff --git a/web-old/src/components/CameraControlPanel.jsx b/web-old/src/components/CameraControlPanel.jsx
deleted file mode 100644
index 394d41794..000000000
--- a/web-old/src/components/CameraControlPanel.jsx
+++ /dev/null
@@ -1,257 +0,0 @@
-import { h } from 'preact';
-import { useEffect, useCallback, useState } from 'preact/hooks';
-import useSWR from 'swr';
-import { usePtzCommand } from '../api/ws';
-import ActivityIndicator from './ActivityIndicator';
-import ArrowRightDouble from '../icons/ArrowRightDouble';
-import ArrowUpDouble from '../icons/ArrowUpDouble';
-import ArrowDownDouble from '../icons/ArrowDownDouble';
-import ArrowLeftDouble from '../icons/ArrowLeftDouble';
-import Button from './Button';
-import Heading from './Heading';
-
-export default function CameraControlPanel({ camera = '' }) {
- const { data: ptz } = useSWR(`${camera}/ptz/info`);
- const [currentPreset, setCurrentPreset] = useState('');
-
- const { payload: _, send: sendPtz } = usePtzCommand(camera);
-
- const onSetPreview = async (e) => {
- e.stopPropagation();
-
- if (currentPreset == 'none') {
- return;
- }
-
- sendPtz(`preset_${currentPreset}`);
- setCurrentPreset('');
- };
-
- const onSetMove = useCallback(async (e, dir) => {
- e.stopPropagation();
- sendPtz(`MOVE_${dir}`);
- setCurrentPreset('');
- }, [sendPtz, setCurrentPreset]);
-
- const onSetZoom = useCallback(async (e, dir) => {
- e.stopPropagation();
- sendPtz(`ZOOM_${dir}`);
- setCurrentPreset('');
- }, [sendPtz, setCurrentPreset]);
-
- const onSetStop = useCallback(async (e) => {
- e.stopPropagation();
- sendPtz('STOP');
- }, [sendPtz]);
-
- const keydownListener = useCallback((e) => {
- if (!ptz || !e) {
- return;
- }
-
- if (e.repeat) {
- e.preventDefault();
- return;
- }
-
- if (ptz.features.includes('pt')) {
- if (e.key === 'ArrowLeft') {
- e.preventDefault();
- onSetMove(e, 'LEFT');
- } else if (e.key === 'ArrowRight') {
- e.preventDefault();
- onSetMove(e, 'RIGHT');
- } else if (e.key === 'ArrowUp') {
- e.preventDefault();
- onSetMove(e, 'UP');
- } else if (e.key === 'ArrowDown') {
- e.preventDefault();
- onSetMove(e, 'DOWN');
- }
-
- if (ptz.features.includes('zoom')) {
- if (e.key == '+') {
- e.preventDefault();
- onSetZoom(e, 'IN');
- } else if (e.key == '-') {
- e.preventDefault();
- onSetZoom(e, 'OUT');
- }
- }
- }
- }, [onSetMove, onSetZoom, ptz]);
-
- const keyupListener = useCallback((e) => {
- if (!e || e.repeat) {
- return;
- }
-
- if (
- e.key === 'ArrowLeft' ||
- e.key === 'ArrowRight' ||
- e.key === 'ArrowUp' ||
- e.key === 'ArrowDown' ||
- e.key === '+' ||
- e.key === '-'
- ) {
- e.preventDefault();
- onSetStop(e);
- }
- }, [onSetStop]);
-
- useEffect(() => {
- document.addEventListener('keydown', keydownListener);
- document.addEventListener('keyup', keyupListener);
- return () => {
- document.removeEventListener('keydown', keydownListener);
- document.removeEventListener('keyup', keyupListener);
- };
- }, [keydownListener, keyupListener, ptz]);
-
- if (!ptz) {
- return ;
- }
-
- return (
-
- {ptz.features.includes('pt') && (
-
-
-
- Pan / Tilt
-
-
-
onSetMove(e, 'UP')}
- onMouseUp={(e) => onSetStop(e)}
- onTouchStart={(e) => {
- onSetMove(e, 'UP');
- e.preventDefault();
- }}
- onTouchEnd={(e) => {
- onSetStop(e);
- e.preventDefault();
- }}
- >
-
-
-
-
-
onSetMove(e, 'LEFT')}
- onMouseUp={(e) => onSetStop(e)}
- onTouchStart={(e) => {
- onSetMove(e, 'LEFT');
- e.preventDefault();
- }}
- onTouchEnd={(e) => {
- onSetStop(e);
- e.preventDefault();
- }}
- >
-
-
-
onSetMove(e, 'RIGHT')}
- onMouseUp={(e) => onSetStop(e)}
- onTouchStart={(e) => {
- onSetMove(e, 'RIGHT');
- e.preventDefault();
- }}
- onTouchEnd={(e) => {
- onSetStop(e);
- e.preventDefault();
- }}
- >
-
-
-
-
-
onSetMove(e, 'DOWN')}
- onMouseUp={(e) => onSetStop(e)}
- onTouchStart={(e) => {
- onSetMove(e, 'DOWN');
- e.preventDefault();
- }}
- onTouchEnd={(e) => {
- onSetStop(e);
- e.preventDefault();
- }}
- >
-
-
-
-
-
- )}
-
- {ptz.features.includes('zoom') && (
-
-
- Zoom
-
-
-
onSetZoom(e, 'IN')}
- onMouseUp={(e) => onSetStop(e)}
- onTouchStart={(e) => {
- onSetZoom(e, 'IN');
- e.preventDefault();
- }}
- onTouchEnd={(e) => {
- onSetStop(e);
- e.preventDefault();
- }}
- >
- +
-
-
-
-
-
onSetZoom(e, 'OUT')}
- onMouseUp={(e) => onSetStop(e)}
- onTouchStart={(e) => {
- onSetZoom(e, 'OUT');
- e.preventDefault();
- }}
- onTouchEnd={(e) => {
- onSetStop(e);
- e.preventDefault();
- }}
- >
- -
-
-
-
- )}
-
- {(ptz.presets || []).length > 0 && (
-
-
- Presets
-
-
- {
- setCurrentPreset(e.target.value);
- }}
- >
- Select Preset
- {ptz.presets.map((item) => (
-
- {item.charAt(0).toUpperCase() + item.slice(1)}
-
- ))}
-
-
-
-
onSetPreview(e)}>Move Camera To Preset
-
- )}
-
- );
-}
diff --git a/web-old/src/components/CameraImage.jsx b/web-old/src/components/CameraImage.jsx
deleted file mode 100644
index fdca8172d..000000000
--- a/web-old/src/components/CameraImage.jsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import { h } from 'preact';
-import ActivityIndicator from './ActivityIndicator';
-import { useApiHost } from '../api';
-import useSWR from 'swr';
-import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks';
-import { useResizeObserver } from '../hooks';
-
-export default function CameraImage({ camera, onload, searchParams = '', stretch = false }) {
- const { data: config } = useSWR('config');
- const apiHost = useApiHost();
- const [hasLoaded, setHasLoaded] = useState(false);
- const containerRef = useRef(null);
- const canvasRef = useRef(null);
- const [{ width: containerWidth }] = useResizeObserver(containerRef);
-
- // Add scrollbar width (when visible) to the available observer width to eliminate screen juddering.
- // https://github.com/blakeblackshear/frigate/issues/1657
- let scrollBarWidth = 0;
- if (window.innerWidth && document.body.offsetWidth) {
- scrollBarWidth = window.innerWidth - document.body.offsetWidth;
- }
- const availableWidth = scrollBarWidth ? containerWidth + scrollBarWidth : containerWidth;
-
- const { name } = config ? config.cameras[camera] : '';
- const enabled = config ? config.cameras[camera].enabled : 'True';
- const { width, height } = config ? config.cameras[camera].detect : { width: 1, height: 1 };
- const aspectRatio = width / height;
-
- const scaledHeight = useMemo(() => {
- const scaledHeight = Math.floor(availableWidth / aspectRatio);
- const finalHeight = stretch ? scaledHeight : Math.min(scaledHeight, height);
-
- if (finalHeight > 0) {
- return finalHeight;
- }
-
- return 100;
- }, [availableWidth, aspectRatio, height, stretch]);
- const scaledWidth = useMemo(
- () => Math.ceil(scaledHeight * aspectRatio - scrollBarWidth),
- [scaledHeight, aspectRatio, scrollBarWidth]
- );
-
- const img = useMemo(() => new Image(), []);
- img.onload = useCallback(
- (event) => {
- setHasLoaded(true);
- if (canvasRef.current) {
- const ctx = canvasRef.current.getContext('2d');
- ctx.drawImage(img, 0, 0, scaledWidth, scaledHeight);
- }
- onload && onload(event);
- },
- [img, scaledHeight, scaledWidth, setHasLoaded, onload, canvasRef]
- );
-
- useEffect(() => {
- if (!config || scaledHeight === 0 || !canvasRef.current) {
- return;
- }
- img.src = `${apiHost}api/${name}/latest.jpg?h=${scaledHeight}${searchParams ? `&${searchParams}` : ''}`;
- }, [apiHost, canvasRef, name, img, searchParams, scaledHeight, config]);
-
- return (
-
- {enabled ? (
-
- ) : (
-
Camera is disabled in config, no stream or snapshot available!
- )}
- {!hasLoaded && enabled ? (
-
- ) : null}
-
- );
-}
diff --git a/web-old/src/components/Card.jsx b/web-old/src/components/Card.jsx
deleted file mode 100644
index 43f334d1d..000000000
--- a/web-old/src/components/Card.jsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { h } from 'preact';
-import Button from './Button';
-import Heading from './Heading';
-
-export default function Box({
- buttons = [],
- className = '',
- content,
- elevated = true,
- header,
- href,
- icons = [],
- media = null,
- ...props
-}) {
- const Element = href ? 'a' : 'div';
-
- const typeClasses = elevated
- ? 'shadow-md hover:shadow-lg transition-shadow'
- : 'border border-gray-200 dark:border-gray-700';
-
- return (
-
- {media || header ? (
-
- {media}
- {header ? {header} : null}
-
- ) : null}
- {buttons.length || content || icons.length ? (
-
- {content || null}
- {buttons.length ? (
-
- {buttons.map(({ name, href }) => (
-
- {name}
-
- ))}
-
- {icons.map(({ name, icon: Icon, ...props }) => (
-
-
-
- ))}
-
- ) : null}
-
- ) : null}
-
- );
-}
diff --git a/web-old/src/components/DatePicker.jsx b/web-old/src/components/DatePicker.jsx
deleted file mode 100644
index 1df2e35dd..000000000
--- a/web-old/src/components/DatePicker.jsx
+++ /dev/null
@@ -1,161 +0,0 @@
-import { h } from 'preact';
-import { useCallback, useEffect, useState } from 'preact/hooks';
-
-export const DateFilterOptions = [
- {
- label: 'All',
- value: ['all'],
- },
- {
- label: 'Today',
- value: {
- //Before
- before: new Date().setHours(24, 0, 0, 0) / 1000,
- //After
- after: new Date().setHours(0, 0, 0, 0) / 1000,
- },
- },
- {
- label: 'Yesterday',
- value: {
- //Before
- before: new Date(new Date().setDate(new Date().getDate() - 1)).setHours(24, 0, 0, 0) / 1000,
- //After
- after: new Date(new Date().setDate(new Date().getDate() - 1)).setHours(0, 0, 0, 0) / 1000,
- },
- },
- {
- label: 'Last 7 Days',
- value: {
- //Before
- before: new Date().setHours(24, 0, 0, 0) / 1000,
- //After
- after: new Date(new Date().setDate(new Date().getDate() - 7)).setHours(0, 0, 0, 0) / 1000,
- },
- },
- {
- label: 'This Month',
- value: {
- //Before
- before: new Date().setHours(24, 0, 0, 0) / 1000,
- //After
- after: new Date(new Date().getFullYear(), new Date().getMonth(), 1).getTime() / 1000,
- },
- },
- {
- label: 'Last Month',
- value: {
- //Before
- before: new Date(new Date().getFullYear(), new Date().getMonth(), 1).getTime() / 1000,
- //After
- after: new Date(new Date().getFullYear(), new Date().getMonth() - 1, 1).getTime() / 1000,
- },
- },
- {
- label: 'Custom Range',
- value: 'custom_range',
- },
-];
-
-export default function DatePicker({
- helpText,
- keyboardType = 'text',
- inputRef,
- label,
- leadingIcon: LeadingIcon,
- onBlur,
- onChangeText,
- onFocus,
- trailingIcon: TrailingIcon,
- value: propValue = '',
- ...props
-}) {
- const [isFocused, setFocused] = useState(false);
- const [value, setValue] = useState(propValue);
-
- useEffect(() => {
- if (propValue !== value) {
- setValue(propValue);
- }
- }, [propValue, setValue, value]);
-
- const handleFocus = useCallback(
- (event) => {
- setFocused(true);
- onFocus && onFocus(event);
- },
- [onFocus]
- );
-
- const handleBlur = useCallback(
- (event) => {
- setFocused(false);
- onBlur && onBlur(event);
- },
- [onBlur]
- );
-
- const handleChange = useCallback(
- (event) => {
- const { value } = event.target;
- setValue(value);
- onChangeText && onChangeText(value);
- },
- [onChangeText, setValue]
- );
-
- const onClick = (e) => {
- props.onclick(e);
- };
- const labelMoved = isFocused || value !== '';
-
- return (
-
- {props.children}
-
-
- {LeadingIcon ? (
-
-
-
- ) : null}
-
- {TrailingIcon ? (
-
-
-
- ) : null}
-
-
- {helpText ?
{helpText}
: null}
-
- );
-}
diff --git a/web-old/src/components/DebugCamera.jsx b/web-old/src/components/DebugCamera.jsx
deleted file mode 100644
index 9c4d67f73..000000000
--- a/web-old/src/components/DebugCamera.jsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import { h } from 'preact';
-import Link from './Link';
-import Switch from './Switch';
-import { useCallback, useMemo } from 'preact/hooks';
-import { usePersistence } from '../context';
-import AutoUpdatingCameraImage from './AutoUpdatingCameraImage';
-
-const emptyObject = Object.freeze({});
-
-export function DebugCamera({ camera }) {
- const [options, setOptions] = usePersistence(`${camera}-feed`, emptyObject);
-
- const handleSetOption = useCallback(
- (id, value) => {
- const newOptions = { ...options, [id]: value };
- setOptions(newOptions);
- },
- [options, setOptions]
- );
-
- const searchParams = useMemo(
- () =>
- new URLSearchParams(
- Object.keys(options).reduce((memo, key) => {
- memo.push([key, options[key] === true ? '1' : '0']);
- return memo;
- }, [])
- ),
- [options]
- );
-
- const optionContent = (
-
-
-
-
-
-
-
- Mask & Zone creator
-
- );
-
- return (
-
- );
-}
diff --git a/web-old/src/components/Dialog.jsx b/web-old/src/components/Dialog.jsx
deleted file mode 100644
index 6bf9e3105..000000000
--- a/web-old/src/components/Dialog.jsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { h, Fragment } from 'preact';
-import { createPortal } from 'preact/compat';
-import { useState, useEffect } from 'preact/hooks';
-
-export default function Dialog({ children, portalRootID = 'dialogs' }) {
- const portalRoot = portalRootID && document.getElementById(portalRootID);
- const [show, setShow] = useState(false);
-
- useEffect(() => {
- window.requestAnimationFrame(() => {
- setShow(true);
- });
- }, []);
-
- const dialog = (
-
-
-
- );
-
- return portalRoot ? createPortal(dialog, portalRoot) : dialog;
-}
diff --git a/web-old/src/components/DialogLarge.jsx b/web-old/src/components/DialogLarge.jsx
deleted file mode 100644
index c78926822..000000000
--- a/web-old/src/components/DialogLarge.jsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { h, Fragment } from 'preact';
-import { createPortal } from 'preact/compat';
-import { useState, useEffect } from 'preact/hooks';
-
-export default function LargeDialog({ children, portalRootID = 'dialogs' }) {
- const portalRoot = portalRootID && document.getElementById(portalRootID);
- const [show, setShow] = useState(false);
-
- useEffect(() => {
- window.requestAnimationFrame(() => {
- setShow(true);
- });
- }, []);
-
- const dialog = (
-
-
-
- );
-
- return portalRoot ? createPortal(dialog, portalRoot) : dialog;
-}
diff --git a/web-old/src/components/Heading.jsx b/web-old/src/components/Heading.jsx
deleted file mode 100644
index b730c6922..000000000
--- a/web-old/src/components/Heading.jsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { h } from 'preact';
-
-export default function Heading({ children, className = '', size = '2xl' }) {
- return {children} ;
-}
diff --git a/web-old/src/components/HistoryViewer/HistoryHeader.tsx b/web-old/src/components/HistoryViewer/HistoryHeader.tsx
deleted file mode 100644
index 8be8a1b44..000000000
--- a/web-old/src/components/HistoryViewer/HistoryHeader.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { h } from 'preact';
-import Heading from '../Heading';
-import type { TimelineEvent } from '../Timeline/TimelineEvent';
-
-interface HistoryHeaderProps {
- event?: TimelineEvent;
- className?: string;
-}
-export const HistoryHeader = ({ event, className = '' }: HistoryHeaderProps) => {
- let title = 'No Event Found';
- let subtitle = Event was not found at marker position. ;
- if (event) {
- const { startTime, endTime, label } = event;
- const thisMorning = new Date();
- thisMorning.setHours(0, 0, 0);
- const isToday = endTime.getTime() > thisMorning.getTime();
- title = label;
- subtitle = (
-
- {isToday ? 'Today' : 'Yesterday'}, {startTime.toLocaleTimeString()} - {endTime.toLocaleTimeString()} ·
-
- );
- }
- return (
-
- );
-};
diff --git a/web-old/src/components/HistoryViewer/HistoryVideo.tsx b/web-old/src/components/HistoryViewer/HistoryVideo.tsx
deleted file mode 100644
index c843afb02..000000000
--- a/web-old/src/components/HistoryViewer/HistoryVideo.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-import { h } from 'preact';
-import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
-import { useApiHost } from '../../api';
-import { isNullOrUndefined } from '../../utils/objectUtils';
-
-import 'video.js/dist/video-js.css';
-
-import videojs from 'video.js';
-import type Player from 'video.js/dist/types/player';
-
-interface OnTimeUpdateEvent {
- timestamp: number;
- isPlaying: boolean;
-}
-
-interface HistoryVideoProps {
- id?: string;
- isPlaying: boolean;
- currentTime: number;
- onTimeUpdate?: (event: OnTimeUpdateEvent) => void;
- onPause: () => void;
- onPlay: () => void;
-}
-
-export const HistoryVideo = ({
- id,
- isPlaying: videoIsPlaying,
- currentTime,
- onTimeUpdate,
- onPause,
- onPlay,
-}: HistoryVideoProps) => {
- const apiHost = useApiHost();
- const videoRef = useRef(null);
-
- const [video, setVideo] = useState();
-
- useEffect(() => {
- let video: Player
- if (videoRef.current) {
- video = videojs(videoRef.current, {})
- setVideo(video)
- }
- () => video?.dispose()
- }, [videoRef]);
-
- useEffect(() => {
- if (!video) {
- return
- }
-
-
- if (!id) {
- video.pause()
- return
- }
-
- video.src({
- src: `${apiHost}vod/event/${id}/master.m3u8`,
- type: 'application/vnd.apple.mpegurl',
- });
- video.poster(`${apiHost}api/events/${id}/snapshot.jpg`);
- if (videoIsPlaying) {
- video.play();
- }
- }, [video, id, apiHost, videoIsPlaying]);
-
- useEffect(() => {
- const video = videoRef.current;
- const videoExists = !isNullOrUndefined(video);
- const hasSeeked = currentTime >= 0;
- if (video && videoExists && hasSeeked) {
- video.currentTime = currentTime;
- }
- }, [currentTime, videoRef]);
-
- const onTimeUpdateHandler = useCallback(
- (event: Event) => {
- const target = event.target as HTMLMediaElement;
- const timeUpdateEvent = {
- isPlaying: videoIsPlaying,
- timestamp: target.currentTime,
- };
- onTimeUpdate && onTimeUpdate(timeUpdateEvent);
- },
- [videoIsPlaying, onTimeUpdate]
- );
-
- useEffect(() => {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- if (video && (video as any).readyState() >= 1) {
- if (videoIsPlaying) {
- video.play()
- } else {
- video.pause()
- }
- }
- }, [video, videoIsPlaying])
-
- const onLoad = useCallback(() => {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- if (video && (video as any).readyState() >= 1 && videoIsPlaying) {
- video.play()
- }
- }, [video, videoIsPlaying])
-
- return (
-
-
-
- );
-};
diff --git a/web-old/src/components/HistoryViewer/HistoryViewer.tsx b/web-old/src/components/HistoryViewer/HistoryViewer.tsx
deleted file mode 100644
index 36aaaf7cf..000000000
--- a/web-old/src/components/HistoryViewer/HistoryViewer.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-import { Fragment, h } from 'preact';
-import { useCallback, useEffect, useState } from 'preact/hooks';
-import useSWR from 'swr';
-import axios from 'axios';
-import Timeline from '../Timeline/Timeline';
-import type { TimelineChangeEvent } from '../Timeline/TimelineChangeEvent';
-import type { TimelineEvent } from '../Timeline/TimelineEvent';
-import { HistoryHeader } from './HistoryHeader';
-import { HistoryVideo } from './HistoryVideo';
-
-export default function HistoryViewer({ camera }: {camera: string}) {
- const searchParams = {
- before: null,
- after: null,
- camera,
- label: 'all',
- zone: 'all',
- };
-
- // TODO: refactor
- const eventsFetcher = (path: string, params: {[name:string]: string|number}) => {
- params = { ...params, include_thumbnails: 0, limit: 500 };
- return axios.get(path, { params }).then((res) => res.data);
- };
-
- const { data: events } = useSWR(['events', searchParams], eventsFetcher);
-
- const [timelineEvents, setTimelineEvents] = useState([]);
- const [currentEvent, setCurrentEvent] = useState();
- const [isPlaying, setIsPlaying] = useState(false);
- const [currentTime, setCurrentTime] = useState(new Date().getTime());
-
- useEffect(() => {
- if (events) {
- const filteredEvents = [...events].reverse().filter((e) => e.end_time !== undefined);
- setTimelineEvents(filteredEvents);
- }
- }, [events]);
-
- const handleTimelineChange = useCallback(
- (event: TimelineChangeEvent) => {
- if (event.seekComplete) {
- setCurrentEvent(event.timelineEvent);
-
- if (isPlaying && event.timelineEvent) {
- const eventTime = (event.markerTime.getTime() - event.timelineEvent.startTime.getTime()) / 1000;
- setCurrentTime(eventTime);
- }
- }
- },
- [isPlaying]
- );
-
- const onPlayHandler = () => {
- setIsPlaying(true);
- };
-
- const onPausedHandler = () => {
- setIsPlaying(false);
- };
-
- const onPlayPauseHandler = (isPlaying: boolean) => {
- setIsPlaying(isPlaying);
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/web-old/src/components/JSMpegPlayer.jsx b/web-old/src/components/JSMpegPlayer.jsx
deleted file mode 100644
index c77f2530d..000000000
--- a/web-old/src/components/JSMpegPlayer.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { h } from 'preact';
-import { baseUrl } from '../api/baseUrl';
-import { useRef, useEffect } from 'preact/hooks';
-import JSMpeg from '@cycjimmy/jsmpeg-player';
-
-export default function JSMpegPlayer({ camera, width, height }) {
- const playerRef = useRef();
- const url = `${baseUrl.replace(/^http/, 'ws')}live/jsmpeg/${camera}`;
-
- useEffect(() => {
- const video = new JSMpeg.VideoElement(
- playerRef.current,
- url,
- {},
- {protocols: [], audio: false, videoBufferSize: 1024*1024*4}
- );
-
- const fullscreen = () => {
- if (video.els.canvas.webkitRequestFullScreen) {
- video.els.canvas.webkitRequestFullScreen();
- }
- else {
- video.els.canvas.mozRequestFullScreen();
- }
- };
-
- video.els.canvas.addEventListener('click',fullscreen);
-
- return () => {
- video.destroy();
- };
- }, [url]);
-
- return (
-
- );
-}
diff --git a/web-old/src/components/Link.jsx b/web-old/src/components/Link.jsx
deleted file mode 100644
index 3547996d7..000000000
--- a/web-old/src/components/Link.jsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { h } from 'preact';
-import { Link as RouterLink } from 'preact-router/match';
-
-export default function Link({
- activeClassName = '',
- className = 'text-blue-500 hover:underline',
- children,
- href,
- ...props
-}) {
- return (
-
- {children}
-
- );
-}
diff --git a/web-old/src/components/LinkedLogo.jsx b/web-old/src/components/LinkedLogo.jsx
deleted file mode 100644
index 4bf83aa9d..000000000
--- a/web-old/src/components/LinkedLogo.jsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { h } from 'preact';
-import Heading from './Heading';
-import Logo from './Logo';
-
-export default function LinkedLogo() {
- return (
-
-
-
-
-
- Frigate
-
-
- );
-}
diff --git a/web-old/src/components/LiveChip.jsx b/web-old/src/components/LiveChip.jsx
deleted file mode 100644
index 5173cdd53..000000000
--- a/web-old/src/components/LiveChip.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { h } from 'preact';
-
-export function LiveChip({ className }) {
- return (
-
- );
-}
diff --git a/web-old/src/components/Logo.jsx b/web-old/src/components/Logo.jsx
deleted file mode 100644
index de7f62731..000000000
--- a/web-old/src/components/Logo.jsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { h } from 'preact';
-
-export default function Logo() {
- return (
-
-
-
- );
-}
diff --git a/web-old/src/components/Menu.jsx b/web-old/src/components/Menu.jsx
deleted file mode 100644
index 34ff20326..000000000
--- a/web-old/src/components/Menu.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { h } from 'preact';
-import RelativeModal from './RelativeModal';
-import { useCallback } from 'preact/hooks';
-
-export default function Menu({ className, children, onDismiss, relativeTo, widthRelative }) {
- return relativeTo ? (
-
- ) : null;
-}
-
-export function MenuItem({ focus, icon: Icon, label, href, onSelect, value, ...attrs }) {
- const handleClick = useCallback(() => {
- onSelect && onSelect(value, label);
- }, [onSelect, value, label]);
-
- const Element = href ? 'a' : 'div';
-
- return (
-
- {Icon ? (
-
-
-
- ) : null}
- {label}
-
- );
-}
-
-export function MenuSeparator() {
- return
;
-}
diff --git a/web-old/src/components/MsePlayer.js b/web-old/src/components/MsePlayer.js
deleted file mode 100644
index 6607bc2f4..000000000
--- a/web-old/src/components/MsePlayer.js
+++ /dev/null
@@ -1,649 +0,0 @@
-class VideoRTC extends HTMLElement {
- constructor() {
- super();
-
- this.DISCONNECT_TIMEOUT = 5000;
- this.RECONNECT_TIMEOUT = 30000;
-
- this.CODECS = [
- 'avc1.640029', // H.264 high 4.1 (Chromecast 1st and 2nd Gen)
- 'avc1.64002A', // H.264 high 4.2 (Chromecast 3rd Gen)
- 'avc1.640033', // H.264 high 5.1 (Chromecast with Google TV)
- 'hvc1.1.6.L153.B0', // H.265 main 5.1 (Chromecast Ultra)
- 'mp4a.40.2', // AAC LC
- 'mp4a.40.5', // AAC HE
- 'flac', // FLAC (PCM compatible)
- 'opus', // OPUS Chrome, Firefox
- ];
-
- /**
- * [config] Supported modes (webrtc, mse, mp4, mjpeg).
- * @type {string}
- */
- this.mode = 'webrtc,mse,mp4,mjpeg';
-
- /**
- * [config] Run stream when not displayed on the screen. Default `false`.
- * @type {boolean}
- */
- this.background = false;
-
- /**
- * [config] Run stream only when player in the viewport. Stop when user scroll out player.
- * Value is percentage of visibility from `0` (not visible) to `1` (full visible).
- * Default `0` - disable;
- * @type {number}
- */
- this.visibilityThreshold = 0;
-
- /**
- * [config] Run stream only when browser page on the screen. Stop when user change browser
- * tab or minimise browser windows.
- * @type {boolean}
- */
- this.visibilityCheck = true;
-
- /**
- * [config] WebRTC configuration
- * @type {RTCConfiguration}
- */
- this.pcConfig = {
- iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
- sdpSemantics: 'unified-plan', // important for Chromecast 1
- };
-
- /**
- * [info] WebSocket connection state. Values: CONNECTING, OPEN, CLOSED
- * @type {number}
- */
- this.wsState = WebSocket.CLOSED;
-
- /**
- * [info] WebRTC connection state.
- * @type {number}
- */
- this.pcState = WebSocket.CLOSED;
-
- /**
- * @type {HTMLVideoElement}
- */
- this.video = null;
-
- /**
- * @type {WebSocket}
- */
- this.ws = null;
-
- /**
- * @type {string|URL}
- */
- this.wsURL = '';
-
- /**
- * @type {RTCPeerConnection}
- */
- this.pc = null;
-
- /**
- * @type {number}
- */
- this.connectTS = 0;
-
- /**
- * @type {string}
- */
- this.mseCodecs = '';
-
- /**
- * [internal] Disconnect TimeoutID.
- * @type {number}
- */
- this.disconnectTID = 0;
-
- /**
- * [internal] Reconnect TimeoutID.
- * @type {number}
- */
- this.reconnectTID = 0;
-
- /**
- * [internal] Handler for receiving Binary from WebSocket.
- * @type {Function}
- */
- this.ondata = null;
-
- /**
- * [internal] Handlers list for receiving JSON from WebSocket
- * @type {Object.}}
- */
- this.onmessage = null;
- }
-
- /**
- * Set video source (WebSocket URL). Support relative path.
- * @param {string|URL} value
- */
- set src(value) {
- if (typeof value !== 'string') value = value.toString();
- if (value.startsWith('http')) {
- value = `ws${value.substring(4)}`;
- } else if (value.startsWith('/')) {
- value = `ws${location.origin.substring(4)}${value}`;
- }
-
- this.wsURL = value;
-
- this.onconnect();
- }
-
- /**
- * Play video. Support automute when autoplay blocked.
- * https://developer.chrome.com/blog/autoplay/
- */
- play() {
- this.video.play().catch((er) => {
- if (er.name === 'NotAllowedError' && !this.video.muted) {
- this.video.muted = true;
- this.video.play().catch(() => { });
- }
- });
- }
-
- /**
- * Send message to server via WebSocket
- * @param {Object} value
- */
- send(value) {
- if (this.ws) this.ws.send(JSON.stringify(value));
- }
-
- /** @param {Function} isSupported */
- codecs(isSupported) {
- return this.CODECS.filter(codec => isSupported(`video/mp4; codecs="${codec}"`)).join();
- }
-
- /**
- * `CustomElement`. Invoked each time the custom element is appended into a
- * document-connected element.
- */
- connectedCallback() {
- if (this.disconnectTID) {
- clearTimeout(this.disconnectTID);
- this.disconnectTID = 0;
- }
-
- // because video autopause on disconnected from DOM
- if (this.video) {
- const seek = this.video.seekable;
- if (seek.length > 0) {
- this.video.currentTime = seek.end(seek.length - 1);
- }
- this.play();
- } else {
- this.oninit();
- }
-
- this.onconnect();
- }
-
- /**
- * `CustomElement`. Invoked each time the custom element is disconnected from the
- * document's DOM.
- */
- disconnectedCallback() {
- if (this.background || this.disconnectTID) return;
- if (this.wsState === WebSocket.CLOSED && this.pcState === WebSocket.CLOSED) return;
-
- this.disconnectTID = setTimeout(() => {
- if (this.reconnectTID) {
- clearTimeout(this.reconnectTID);
- this.reconnectTID = 0;
- }
-
- this.disconnectTID = 0;
-
- this.ondisconnect();
- }, this.DISCONNECT_TIMEOUT);
- }
-
- /**
- * Creates child DOM elements. Called automatically once on `connectedCallback`.
- */
- oninit() {
- this.video = document.createElement('video');
- this.video.controls = true;
- this.video.playsInline = true;
- this.video.preload = 'auto';
- this.video.muted = true;
-
- this.video.style.display = 'block'; // fix bottom margin 4px
- this.video.style.width = '100%';
- this.video.style.height = '100%';
-
- this.appendChild(this.video);
-
- if (this.background) return;
-
- if ('hidden' in document && this.visibilityCheck) {
- document.addEventListener('visibilitychange', () => {
- if (document.hidden) {
- this.disconnectedCallback();
- } else if (this.isConnected) {
- this.connectedCallback();
- }
- });
- }
-
- if ('IntersectionObserver' in window && this.visibilityThreshold) {
- const observer = new IntersectionObserver(
- (entries) => {
- entries.forEach((entry) => {
- if (!entry.isIntersecting) {
- this.disconnectedCallback();
- } else if (this.isConnected) {
- this.connectedCallback();
- }
- });
- },
- { threshold: this.visibilityThreshold }
- );
- observer.observe(this);
- }
- }
-
- /**
- * Connect to WebSocket. Called automatically on `connectedCallback`.
- * @return {boolean} true if the connection has started.
- */
- onconnect() {
- if (!this.isConnected || !this.wsURL || this.ws || this.pc) return false;
-
- // CLOSED or CONNECTING => CONNECTING
- this.wsState = WebSocket.CONNECTING;
-
- this.connectTS = Date.now();
-
- this.ws = new WebSocket(this.wsURL);
- this.ws.binaryType = 'arraybuffer';
- this.ws.addEventListener('open', (ev) => this.onopen(ev));
- this.ws.addEventListener('close', (ev) => this.onclose(ev));
-
- return true;
- }
-
- ondisconnect() {
- this.wsState = WebSocket.CLOSED;
- if (this.ws) {
- this.ws.close();
- this.ws = null;
- }
-
- this.pcState = WebSocket.CLOSED;
- if (this.pc) {
- this.pc.close();
- this.pc = null;
- }
- }
-
- /**
- * @returns {Array.} of modes (mse, webrtc, etc.)
- */
- onopen() {
- // CONNECTING => OPEN
- this.wsState = WebSocket.OPEN;
-
- this.ws.addEventListener('message', (ev) => {
- if (typeof ev.data === 'string') {
- const msg = JSON.parse(ev.data);
- for (const mode in this.onmessage) {
- this.onmessage[mode](msg);
- }
- } else {
- this.ondata(ev.data);
- }
- });
-
- this.ondata = null;
- this.onmessage = {};
-
- const modes = [];
-
- if (this.mode.indexOf('mse') >= 0 && ('MediaSource' in window || 'ManagedMediaSource' in window)) {
- // iPhone
- modes.push('mse');
- this.onmse();
- } else if (this.mode.indexOf('mp4') >= 0) {
- modes.push('mp4');
- this.onmp4();
- }
-
- if (this.mode.indexOf('webrtc') >= 0 && 'RTCPeerConnection' in window) {
- // macOS Desktop app
- modes.push('webrtc');
- this.onwebrtc();
- }
-
- if (this.mode.indexOf('mjpeg') >= 0) {
- if (modes.length) {
- this.onmessage['mjpeg'] = (msg) => {
- if (msg.type !== 'error' || msg.value.indexOf(modes[0]) !== 0) return;
- this.onmjpeg();
- };
- } else {
- modes.push('mjpeg');
- this.onmjpeg();
- }
- }
-
- return modes;
- }
-
- /**
- * @return {boolean} true if reconnection has started.
- */
- onclose() {
- if (this.wsState === WebSocket.CLOSED) return false;
-
- // CONNECTING, OPEN => CONNECTING
- this.wsState = WebSocket.CONNECTING;
- this.ws = null;
-
- // reconnect no more than once every X seconds
- const delay = Math.max(this.RECONNECT_TIMEOUT - (Date.now() - this.connectTS), 0);
-
- this.reconnectTID = setTimeout(() => {
- this.reconnectTID = 0;
- this.onconnect();
- }, delay);
-
- return true;
- }
-
- onmse() {
- /** @type {MediaSource} */
- let ms;
-
- if ('ManagedMediaSource' in window) {
- const MediaSource = window.ManagedMediaSource;
-
- ms = new MediaSource();
- ms.addEventListener('sourceopen', () => {
- this.send({type: 'mse', value: this.codecs(MediaSource.isTypeSupported)});
- }, {once: true});
-
- this.video.disableRemotePlayback = true;
- this.video.srcObject = ms;
- } else {
- ms = new MediaSource();
- ms.addEventListener('sourceopen', () => {
- URL.revokeObjectURL(this.video.src);
- this.send({type: 'mse', value: this.codecs(MediaSource.isTypeSupported)});
- }, {once: true});
-
- this.video.src = URL.createObjectURL(ms);
- this.video.srcObject = null;
- }
- this.play();
-
- this.mseCodecs = '';
-
- this.onmessage['mse'] = (msg) => {
- if (msg.type !== 'mse') return;
-
- this.mseCodecs = msg.value;
-
- const sb = ms.addSourceBuffer(msg.value);
- sb.mode = 'segments'; // segments or sequence
- sb.addEventListener('updateend', () => {
- if (sb.updating) return;
-
- try {
- if (bufLen > 0) {
- const data = buf.slice(0, bufLen);
- bufLen = 0;
- sb.appendBuffer(data);
- } else if (sb.buffered && sb.buffered.length) {
- const end = sb.buffered.end(sb.buffered.length - 1) - 15;
- const start = sb.buffered.start(0);
- if (end > start) {
- sb.remove(start, end);
- ms.setLiveSeekableRange(end, end + 15);
- }
- // console.debug("VideoRTC.buffered", start, end);
- }
- } catch (e) {
- // console.debug(e);
- }
- });
-
- const buf = new Uint8Array(2 * 1024 * 1024);
- let bufLen = 0;
-
- this.ondata = (data) => {
- if (sb.updating || bufLen > 0) {
- const b = new Uint8Array(data);
- buf.set(b, bufLen);
- bufLen += b.byteLength;
- // console.debug("VideoRTC.buffer", b.byteLength, bufLen);
- } else {
- try {
- sb.appendBuffer(data);
- } catch (e) {
- // console.debug(e);
- }
- }
- };
- };
- }
-
- onwebrtc() {
- const pc = new RTCPeerConnection(this.pcConfig);
-
- /** @type {HTMLVideoElement} */
- const video2 = document.createElement('video');
- video2.addEventListener('loadeddata', (ev) => this.onpcvideo(ev), { once: true });
-
- pc.addEventListener('icecandidate', (ev) => {
- const candidate = ev.candidate ? ev.candidate.toJSON().candidate : '';
- this.send({ type: 'webrtc/candidate', value: candidate });
- });
-
- pc.addEventListener('track', (ev) => {
- // when stream already init
- if (video2.srcObject !== null) return;
-
- // when audio track not exist in Chrome
- if (ev.streams.length === 0) return;
-
- // when audio track not exist in Firefox
- if (ev.streams[0].id[0] === '{') return;
-
- video2.srcObject = ev.streams[0];
- });
-
- pc.addEventListener('connectionstatechange', () => {
- if (pc.connectionState === 'failed' || pc.connectionState === 'disconnected') {
- pc.close(); // stop next events
-
- this.pcState = WebSocket.CLOSED;
- this.pc = null;
-
- this.onconnect();
- }
- });
-
- this.onmessage['webrtc'] = (msg) => {
- switch (msg.type) {
- case 'webrtc/candidate':
- pc.addIceCandidate({
- candidate: msg.value,
- sdpMid: '0',
- }).catch(() => { });
- break;
- case 'webrtc/answer':
- pc.setRemoteDescription({
- type: 'answer',
- sdp: msg.value,
- }).catch(() => { });
- break;
- case 'error':
- if (msg.value.indexOf('webrtc/offer') < 0) return;
- pc.close();
- }
- };
-
- // Safari doesn't support "offerToReceiveVideo"
- pc.addTransceiver('video', { direction: 'recvonly' });
- pc.addTransceiver('audio', { direction: 'recvonly' });
-
- pc.createOffer().then((offer) => {
- pc.setLocalDescription(offer).then(() => {
- this.send({ type: 'webrtc/offer', value: offer.sdp });
- });
- });
-
- this.pcState = WebSocket.CONNECTING;
- this.pc = pc;
- }
-
- /**
- * @param ev {Event}
- */
- onpcvideo(ev) {
- if (!this.pc) return;
-
- /** @type {HTMLVideoElement} */
- const video2 = ev.target;
- const state = this.pc.connectionState;
-
- // Firefox doesn't support pc.connectionState
- if (state === 'connected' || state === 'connecting' || !state) {
- // Video+Audio > Video, H265 > H264, Video > Audio, WebRTC > MSE
- let rtcPriority = 0,
- msePriority = 0;
-
- /** @type {MediaStream} */
- const ms = video2.srcObject;
- if (ms.getVideoTracks().length > 0) rtcPriority += 0x220;
- if (ms.getAudioTracks().length > 0) rtcPriority += 0x102;
-
- if (this.mseCodecs.indexOf('hvc1.') >= 0) msePriority += 0x230;
- if (this.mseCodecs.indexOf('avc1.') >= 0) msePriority += 0x210;
- if (this.mseCodecs.indexOf('mp4a.') >= 0) msePriority += 0x101;
-
- if (rtcPriority >= msePriority) {
- this.video.srcObject = ms;
- this.play();
-
- this.pcState = WebSocket.OPEN;
-
- this.wsState = WebSocket.CLOSED;
- this.ws.close();
- this.ws = null;
- } else {
- this.pcState = WebSocket.CLOSED;
- this.pc.close();
- this.pc = null;
- }
- }
-
- video2.srcObject = null;
- }
-
- onmjpeg() {
- this.ondata = (data) => {
- this.video.controls = false;
- this.video.poster = `data:image/jpeg;base64,${VideoRTC.btoa(data)}`;
- };
-
- this.send({ type: 'mjpeg' });
- }
-
- onmp4() {
- /** @type {HTMLCanvasElement} **/
- const canvas = document.createElement('canvas');
- /** @type {CanvasRenderingContext2D} */
- let context;
-
- /** @type {HTMLVideoElement} */
- const video2 = document.createElement('video');
- video2.autoplay = true;
- video2.playsInline = true;
- video2.muted = true;
-
- video2.addEventListener('loadeddata', (_) => {
- if (!context) {
- canvas.width = video2.videoWidth;
- canvas.height = video2.videoHeight;
- context = canvas.getContext('2d');
- }
-
- context.drawImage(video2, 0, 0, canvas.width, canvas.height);
-
- this.video.controls = false;
- this.video.poster = canvas.toDataURL('image/jpeg');
- });
-
- this.ondata = (data) => {
- video2.src = `data:video/mp4;base64,${VideoRTC.btoa(data)}`;
- };
-
- this.send({ type: 'mp4', value: this.codecs(this.video.canPlayType) });
- }
-
- static btoa(buffer) {
- const bytes = new Uint8Array(buffer);
- const len = bytes.byteLength;
- let binary = '';
- for (let i = 0; i < len; i++) {
- binary += String.fromCharCode(bytes[i]);
- }
- return window.btoa(binary);
- }
-}
-
-class VideoStream extends VideoRTC {
-
-
- /**
- * Custom GUI
- */
- oninit() {
- super.oninit();
- const info = this.querySelector('.info');
- this.insertBefore(this.video, info);
- }
-
- onconnect() {
- const result = super.onconnect();
- if (result) this.divMode = 'loading';
- return result;
- }
-
- ondisconnect() {;
- super.ondisconnect();
- }
-
- onopen() {
- const result = super.onopen();
-
- this.onmessage['stream'] = (_) => {
- };
-
- return result;
- }
-
- onclose() {
- return super.onclose();
- }
-
- onpcvideo(ev) {
- super.onpcvideo(ev);
-
- if (this.pcState !== WebSocket.CLOSED) {
- this.divMode = 'RTC';
- }
- }
-}
-
-customElements.define('video-stream', VideoStream);
diff --git a/web-old/src/components/MultiSelect.jsx b/web-old/src/components/MultiSelect.jsx
deleted file mode 100644
index 5c706fd24..000000000
--- a/web-old/src/components/MultiSelect.jsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import { h } from 'preact';
-import { useRef, useState } from 'preact/hooks';
-import Menu from './Menu';
-import { ArrowDropdown } from '../icons/ArrowDropdown';
-import Heading from './Heading';
-import Button from './Button';
-import SelectOnlyIcon from '../icons/SelectOnly';
-
-export default function MultiSelect({ className, title, options, selection, onToggle, onShowAll, onSelectSingle }) {
- const popupRef = useRef(null);
-
- const [state, setState] = useState({
- showMenu: false,
- });
-
- const isOptionSelected = (item) => {
- return selection == 'all' || selection.split(',').indexOf(item) > -1;
- };
-
- const menuHeight = Math.round(window.innerHeight * 0.55);
- return (
-
-
setState({ showMenu: true })}>
-
{title}
-
-
- {state.showMenu ? (
-
setState({ showMenu: false })}
- >
-
-
- {title}
-
- onShowAll()}>
- Show All
-
-
- {options.map((item) => (
-
-
- onToggle(item)}
- />
- {item.replaceAll('_', ' ')}
-
-
- onSelectSingle(item)}
- >
- { ( ) }
-
-
-
- ))}
-
- ) : null}
-
- );
-}
diff --git a/web-old/src/components/NavigationDrawer.jsx b/web-old/src/components/NavigationDrawer.jsx
deleted file mode 100644
index 04397c429..000000000
--- a/web-old/src/components/NavigationDrawer.jsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { h, Fragment } from 'preact';
-import { Link } from 'preact-router/match';
-import { useCallback } from 'preact/hooks';
-import { useDrawer } from '../context';
-
-export default function NavigationDrawer({ children, header }) {
- const { showDrawer, setShowDrawer } = useDrawer();
-
- const handleDismiss = useCallback(() => {
- setShowDrawer(false);
- }, [setShowDrawer]);
-
- return (
-
- {showDrawer ?
: ''}
-
- {header ? (
-
- {header}
-
- ) : null}
-
-
{children}
-
-
- );
-}
-
-export function Destination({ className = '', href, text, ...other }) {
- const external = href.startsWith('http');
- const props = external ? { rel: 'noopener nofollow', target: '_blank' } : {};
-
- const { setShowDrawer } = useDrawer();
-
- const handleDismiss = useCallback(() => {
- setTimeout(() => {
- setShowDrawer(false);
- }, 250);
- }, [setShowDrawer]);
-
- const styleProps = {
- [external
- ? className
- : 'class']: 'block p-2 text-sm font-semibold text-gray-900 rounded hover:bg-blue-500 dark:text-gray-200 hover:text-white dark:hover:text-white focus:outline-none ring-opacity-50 focus:ring-2 ring-blue-300',
- };
-
- const El = external ? 'a' : Link;
-
- return (
-
- {text}
-
- );
-}
-
-export function Separator() {
- return
;
-}
diff --git a/web-old/src/components/Prompt.jsx b/web-old/src/components/Prompt.jsx
deleted file mode 100644
index 689fc0fdf..000000000
--- a/web-old/src/components/Prompt.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { h } from 'preact';
-import Button from './Button';
-import Heading from './Heading';
-import Dialog from './Dialog';
-
-export default function Prompt({ actions = [], title, text }) {
- return (
-
-
-
- {actions.map(({ color, text, onClick, ...props }, i) => (
-
- {text}
-
- ))}
-
-
- );
-}
diff --git a/web-old/src/components/RecordingPlaylist.jsx b/web-old/src/components/RecordingPlaylist.jsx
deleted file mode 100644
index 7eaea1b04..000000000
--- a/web-old/src/components/RecordingPlaylist.jsx
+++ /dev/null
@@ -1,176 +0,0 @@
-import { h } from 'preact';
-import { useState, useMemo } from 'preact/hooks';
-import {
- getUnixTime,
- fromUnixTime,
- format,
- parseISO,
- intervalToDuration,
- formatDuration,
- endOfDay,
- startOfDay,
- isSameDay,
-} from 'date-fns';
-import ArrowDropdown from '../icons/ArrowDropdown';
-import ArrowDropup from '../icons/ArrowDropup';
-import Link from '../components/Link';
-import ActivityIndicator from '../components/ActivityIndicator';
-import Menu from '../icons/Menu';
-import MenuOpen from '../icons/MenuOpen';
-import { useApiHost } from '../api';
-import useSWR from 'swr';
-
-export default function RecordingPlaylist({ camera, recordings, selectedDate }) {
- const [active, setActive] = useState(true);
- const toggle = () => setActive(!active);
-
- const result = [];
- for (const recording of recordings) {
- const date = parseISO(recording.day);
- result.push(
-
-
-
- );
- }
-
- const openClass = active ? '-left-6' : 'right-0';
-
- return (
-
-
- {active ?
: }
-
-
- {result}
-
-
- );
-}
-
-export function DayOfEvents({ camera, day, hours }) {
- const date = parseISO(day);
- const { data: events } = useSWR([
- `events`,
- {
- before: getUnixTime(endOfDay(date)),
- after: getUnixTime(startOfDay(date)),
- camera,
- has_clip: '1',
- include_thumbnails: 0,
- limit: 5000,
- },
- ]);
-
- // maps all the events under the keys for the hour by hour recordings view
- const eventMap = useMemo(() => {
- const eventMap = {};
- for (const hour of hours) {
- eventMap[`${day}-${hour.hour}`] = [];
- }
-
- if (!events) {
- return eventMap;
- }
-
- for (const event of events) {
- const key = format(fromUnixTime(event.start_time), 'yyyy-MM-dd-HH');
- // if the hour of recordings is missing for the event start time, skip it
- if (key in eventMap) {
- eventMap[key].push(event);
- }
- }
-
- return eventMap;
- }, [events, day, hours]);
-
- if (!events) {
- return ;
- }
-
- return (
- <>
- {hours.map((hour, i) => (
-
-
-
-
- {hour.hour}:00
-
-
-
{hour.events} Events
-
- {eventMap[`${day}-${hour.hour}`].map((event) => (
-
- ))}
-
- ))}
- >
- );
-}
-
-export function ExpandableList({ title, events = 0, children, selected = false }) {
- const [active, setActive] = useState(selected);
- const toggle = () => setActive(!active);
- return (
-
-
-
{title}
-
{events} Events
-
-
- {/* Only render the child when expanded to lazy load events for the day */}
- {active &&
{children}
}
-
- );
-}
-
-export function EventCard({ camera, event }) {
- const apiHost = useApiHost();
- const start = fromUnixTime(event.start_time);
- const end = fromUnixTime(event.end_time);
- let duration = 'In Progress';
- if (event.end_time) {
- duration = formatDuration(intervalToDuration({ start, end }));
- }
-
- return (
-
-
-
-
-
-
-
-
-
-
{event.label}
-
Start: {format(start, 'HH:mm:ss')}
-
Duration: {duration}
-
-
- {((event?.data?.top_score || event.top_score) * 100).toFixed(1)}%
-
-
-
-
-
-
-
- );
-}
diff --git a/web-old/src/components/RelativeModal.jsx b/web-old/src/components/RelativeModal.jsx
deleted file mode 100644
index 6ccfccbe1..000000000
--- a/web-old/src/components/RelativeModal.jsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import { h, Fragment } from 'preact';
-import { createPortal } from 'preact/compat';
-import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
-
-const WINDOW_PADDING = 20;
-
-export default function RelativeModal({
- className,
- role = 'dialog',
- children,
- onDismiss,
- portalRootID,
- relativeTo,
- widthRelative = false,
-}) {
- const [position, setPosition] = useState({ top: -9999, left: -9999 });
- const [show, setShow] = useState(false);
- const portalRoot = portalRootID && document.getElementById(portalRootID);
- const ref = useRef(null);
-
- const handleDismiss = useCallback(
- (event) => {
- onDismiss && onDismiss(event);
- },
- [onDismiss]
- );
-
- const handleKeydown = useCallback(
- (event) => {
- const focusable = ref.current && ref.current.querySelectorAll('[tabindex]');
- if (event.key === 'Tab' && focusable.length) {
- if (event.shiftKey && document.activeElement === focusable[0]) {
- focusable[focusable.length - 1].focus();
- event.preventDefault();
- } else if (document.activeElement === focusable[focusable.length - 1]) {
- focusable[0].focus();
- event.preventDefault();
- }
- return;
- }
-
- if (event.key === 'Escape') {
- setShow(false);
- handleDismiss();
- return;
- }
- },
- [ref, handleDismiss]
- );
-
- useLayoutEffect(() => {
- if (ref && ref.current && relativeTo && relativeTo.current) {
- const windowWidth = window.innerWidth;
- const windowHeight = window.innerHeight;
- const { width: menuWidth, height: menuHeight } = ref.current.getBoundingClientRect();
- const {
- x: relativeToX,
- y: relativeToY,
- width: relativeToWidth,
- height: relativeToHeight,
- } = relativeTo.current.getBoundingClientRect();
-
- const _width = widthRelative ? relativeToWidth : menuWidth;
- const width = _width * 1.1;
-
- const left = relativeToX + window.scrollX;
- const top = relativeToY + window.scrollY;
-
- let newTop = top;
- let newLeft = left;
-
- // too far left
- if (left < WINDOW_PADDING) {
- newLeft = WINDOW_PADDING;
- }
- // too far right
- else if (newLeft + width + WINDOW_PADDING >= windowWidth - WINDOW_PADDING) {
- newLeft = windowWidth - width - WINDOW_PADDING;
- }
-
- // This condition checks if the menu overflows the bottom of the page and
- // if there's enough space to position the menu above the clicked icon.
- // If both conditions are met, the menu will be positioned above the clicked icon
- if (
- top + menuHeight > windowHeight - WINDOW_PADDING + window.scrollY &&
- top - menuHeight - relativeToHeight >= WINDOW_PADDING
- ) {
- newTop = top - menuHeight;
- }
-
- if (top <= WINDOW_PADDING + window.scrollY) {
- newTop = WINDOW_PADDING;
- }
-
- // This calculation checks if there's enough space below the clicked icon for the menu to fit.
- // If there is, it sets the maxHeight to null(meaning no height constraint). If not, it calculates the maxHeight based on the remaining space in the window
- const maxHeight =
- windowHeight - WINDOW_PADDING * 2 - top > menuHeight
- ? null
- : windowHeight - WINDOW_PADDING * 2 - top + window.scrollY;
-
- const newPosition = { left: newLeft, top: newTop, maxHeight };
- if (widthRelative) {
- newPosition.width = relativeToWidth;
- }
- setPosition(newPosition);
- const focusable = ref.current.querySelector('[tabindex]');
- focusable && focusable.focus();
- }
- }, [relativeTo, ref, widthRelative]);
-
- useEffect(() => {
- if (position.top >= 0) {
- window.requestAnimationFrame(() => {
- setShow(true);
- });
- } else {
- setShow(false);
- }
- }, [show, position, ref]);
-
- const menu = (
-
-
-
- {children}
-
-
- );
-
- return portalRoot ? createPortal(menu, portalRoot) : menu;
-}
diff --git a/web-old/src/components/Select.jsx b/web-old/src/components/Select.jsx
deleted file mode 100644
index 300cf6faa..000000000
--- a/web-old/src/components/Select.jsx
+++ /dev/null
@@ -1,256 +0,0 @@
-import { h, Fragment } from 'preact';
-import ArrowDropdown from '../icons/ArrowDropdown';
-import ArrowDropup from '../icons/ArrowDropup';
-import Menu, { MenuItem } from './Menu';
-import TextField from './TextField';
-import DatePicker from './DatePicker';
-import Calendar from './Calendar';
-import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks';
-
-export default function Select({
- type,
- label,
- onChange,
- paramName,
- options: inputOptions = [],
- selected: propSelected,
-}) {
- const options = useMemo(
- () =>
- typeof inputOptions[0] === 'string' ? inputOptions.map((opt) => ({ value: opt, label: opt })) : inputOptions,
- [inputOptions]
- );
-
- const [showMenu, setShowMenu] = useState(false);
- const [selected, setSelected] = useState();
- const [datePickerValue, setDatePickerValue] = useState();
-
- // Reset the state if the prop value changes
- useEffect(() => {
- const selectedIndex = Math.max(
- options.findIndex(({ value }) => value === propSelected),
- 0
- );
- if (propSelected && selectedIndex !== selected) {
- setSelected(selectedIndex);
- setFocused(selectedIndex);
- }
- // DO NOT include `selected`
- }, [options, propSelected]); // eslint-disable-line react-hooks/exhaustive-deps
-
- useEffect(() => {
- if (type === 'datepicker') {
- if ('after' && 'before' in propSelected) {
- if (!propSelected.before || !propSelected.after) return setDatePickerValue('all');
-
- for (let i = 0; i < inputOptions.length; i++) {
- if (
- inputOptions[i].value &&
- Object.entries(inputOptions[i].value).sort().toString() === Object.entries(propSelected).sort().toString()
- ) {
- setDatePickerValue(inputOptions[i]?.label);
- break;
- } else {
- setDatePickerValue(
- `${new Date(propSelected.after * 1000).toLocaleDateString()} -> ${new Date(
- propSelected.before * 1000 - 1
- ).toLocaleDateString()}`
- );
- }
- }
- }
- }
- if (type === 'dropdown') {
- setSelected(
- Math.max(
- options.findIndex(({ value }) => Object.values(propSelected).includes(value)),
- 0
- )
- );
- }
- }, [type, options, inputOptions, propSelected, setSelected]);
-
- const [focused, setFocused] = useState(null);
- const [showCalendar, setShowCalendar] = useState(false);
- const calendarRef = useRef(null);
- const ref = useRef(null);
-
- const handleSelect = useCallback(
- (value) => {
- setSelected(options.findIndex(({ value }) => Object.values(propSelected).includes(value)));
- setShowMenu(false);
-
- //show calendar date range picker
- if (value === 'custom_range') return setShowCalendar(true);
- onChange && onChange(value);
- },
- [onChange, options, propSelected, setSelected]
- );
-
- const handleDateRange = useCallback(
- (range) => {
- onChange && onChange(range);
- setShowMenu(false);
- },
- [onChange]
- );
-
- const handleClick = useCallback(() => {
- setShowMenu(true);
- }, [setShowMenu]);
-
- const handleKeydownDatePicker = useCallback(
- (event) => {
- switch (event.key) {
- case 'Enter': {
- if (!showMenu) {
- setShowMenu(true);
- setFocused(selected);
- } else {
- setSelected(focused);
- if (options[focused].value === 'custom_range') {
- setShowMenu(false);
- return setShowCalendar(true);
- }
-
- onChange && onChange(options[focused].value);
- setShowMenu(false);
- }
- break;
- }
-
- case 'ArrowDown': {
- event.preventDefault();
- const newIndex = focused + 1;
- newIndex < options.length && setFocused(newIndex);
- break;
- }
-
- case 'ArrowUp': {
- event.preventDefault();
- const newIndex = focused - 1;
- newIndex > -1 && setFocused(newIndex);
- break;
- }
-
- // no default
- }
- },
- [onChange, options, showMenu, setShowMenu, setFocused, focused, selected]
- );
-
- const handleKeydown = useCallback(
- (event) => {
- switch (event.key) {
- case 'Enter': {
- if (!showMenu) {
- setShowMenu(true);
- setFocused(selected);
- } else {
- setSelected(focused);
- onChange && onChange({ [paramName]: options[focused].value });
- setShowMenu(false);
- }
- break;
- }
-
- case 'ArrowDown': {
- event.preventDefault();
- const newIndex = focused + 1;
- newIndex < options.length && setFocused(newIndex);
- break;
- }
-
- case 'ArrowUp': {
- event.preventDefault();
- const newIndex = focused - 1;
- newIndex > -1 && setFocused(newIndex);
- break;
- }
-
- // no default
- }
- },
- [onChange, options, showMenu, setShowMenu, setFocused, focused, selected, paramName]
- );
-
- const handleDismiss = useCallback(() => {
- setShowMenu(false);
- }, [setShowMenu]);
-
- const findDOMNodes = (component) => {
- return (component && (component.base || (component.nodeType === 1 && component))) || null;
- };
-
- useEffect(() => {
- const addBackDrop = (e) => {
- if (showCalendar && !findDOMNodes(calendarRef.current).contains(e.target)) {
- setShowCalendar(false);
- }
- };
- window.addEventListener('click', addBackDrop);
-
- return function cleanup() {
- window.removeEventListener('click', addBackDrop);
- };
- }, [showCalendar]);
-
- switch (type) {
- case 'datepicker':
- return (
-
-
- {showCalendar && (
-
- setShowCalendar(false)} />
-
- )}
- {showMenu ? (
-
- {options.map(({ value, label }, i) => (
-
- ))}
-
- ) : null}
-
- );
-
- // case 'dropdown':
- default:
- return (
-
-
- {showMenu ? (
-
- {options.map(({ value, label }, i) => (
-
- ))}
-
- ) : null}
-
- );
- }
-}
diff --git a/web-old/src/components/Switch.jsx b/web-old/src/components/Switch.jsx
deleted file mode 100644
index db040f4a5..000000000
--- a/web-old/src/components/Switch.jsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import { h } from 'preact';
-import { useCallback, useState } from 'preact/hooks';
-
-export default function Switch({ className, checked, id, onChange, label, labelPosition = 'before' }) {
- const [isFocused, setFocused] = useState(false);
-
- const handleChange = useCallback(() => {
- if (onChange) {
- onChange(id, !checked);
- }
- }, [id, onChange, checked]);
-
- const handleFocus = useCallback(() => {
- onChange && setFocused(true);
- }, [onChange, setFocused]);
-
- const handleBlur = useCallback(() => {
- onChange && setFocused(false);
- }, [onChange, setFocused]);
-
- return (
-
- {label && labelPosition === 'before' ? (
-
- {label}
-
- ) : null}
-
- {label && labelPosition !== 'before' ? (
-
- {label}
-
- ) : null}
-
- );
-}
diff --git a/web-old/src/components/Table.jsx b/web-old/src/components/Table.jsx
deleted file mode 100644
index eb5a1431c..000000000
--- a/web-old/src/components/Table.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { h } from 'preact';
-
-export function Table({ children, className = '' }) {
- return (
-
- );
-}
-
-export function Thead({ children, className, ...attrs }) {
- return (
-
- {children}
-
- );
-}
-
-export function Tbody({ children, className, reference, ...attrs }) {
- return (
-
- {children}
-
- );
-}
-
-export function Tfoot({ children, className = '', ...attrs }) {
- return (
-
- {children}
-
- );
-}
-
-export function Tr({ children, className = '', reference, ...attrs }) {
- return (
-
- {children}
-
- );
-}
-
-export function Th({ children, className = '', colspan, ...attrs }) {
- return (
-
- {children}
-
- );
-}
-
-export function Td({ children, className = '', reference, colspan, ...attrs }) {
- return (
-
- {children}
-
- );
-}
diff --git a/web-old/src/components/Tabs.jsx b/web-old/src/components/Tabs.jsx
deleted file mode 100644
index 2e14227fb..000000000
--- a/web-old/src/components/Tabs.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { h } from 'preact';
-import { useCallback, useState } from 'preact/hooks';
-
-export function Tabs({ children, selectedIndex: selectedIndexProp, onChange, className }) {
- const [selectedIndex, setSelectedIndex] = useState(selectedIndexProp);
-
- const handleSelected = useCallback(
- (index) => () => {
- setSelectedIndex(index);
- onChange && onChange(index);
- },
- [onChange]
- );
-
- const RenderChildren = useCallback(() => {
- return children.map((child, i) => {
- child.props.selected = i === selectedIndex;
- child.props.onClick = handleSelected(i);
- return child;
- });
- }, [selectedIndex, children, handleSelected]);
-
- return (
-
-
-
- );
-}
-
-export function TextTab({ selected, text, onClick, disabled }) {
- const selectedStyle = disabled
- ? 'text-gray-400 dark:text-gray-600 bg-transparent'
- : selected
- ? 'text-white bg-blue-500 dark:text-black dark:bg-white'
- : 'text-black dark:text-white bg-transparent';
- return (
-
- {text}
-
- );
-}
diff --git a/web-old/src/components/TextField.jsx b/web-old/src/components/TextField.jsx
deleted file mode 100644
index 8dd3540c0..000000000
--- a/web-old/src/components/TextField.jsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import { h } from 'preact';
-import { useCallback, useEffect, useState } from 'preact/hooks';
-
-export default function TextField({
- helpText,
- keyboardType = 'text',
- inputRef,
- label,
- leadingIcon: LeadingIcon,
- onBlur,
- onChangeText,
- onFocus,
- readonly,
- trailingIcon: TrailingIcon,
- value: propValue = '',
- ...props
-}) {
- const [isFocused, setFocused] = useState(false);
- const [value, setValue] = useState(propValue);
-
- const handleFocus = useCallback(
- (event) => {
- setFocused(true);
- onFocus && onFocus(event);
- },
- [onFocus]
- );
-
- const handleBlur = useCallback(
- (event) => {
- setFocused(false);
- onBlur && onBlur(event);
- },
- [onBlur]
- );
-
- const handleChange = useCallback(
- (event) => {
- const { value } = event.target;
- setValue(value);
- onChangeText && onChangeText(value);
- },
- [onChangeText, setValue]
- );
-
- useEffect(() => {
- if (propValue !== value) {
- setValue(propValue);
- }
- // DO NOT include `value`
- }, [propValue, setValue]); // eslint-disable-line react-hooks/exhaustive-deps
-
- const labelMoved = isFocused || value !== '';
-
- return (
-
-
-
- {LeadingIcon ? (
-
-
-
- ) : null}
-
- {TrailingIcon ? (
-
-
-
- ) : null}
-
-
- {helpText ?
{helpText}
: null}
-
- );
-}
diff --git a/web-old/src/components/TimeAgo.tsx b/web-old/src/components/TimeAgo.tsx
deleted file mode 100644
index b7ed45007..000000000
--- a/web-old/src/components/TimeAgo.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import { h, FunctionComponent } from 'preact';
-import { useEffect, useMemo, useState } from 'preact/hooks';
-
-interface IProp {
- /** The time to calculate time-ago from */
- time: Date;
- /** OPTIONAL: overwrite current time */
- currentTime?: Date;
- /** OPTIONAL: boolean that determines whether to show the time-ago text in dense format */
- dense?: boolean;
- /** OPTIONAL: set custom refresh interval in milliseconds, default 1000 (1 sec) */
- refreshInterval?: number;
-}
-
-type TimeUnit = {
- unit: string;
- full: string;
- value: number;
-};
-
-const timeAgo = ({ time, currentTime = new Date(), dense = false }: IProp): string => {
- if (typeof time !== 'number' || time < 0) return 'Invalid Time Provided';
-
- const pastTime: Date = new Date(time);
- const elapsedTime: number = currentTime.getTime() - pastTime.getTime();
-
- const timeUnits: TimeUnit[] = [
- { unit: 'yr', full: 'year', value: 31536000 },
- { unit: 'mo', full: 'month', value: 0 },
- { unit: 'd', full: 'day', value: 86400 },
- { unit: 'h', full: 'hour', value: 3600 },
- { unit: 'm', full: 'minute', value: 60 },
- { unit: 's', full: 'second', value: 1 },
- ];
-
- const elapsed: number = elapsedTime / 1000;
- if (elapsed < 10) {
- return 'just now';
- }
-
- for (let i = 0; i < timeUnits.length; i++) {
- // if months
- if (i === 1) {
- // Get the month and year for the time provided
- const pastMonth = pastTime.getUTCMonth();
- const pastYear = pastTime.getUTCFullYear();
-
- // get current month and year
- const currentMonth = currentTime.getUTCMonth();
- const currentYear = currentTime.getUTCFullYear();
-
- let monthDiff = (currentYear - pastYear) * 12 + (currentMonth - pastMonth);
-
- // check if the time provided is the previous month but not exceeded 1 month ago.
- if (currentTime.getUTCDate() < pastTime.getUTCDate()) {
- monthDiff--;
- }
-
- if (monthDiff > 0) {
- const unitAmount = monthDiff;
- return `${unitAmount}${dense ? timeUnits[i].unit : ` ${timeUnits[i].full}`}${dense ? '' : 's'} ago`;
- }
- } else if (elapsed >= timeUnits[i].value) {
- const unitAmount: number = Math.floor(elapsed / timeUnits[i].value);
- return `${unitAmount}${dense ? timeUnits[i].unit : ` ${timeUnits[i].full}`}${dense ? '' : 's'} ago`;
- }
- }
- return 'Invalid Time';
-};
-
-const TimeAgo: FunctionComponent = ({ refreshInterval = 1000, ...rest }): JSX.Element => {
- const [currentTime, setCurrentTime] = useState(new Date());
- useEffect(() => {
- const intervalId: NodeJS.Timeout = setInterval(() => {
- setCurrentTime(new Date());
- }, refreshInterval);
- return () => clearInterval(intervalId);
- }, [refreshInterval]);
-
- const timeAgoValue = useMemo(() => timeAgo({ currentTime, ...rest }), [currentTime, rest]);
-
- return {timeAgoValue} ;
-};
-export default TimeAgo;
diff --git a/web-old/src/components/TimePicker.jsx b/web-old/src/components/TimePicker.jsx
deleted file mode 100644
index 4a70e9c29..000000000
--- a/web-old/src/components/TimePicker.jsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import { h } from 'preact';
-import { useState } from 'preact/hooks';
-import { ArrowDropdown } from '../icons/ArrowDropdown';
-import { ArrowDropup } from '../icons/ArrowDropup';
-import Heading from './Heading';
-
-const TimePicker = ({ timeRange, onChange }) => {
- const times = timeRange.split(',');
- const [after, setAfter] = useState(times[0]);
- const [before, setBefore] = useState(times[1]);
-
- // Create repeating array with the number of hours for 1 day ...23,24,0,1,2...
- const hoursInDays = Array.from({ length: 24 }, (_, i) => String(i % 24).padStart(2, '0'));
-
- // background colors for each day
- function randomGrayTone(shade) {
- const grayTones = [
- 'bg-[#212529]/50',
- 'bg-[#343a40]/50',
- 'bg-[#495057]/50',
- 'bg-[#666463]/50',
- 'bg-[#817D7C]/50',
- 'bg-[#73706F]/50',
- 'bg-[#585655]/50',
- 'bg-[#4F4D4D]/50',
- 'bg-[#454343]/50',
- 'bg-[#363434]/50',
- ];
- return grayTones[shade % grayTones.length];
- }
-
- const isSelected = (idx, current) => {
- return current == `${idx}:00`;
- };
-
- const isSelectedCss = 'bg-blue-600 transition duration-300 ease-in-out hover:rounded-none';
- const handleTime = (after, before) => {
- setAfter(after);
- setBefore(before);
- onChange(`${after},${before}`);
- };
-
- return (
- <>
-
-
-
-
-
- After
-
-
- {hoursInDays.map((time, idx) => (
-
-
handleTime(`${time}:00`, before)}
- >
- {hoursInDays[idx]}:00
-
-
- ))}
-
-
-
-
- Before
-
-
- {hoursInDays.map((time, idx) => (
-
-
handleTime(after, `${time}:00`)}
- >
- {hoursInDays[idx]}:00
-
-
- ))}
-
-
-
-
-
- >
- );
-};
-
-export default TimePicker;
diff --git a/web-old/src/components/Timeline/ScrollPermission.ts b/web-old/src/components/Timeline/ScrollPermission.ts
deleted file mode 100644
index c0fe084c9..000000000
--- a/web-old/src/components/Timeline/ScrollPermission.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface ScrollPermission {
- allowed: boolean;
- resetAfterSeeked: boolean;
-}
\ No newline at end of file
diff --git a/web-old/src/components/Timeline/Timeline.tsx b/web-old/src/components/Timeline/Timeline.tsx
deleted file mode 100644
index 785af1f9b..000000000
--- a/web-old/src/components/Timeline/Timeline.tsx
+++ /dev/null
@@ -1,245 +0,0 @@
-import { Fragment, h } from 'preact';
-import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks';
-import { getTimelineEventBlocksFromTimelineEvents } from '../../utils/Timeline/timelineEventUtils';
-import type { ScrollPermission } from './ScrollPermission';
-import { TimelineBlocks } from './TimelineBlocks';
-import type { TimelineChangeEvent } from './TimelineChangeEvent';
-import { DisabledControls, TimelineControls } from './TimelineControls';
-import type { TimelineEvent } from './TimelineEvent';
-import type { TimelineEventBlock } from './TimelineEventBlock';
-
-interface TimelineProps {
- events: TimelineEvent[];
- isPlaying: boolean;
- onChange: (event: TimelineChangeEvent) => void;
- onPlayPause?: (isPlaying: boolean) => void;
-}
-
-export default function Timeline({ events, isPlaying, onChange, onPlayPause }: TimelineProps) {
- const timelineContainerRef = useRef(null);
-
- const [timeline, setTimeline] = useState([]);
- const [disabledControls, setDisabledControls] = useState({
- playPause: false,
- next: true,
- previous: false,
- });
- const [timelineOffset, setTimelineOffset] = useState(0);
- const [markerTime, setMarkerTime] = useState(new Date());
- const [currentEvent, setCurrentEvent] = useState(undefined);
- const [scrollTimeout, setScrollTimeout] = useState();
- const [scrollPermission, setScrollPermission] = useState({
- allowed: true,
- resetAfterSeeked: false,
- });
-
- const scrollToPosition = useCallback(
- (positionX: number) => {
- if (timelineContainerRef.current) {
- const permission: ScrollPermission = {
- allowed: true,
- resetAfterSeeked: true,
- };
- setScrollPermission(permission);
- timelineContainerRef.current.scroll({
- left: positionX,
- behavior: 'smooth',
- });
- }
- },
- [timelineContainerRef]
- );
-
- const scrollToEvent = useCallback(
- (event: TimelineEventBlock, offset = 0) => {
- scrollToPosition(event.positionX + offset - timelineOffset);
- },
- [timelineOffset, scrollToPosition]
- );
-
- useEffect(() => {
- if (timeline.length > 0 && currentEvent) {
- const currentIndex = currentEvent.index;
- if (currentIndex === 0) {
- setDisabledControls((previous) => ({
- ...previous,
- next: false,
- previous: true,
- }));
- } else if (currentIndex === timeline.length - 1) {
- setDisabledControls((previous) => ({
- ...previous,
- previous: false,
- next: true,
- }));
- } else {
- setDisabledControls((previous) => ({
- ...previous,
- previous: false,
- next: false,
- }));
- }
- }
- }, [timeline, currentEvent]);
-
- useEffect(() => {
- if (events && events.length > 0 && timelineOffset) {
- const timelineEvents = getTimelineEventBlocksFromTimelineEvents(events, timelineOffset);
- const lastEventIndex = timelineEvents.length - 1;
- const recentEvent = timelineEvents[lastEventIndex];
-
- setTimeline(timelineEvents);
- setMarkerTime(recentEvent.startTime);
- setCurrentEvent(recentEvent);
- scrollToEvent(recentEvent);
- }
- }, [events, timelineOffset, scrollToEvent]);
-
- useEffect(() => {
- const timelineIsLoaded = timeline.length > 0;
- if (timelineIsLoaded) {
- const lastEvent = timeline[timeline.length - 1];
- scrollToEvent(lastEvent);
- }
- }, [timeline, scrollToEvent]);
-
- const checkMarkerForEvent = (markerTime: Date) => {
- const adjustedMarkerTime = new Date(markerTime);
- adjustedMarkerTime.setSeconds(markerTime.getSeconds() + 1);
-
- return [...timeline]
- .reverse()
- .find(
- (timelineEvent) =>
- timelineEvent.startTime.getTime() <= adjustedMarkerTime.getTime() &&
- timelineEvent.endTime.getTime() >= adjustedMarkerTime.getTime()
- );
- };
-
- const seekCompleteHandler = (markerTime: Date) => {
- if (scrollPermission.allowed) {
- const markerEvent = checkMarkerForEvent(markerTime);
- setCurrentEvent(markerEvent);
-
- onChange({
- markerTime,
- timelineEvent: markerEvent,
- seekComplete: true,
- });
- }
-
- if (scrollPermission.resetAfterSeeked) {
- setScrollPermission({
- allowed: true,
- resetAfterSeeked: false,
- });
- }
- };
-
- const waitForSeekComplete = (markerTime: Date) => {
- if (scrollTimeout) {
- clearTimeout(scrollTimeout);
- }
- setScrollTimeout(setTimeout(() => seekCompleteHandler(markerTime), 150));
- };
-
- const onTimelineScrollHandler = () => {
- if (timelineContainerRef.current && timeline.length > 0) {
- const currentMarkerTime = getCurrentMarkerTime();
- setMarkerTime(currentMarkerTime);
- waitForSeekComplete(currentMarkerTime);
- onChange({
- timelineEvent: currentEvent,
- markerTime: currentMarkerTime,
- seekComplete: false,
- });
- }
- };
-
- const getCurrentMarkerTime = useCallback(() => {
- if (timelineContainerRef.current && timeline.length > 0) {
- const scrollPosition = timelineContainerRef.current.scrollLeft;
- const firstTimelineEvent = timeline[0] as TimelineEventBlock;
- const firstTimelineEventStartTime = firstTimelineEvent.startTime.getTime();
- return new Date(firstTimelineEventStartTime + scrollPosition * 1000);
- }
- return new Date();
- }, [timeline, timelineContainerRef]);
-
- useEffect(() => {
- if (timelineContainerRef) {
- const timelineContainerWidth = timelineContainerRef.current?.offsetWidth || 0;
- const offset = Math.round(timelineContainerWidth / 2);
- setTimelineOffset(offset);
- }
- }, [timelineContainerRef]);
-
- const handleViewEvent = useCallback(
- (event: TimelineEventBlock) => {
- scrollToEvent(event);
- setMarkerTime(getCurrentMarkerTime());
- },
- [scrollToEvent, getCurrentMarkerTime]
- );
-
- const onPlayPauseHandler = (isPlaying: boolean) => {
- onPlayPause && onPlayPause(isPlaying);
- };
-
- const onPreviousHandler = () => {
- if (currentEvent) {
- const previousEvent = timeline[currentEvent.index - 1];
- setCurrentEvent(previousEvent);
- scrollToEvent(previousEvent);
- }
- };
- const onNextHandler = () => {
- if (currentEvent) {
- const nextEvent = timeline[currentEvent.index + 1];
- setCurrentEvent(nextEvent);
- scrollToEvent(nextEvent);
- }
- };
-
- const timelineBlocks = useMemo(() => {
- if (timelineOffset && timeline.length > 0) {
- return ;
- }
- }, [timeline, timelineOffset, handleViewEvent]);
-
- return (
-
-
-
-
- {markerTime && {markerTime.toLocaleTimeString()} }
-
-
-
-
-
- {timelineBlocks}
-
-
-
-
-
- );
-}
diff --git a/web-old/src/components/Timeline/TimelineBlockView.tsx b/web-old/src/components/Timeline/TimelineBlockView.tsx
deleted file mode 100644
index 01f680421..000000000
--- a/web-old/src/components/Timeline/TimelineBlockView.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { h } from 'preact';
-import { useCallback } from 'preact/hooks';
-import { getColorFromTimelineEvent } from '../../utils/tailwind/twTimelineEventUtil';
-import type { TimelineEventBlock } from './TimelineEventBlock';
-
-interface TimelineBlockViewProps {
- block: TimelineEventBlock;
- onClick: (block: TimelineEventBlock) => void;
-}
-
-export const TimelineBlockView = ({ block, onClick }: TimelineBlockViewProps) => {
- const onClickHandler = useCallback(() => onClick(block), [block, onClick]);
- return (
-
- );
-};
diff --git a/web-old/src/components/Timeline/TimelineBlocks.tsx b/web-old/src/components/Timeline/TimelineBlocks.tsx
deleted file mode 100644
index 5c93254d5..000000000
--- a/web-old/src/components/Timeline/TimelineBlocks.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { h } from 'preact';
-import { useMemo } from 'preact/hooks';
-import { findLargestYOffsetInBlocks, getTimelineWidthFromBlocks } from '../../utils/Timeline/timelineEventUtils';
-import { convertRemToPixels } from '../../utils/windowUtils';
-import { TimelineBlockView } from './TimelineBlockView';
-import type { TimelineEventBlock } from './TimelineEventBlock';
-
-interface TimelineBlocksProps {
- timeline: TimelineEventBlock[];
- firstBlockOffset: number;
- onEventClick: (block: TimelineEventBlock) => void;
-}
-
-export const TimelineBlocks = ({ timeline, firstBlockOffset, onEventClick }: TimelineBlocksProps) => {
- const timelineEventBlocks = useMemo(() => {
- if (timeline.length > 0 && firstBlockOffset) {
- const largestYOffsetInBlocks = findLargestYOffsetInBlocks(timeline);
- const timelineContainerHeight = largestYOffsetInBlocks + convertRemToPixels(1);
- const timelineContainerWidth = getTimelineWidthFromBlocks(timeline, firstBlockOffset);
- const timelineBlockOffset = (timelineContainerHeight - largestYOffsetInBlocks) / 2;
- return (
-
- {timeline.map((block) => {
- const onClickHandler = (block: TimelineEventBlock) => onEventClick(block);
- const updatedBlock: TimelineEventBlock = {
- ...block,
- yOffset: block.yOffset + timelineBlockOffset,
- };
- return ;
- })}
-
- );
- }
- return
;
- }, [timeline, onEventClick, firstBlockOffset]);
-
- return timelineEventBlocks;
-};
diff --git a/web-old/src/components/Timeline/TimelineChangeEvent.ts b/web-old/src/components/Timeline/TimelineChangeEvent.ts
deleted file mode 100644
index 8e0397f7f..000000000
--- a/web-old/src/components/Timeline/TimelineChangeEvent.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import type { TimelineEvent } from './TimelineEvent';
-
-export interface TimelineChangeEvent {
- timelineEvent?: TimelineEvent;
- markerTime: Date;
- seekComplete: boolean;
-}
\ No newline at end of file
diff --git a/web-old/src/components/Timeline/TimelineControls.tsx b/web-old/src/components/Timeline/TimelineControls.tsx
deleted file mode 100644
index 4e08ec4b7..000000000
--- a/web-old/src/components/Timeline/TimelineControls.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { h } from 'preact';
-import Next from '../../icons/Next';
-import Pause from '../../icons/Pause';
-import Play from '../../icons/Play';
-import Previous from '../../icons/Previous';
-import { BubbleButton } from '../BubbleButton';
-
-export interface DisabledControls {
- playPause: boolean;
- next: boolean;
- previous: boolean;
-}
-
-interface TimelineControlsProps {
- disabled: DisabledControls;
- className?: string;
- isPlaying: boolean;
- onPlayPause: (isPlaying: boolean) => void;
- onNext: () => void;
- onPrevious: () => void;
-}
-
-export const TimelineControls = ({
- disabled,
- isPlaying,
- onPlayPause,
- onNext,
- onPrevious,
- className = '',
-}: TimelineControlsProps) => {
- const onPlayClickHandler = () => {
- onPlayPause(!isPlaying);
- };
- return (
-
-
-
-
-
{!isPlaying ? : }
-
-
-
-
- );
-};
diff --git a/web-old/src/components/Timeline/TimelineEvent.ts b/web-old/src/components/Timeline/TimelineEvent.ts
deleted file mode 100644
index 11bc3e0c1..000000000
--- a/web-old/src/components/Timeline/TimelineEvent.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export interface TimelineEvent {
- start_time: number;
- end_time: number;
- startTime: Date;
- endTime: Date;
- id: string;
- label: 'car' | 'person' | 'dog';
-}
\ No newline at end of file
diff --git a/web-old/src/components/Timeline/TimelineEventBlock.ts b/web-old/src/components/Timeline/TimelineEventBlock.ts
deleted file mode 100644
index b52bf40f1..000000000
--- a/web-old/src/components/Timeline/TimelineEventBlock.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import type { TimelineEvent } from './TimelineEvent';
-
-export interface TimelineEventBlock extends TimelineEvent {
- index: number;
- yOffset: number;
- width: number;
- positionX: number;
- seconds: number;
-}
\ No newline at end of file
diff --git a/web-old/src/components/TimelineEventOverlay.jsx b/web-old/src/components/TimelineEventOverlay.jsx
deleted file mode 100644
index 1cff55099..000000000
--- a/web-old/src/components/TimelineEventOverlay.jsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { Fragment, h } from 'preact';
-import { useState } from 'preact/hooks';
-
-export default function TimelineEventOverlay({ eventOverlay, cameraConfig }) {
- const boxLeftEdge = Math.round(eventOverlay.data.box[0] * 100);
- const boxTopEdge = Math.round(eventOverlay.data.box[1] * 100);
- const boxRightEdge = Math.round((1 - eventOverlay.data.box[2] - eventOverlay.data.box[0]) * 100);
- const boxBottomEdge = Math.round((1 - eventOverlay.data.box[3] - eventOverlay.data.box[1]) * 100);
-
- const [isHovering, setIsHovering] = useState(false);
- const getHoverStyle = () => {
- if (boxLeftEdge < 15) {
- // show object stats on right side
- return {
- left: `${boxLeftEdge + eventOverlay.data.box[2] * 100 + 1}%`,
- top: `${boxTopEdge}%`,
- };
- }
-
- return {
- right: `${boxRightEdge + eventOverlay.data.box[2] * 100 + 1}%`,
- top: `${boxTopEdge}%`,
- };
- };
-
- const getObjectArea = () => {
- const width = eventOverlay.data.box[2] * cameraConfig.detect.width;
- const height = eventOverlay.data.box[3] * cameraConfig.detect.height;
- return Math.round(width * height);
- };
-
- const getObjectRatio = () => {
- const width = eventOverlay.data.box[2] * cameraConfig.detect.width;
- const height = eventOverlay.data.box[3] * cameraConfig.detect.height;
- return Math.round(100 * (width / height)) / 100;
- };
-
- return (
-
- setIsHovering(true)}
- onMouseLeave={() => setIsHovering(false)}
- onTouchStart={() => setIsHovering(true)}
- onTouchEnd={() => setIsHovering(false)}
- style={{
- left: `${boxLeftEdge}%`,
- top: `${boxTopEdge}%`,
- right: `${boxRightEdge}%`,
- bottom: `${boxBottomEdge}%`,
- }}
- >
- {eventOverlay.class_type == 'entered_zone' ? (
-
- ) : null}
-
- {isHovering && (
-
-
{`Area: ${getObjectArea()} px`}
-
{`Ratio: ${getObjectRatio()}`}
-
- )}
-
- );
-}
diff --git a/web-old/src/components/TimelineSummary.jsx b/web-old/src/components/TimelineSummary.jsx
deleted file mode 100644
index 62e3b4cb6..000000000
--- a/web-old/src/components/TimelineSummary.jsx
+++ /dev/null
@@ -1,218 +0,0 @@
-import { h } from 'preact';
-import useSWR from 'swr';
-import ActivityIndicator from './ActivityIndicator';
-import { formatUnixTimestampToDateTime } from '../utils/dateUtil';
-import About from '../icons/About';
-import ActiveObjectIcon from '../icons/ActiveObject';
-import PlayIcon from '../icons/Play';
-import ExitIcon from '../icons/Exit';
-import StationaryObjectIcon from '../icons/StationaryObject';
-import FaceIcon from '../icons/Face';
-import LicensePlateIcon from '../icons/LicensePlate';
-import DeliveryTruckIcon from '../icons/DeliveryTruck';
-import ZoneIcon from '../icons/Zone';
-import { useMemo, useState } from 'preact/hooks';
-import Button from './Button';
-
-export default function TimelineSummary({ event, onFrameSelected }) {
- const { data: eventTimeline } = useSWR([
- 'timeline',
- {
- source_id: event.id,
- },
- ]);
-
- const { data: config } = useSWR('config');
-
- const annotationOffset = useMemo(() => {
- if (!config) {
- return 0;
- }
-
- return (config.cameras[event.camera]?.detect?.annotation_offset || 0) / 1000;
- }, [config, event]);
-
- const [timeIndex, setTimeIndex] = useState(-1);
-
- const recordingParams = useMemo(() => {
- if (!event.end_time) {
- return {
- after: event.start_time,
- };
- }
-
- return {
- before: event.end_time,
- after: event.start_time,
- };
- }, [event]);
- const { data: recordings } = useSWR([`${event.camera}/recordings`, recordingParams], { revalidateOnFocus: false });
-
- // calculates the seek seconds by adding up all the seconds in the segments prior to the playback time
- const getSeekSeconds = (seekUnix) => {
- if (!recordings) {
- return 0;
- }
-
- let seekSeconds = 0;
- recordings.every((segment) => {
- // if the next segment is past the desired time, stop calculating
- if (segment.start_time > seekUnix) {
- return false;
- }
-
- if (segment.end_time < seekUnix) {
- seekSeconds += segment.end_time - segment.start_time;
- return true;
- }
-
- seekSeconds += segment.end_time - segment.start_time - (segment.end_time - seekUnix);
- return true;
- });
-
- return seekSeconds;
- };
-
- const onSelectMoment = async (index) => {
- setTimeIndex(index);
- onFrameSelected(eventTimeline[index], getSeekSeconds(eventTimeline[index].timestamp + annotationOffset));
- };
-
- if (!eventTimeline || !config) {
- return ;
- }
-
- if (eventTimeline.length == 0) {
- return
;
- }
-
- return (
-
-
-
- {eventTimeline.map((item, index) => (
- 640 ? getTimelineItemDescription(config, item, event) : ''}
- onClick={() => onSelectMoment(index)}
- >
- {getTimelineIcon(item)}
-
- ))}
-
-
- {timeIndex >= 0 ? (
-
-
-
Bounding boxes may not align
-
-
-
-
-
- ) : null}
-
- );
-}
-
-function getTimelineIcon(timelineItem) {
- switch (timelineItem.class_type) {
- case 'visible':
- return ;
- case 'gone':
- return ;
- case 'active':
- return ;
- case 'stationary':
- return ;
- case 'entered_zone':
- return ;
- case 'attribute':
- switch (timelineItem.data.attribute) {
- case 'face':
- return ;
- case 'license_plate':
- return ;
- default:
- return ;
- }
- case 'sub_label':
- switch (timelineItem.data.label) {
- case 'person':
- return ;
- case 'car':
- return ;
- }
- }
-}
-
-function getTimelineItemDescription(config, timelineItem, event) {
- switch (timelineItem.class_type) {
- case 'visible':
- return `${event.label} detected at ${formatUnixTimestampToDateTime(timelineItem.timestamp, {
- date_style: 'short',
- time_style: 'medium',
- time_format: config.ui.time_format,
- })}`;
- case 'entered_zone':
- return `${event.label.replaceAll('_', ' ')} entered ${timelineItem.data.zones
- .join(' and ')
- .replaceAll('_', ' ')} at ${formatUnixTimestampToDateTime(timelineItem.timestamp, {
- date_style: 'short',
- time_style: 'medium',
- time_format: config.ui.time_format,
- })}`;
- case 'active':
- return `${event.label} became active at ${formatUnixTimestampToDateTime(timelineItem.timestamp, {
- date_style: 'short',
- time_style: 'medium',
- time_format: config.ui.time_format,
- })}`;
- case 'stationary':
- return `${event.label} became stationary at ${formatUnixTimestampToDateTime(timelineItem.timestamp, {
- date_style: 'short',
- time_style: 'medium',
- time_format: config.ui.time_format,
- })}`;
- case 'attribute': {
- let title = "";
- if (timelineItem.data.attribute == 'face' || timelineItem.data.attribute == 'license_plate') {
- title = `${timelineItem.data.attribute.replaceAll("_", " ")} detected for ${event.label}`;
- } else {
- title = `${event.label} recognized as ${timelineItem.data.attribute.replaceAll("_", " ")}`
- }
- return `${title} at ${formatUnixTimestampToDateTime(
- timelineItem.timestamp,
- {
- date_style: 'short',
- time_style: 'medium',
- time_format: config.ui.time_format,
- }
- )}`;
- }
- case 'sub_label':
- return `${event.label} recognized as ${timelineItem.data.sub_label} at ${formatUnixTimestampToDateTime(
- timelineItem.timestamp,
- {
- date_style: 'short',
- time_style: 'medium',
- time_format: config.ui.time_format,
- }
- )}`;
- case 'gone':
- return `${event.label} left at ${formatUnixTimestampToDateTime(timelineItem.timestamp, {
- date_style: 'short',
- time_style: 'medium',
- time_format: config.ui.time_format,
- })}`;
- }
-}
diff --git a/web-old/src/components/Tooltip.jsx b/web-old/src/components/Tooltip.jsx
deleted file mode 100644
index a7da1d29f..000000000
--- a/web-old/src/components/Tooltip.jsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import { h } from 'preact';
-import { createPortal } from 'preact/compat';
-import { useLayoutEffect, useRef, useState } from 'preact/hooks';
-
-const TIP_SPACE = 20;
-
-export default function Tooltip({ relativeTo, text, capitalize }) {
- const [position, setPosition] = useState({ top: -9999, left: -9999 });
- const portalRoot = document.getElementById('tooltips');
- const ref = useRef();
-
- useLayoutEffect(() => {
- if (ref && ref.current && relativeTo && relativeTo.current) {
- const windowWidth = window.innerWidth;
- const {
- x: relativeToX,
- y: relativeToY,
- width: relativeToWidth,
- height: relativeToHeight,
- } = relativeTo.current.getBoundingClientRect();
- const { width: _tipWidth, height: _tipHeight } = ref.current.getBoundingClientRect();
- const tipWidth = _tipWidth * 1.1;
- const tipHeight = _tipHeight * 1.1;
-
- const left = relativeToX + Math.round(relativeToWidth / 2) + window.scrollX;
- const top = relativeToY + Math.round(relativeToHeight / 2) + window.scrollY;
-
- let newTop = top - TIP_SPACE - tipHeight;
- let newLeft = left - Math.round(tipWidth / 2);
- // too far right
- if (newLeft + tipWidth + TIP_SPACE > windowWidth - window.scrollX) {
- newLeft = Math.max(0, left - tipWidth - TIP_SPACE);
- newTop = top - Math.round(tipHeight / 2);
- }
- // too far left
- else if (newLeft < TIP_SPACE + window.scrollX) {
- newLeft = left + TIP_SPACE;
- newTop = top - Math.round(tipHeight / 2);
- }
- // too close to top
- else if (newTop <= TIP_SPACE + window.scrollY) {
- newTop = top + tipHeight + TIP_SPACE;
- }
-
- setPosition({ left: newLeft, top: newTop });
- }
- }, [relativeTo, ref]);
-
- const tooltip = (
- = 0 ? 'opacity-100 scale-100' : ''}`}
- ref={ref}
- style={position}
- >
- {text}
-
- );
-
- return portalRoot ? createPortal(tooltip, portalRoot) : tooltip;
-}
diff --git a/web-old/src/components/VideoPlayer.jsx b/web-old/src/components/VideoPlayer.jsx
deleted file mode 100644
index ec548eab8..000000000
--- a/web-old/src/components/VideoPlayer.jsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import { h } from 'preact';
-import { useRef, useEffect } from 'preact/hooks';
-import videojs from 'video.js';
-import 'videojs-playlist';
-import 'video.js/dist/video-js.css';
-
-export default function VideoPlayer({ children, options, seekOptions = {forward:30, backward: 10}, onReady = () => {}, onDispose = () => {} }) {
- const playerRef = useRef();
-
- useEffect(() => {
- const defaultOptions = {
- controls: true,
- controlBar: {
- skipButtons: seekOptions,
- },
- playbackRates: [0.5, 1, 2, 4, 8],
- fluid: true,
- };
-
-
- if (!videojs.browser.IS_FIREFOX) {
- defaultOptions.playbackRates.push(16);
- }
-
- const player = videojs(playerRef.current, { ...defaultOptions, ...options }, () => {
- onReady(player);
- });
-
- // Allows player to continue on error
- player.reloadSourceOnError();
-
- // Disable fullscreen on iOS if we have children
- if (
- children &&
- videojs.browser.IS_IOS &&
- videojs.browser.IOS_VERSION > 9 &&
- !player.el_.ownerDocument.querySelector('.bc-iframe')
- ) {
- player.tech_.el_.setAttribute('playsinline', 'playsinline');
- player.tech_.supportsFullScreen = function () {
- return false;
- };
- }
-
- const screen = window.screen;
-
- const angle = () => {
- // iOS
- if (typeof window.orientation === 'number') {
- return window.orientation;
- }
- // Android
- if (screen && screen.orientation && screen.orientation.angle) {
- return window.orientation;
- }
- videojs.log('angle unknown');
- return 0;
- };
-
- const rotationHandler = () => {
- const currentAngle = angle();
-
- if (currentAngle === 90 || currentAngle === 270 || currentAngle === -90) {
- if (player.paused() === false) {
- player.requestFullscreen();
- }
- }
-
- if ((currentAngle === 0 || currentAngle === 180) && player.isFullscreen()) {
- player.exitFullscreen();
- }
- };
-
- if (videojs.browser.IS_IOS) {
- window.addEventListener('orientationchange', rotationHandler);
- } else if (videojs.browser.IS_ANDROID && screen.orientation) {
- // addEventListener('orientationchange') is not a user interaction on Android
- screen.orientation.onchange = rotationHandler;
- }
-
- return () => {
- if (videojs.browser.IS_IOS) {
- window.removeEventListener('orientationchange', rotationHandler);
- }
- player.dispose();
- onDispose();
- };
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
-
- return (
-
- {/* Setting an empty data-setup is required to override the default values and allow video to be fit the size of its parent */}
-
- {children}
-
- );
-}
\ No newline at end of file
diff --git a/web-old/src/components/WebRtcPlayer.jsx b/web-old/src/components/WebRtcPlayer.jsx
deleted file mode 100644
index c1427fcbc..000000000
--- a/web-old/src/components/WebRtcPlayer.jsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import { h } from 'preact';
-import { baseUrl } from '../api/baseUrl';
-import { useCallback, useEffect } from 'preact/hooks';
-
-export default function WebRtcPlayer({ camera, width, height }) {
- const PeerConnection = useCallback(async (media) => {
- const pc = new RTCPeerConnection({
- iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
- });
-
- const localTracks = [];
-
- if (/camera|microphone/.test(media)) {
- const tracks = await getMediaTracks('user', {
- video: media.indexOf('camera') >= 0,
- audio: media.indexOf('microphone') >= 0,
- });
- tracks.forEach((track) => {
- pc.addTransceiver(track, { direction: 'sendonly' });
- if (track.kind === 'video') localTracks.push(track);
- });
- }
-
- if (media.indexOf('display') >= 0) {
- const tracks = await getMediaTracks('display', {
- video: true,
- audio: media.indexOf('speaker') >= 0,
- });
- tracks.forEach((track) => {
- pc.addTransceiver(track, { direction: 'sendonly' });
- if (track.kind === 'video') localTracks.push(track);
- });
- }
-
- if (/video|audio/.test(media)) {
- const tracks = ['video', 'audio']
- .filter((kind) => media.indexOf(kind) >= 0)
- .map((kind) => pc.addTransceiver(kind, { direction: 'recvonly' }).receiver.track);
- localTracks.push(...tracks);
- }
-
- document.getElementById('video').srcObject = new MediaStream(localTracks);
-
- return pc;
- }, []);
-
- async function getMediaTracks(media, constraints) {
- try {
- const stream =
- media === 'user'
- ? await navigator.mediaDevices.getUserMedia(constraints)
- : await navigator.mediaDevices.getDisplayMedia(constraints);
- return stream.getTracks();
- } catch (e) {
- return [];
- }
- }
-
- const connect = useCallback(async (ws, aPc) => {
- const pc = await aPc;
-
- ws.addEventListener('open', () => {
- pc.addEventListener('icecandidate', (ev) => {
- if (!ev.candidate) return;
- const msg = { type: 'webrtc/candidate', value: ev.candidate.candidate };
- ws.send(JSON.stringify(msg));
- });
-
- pc.createOffer()
- .then((offer) => pc.setLocalDescription(offer))
- .then(() => {
- const msg = { type: 'webrtc/offer', value: pc.localDescription.sdp };
- ws.send(JSON.stringify(msg));
- });
- });
-
- ws.addEventListener('message', (ev) => {
- const msg = JSON.parse(ev.data);
- if (msg.type === 'webrtc/candidate') {
- pc.addIceCandidate({ candidate: msg.value, sdpMid: '0' });
- } else if (msg.type === 'webrtc/answer') {
- pc.setRemoteDescription({ type: 'answer', sdp: msg.value });
- }
- });
- }, []);
-
- useEffect(() => {
- const url = `${baseUrl.replace(/^http/, 'ws')}live/webrtc/api/ws?src=${camera}`;
- const ws = new WebSocket(url);
- const aPc = PeerConnection('video+audio');
- connect(ws, aPc);
-
- return async () => {
- (await aPc).close();
- }
- }, [camera, connect, PeerConnection]);
-
- return (
-
-
-
- );
-}
diff --git a/web-old/src/components/__tests__/ActivityIndicator.test.jsx b/web-old/src/components/__tests__/ActivityIndicator.test.jsx
deleted file mode 100644
index a9037fbdf..000000000
--- a/web-old/src/components/__tests__/ActivityIndicator.test.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { h } from 'preact';
-import ActivityIndicator from '../ActivityIndicator';
-import { render, screen } from 'testing-library';
-
-describe('ActivityIndicator', () => {
- test('renders an ActivityIndicator with default size md', async () => {
- render( );
- expect(screen.getByLabelText('Loading…')).toMatchInlineSnapshot(`
-
- `);
- });
-
- test('renders an ActivityIndicator with size sm', async () => {
- render( );
- expect(screen.getByLabelText('Loading…')).toMatchInlineSnapshot(`
-
- `);
- });
-
- test('renders an ActivityIndicator with size lg', async () => {
- render( );
- expect(screen.getByLabelText('Loading…')).toMatchInlineSnapshot(`
-
- `);
- });
-});
diff --git a/web-old/src/components/__tests__/AppBar.test.jsx b/web-old/src/components/__tests__/AppBar.test.jsx
deleted file mode 100644
index b925be0a6..000000000
--- a/web-old/src/components/__tests__/AppBar.test.jsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import { h } from 'preact';
-import { DrawerProvider } from '../../context';
-import AppBar from '../AppBar';
-import { fireEvent, render, screen } from '@testing-library/preact';
-import { useRef } from 'preact/hooks';
-
-function Title() {
- return I am the title
;
-}
-
-describe('AppBar', () => {
- test('renders the title', async () => {
- render(
-
-
-
- );
- expect(screen.getByText('I am the title')).toBeInTheDocument();
- });
-
- describe('overflow menu', () => {
- test('is not rendered if a ref is not provided', async () => {
- const handleOverflow = vi.fn();
- render(
-
-
-
- );
- expect(screen.queryByLabelText('More options')).not.toBeInTheDocument();
- });
-
- test('is not rendered if a click handler is not provided', async () => {
- function Wrapper() {
- const ref = useRef(null);
- return ;
- }
-
- render(
-
-
-
- );
- expect(screen.queryByLabelText('More options')).not.toBeInTheDocument();
- });
-
- test('is rendered with click handler and ref', async () => {
- const handleOverflow = vi.fn();
-
- function Wrapper() {
- const ref = useRef(null);
- return ;
- }
-
- render(
-
-
-
- );
- expect(screen.queryByLabelText('More options')).toBeInTheDocument();
- });
-
- test('calls the handler when clicked', async () => {
- const handleOverflow = vi.fn();
-
- function Wrapper() {
- const ref = useRef(null);
- return ;
- }
-
- render(
-
-
-
- );
-
- fireEvent.click(screen.queryByLabelText('More options'));
-
- expect(handleOverflow).toHaveBeenCalled();
- });
- });
-
- describe('scrolling', () => {
- test('is visible initially', async () => {
- render(
-
-
-
- );
-
- const classes = screen.getByTestId('appbar').classList;
-
- expect(classes.contains('translate-y-0')).toBe(true);
- expect(classes.contains('-translate-y-full')).toBe(false);
- });
-
- test('hides when scrolled downward', async () => {
- vi.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => cb());
- render(
-
-
-
- );
-
- window.scrollY = 300;
- await fireEvent.scroll(document, { target: { scrollY: 300 } });
-
- const classes = screen.getByTestId('appbar').classList;
-
- expect(classes.contains('translate-y-0')).toBe(false);
- expect(classes.contains('-translate-y-full')).toBe(true);
- });
-
- test('reappears when scrolled upward', async () => {
- vi.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => cb());
- render(
-
-
-
- );
-
- window.scrollY = 300;
- await fireEvent.scroll(document, { target: { scrollY: 300 } });
- window.scrollY = 280;
- await fireEvent.scroll(document, { target: { scrollY: 280 } });
-
- const classes = screen.getByTestId('appbar').classList;
-
- expect(classes.contains('translate-y-0')).toBe(true);
- expect(classes.contains('-translate-y-full')).toBe(false);
- });
- });
-});
diff --git a/web-old/src/components/__tests__/AutoUpdatingCameraImage.test.jsx b/web-old/src/components/__tests__/AutoUpdatingCameraImage.test.jsx
deleted file mode 100644
index 9ee532c9b..000000000
--- a/web-old/src/components/__tests__/AutoUpdatingCameraImage.test.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { h } from 'preact';
-import AutoUpdatingCameraImage from '../AutoUpdatingCameraImage';
-import { screen, render } from '@testing-library/preact';
-
-let mockOnload;
-vi.mock('../CameraImage', () => {
- function CameraImage({ onload, searchParams }) {
- mockOnload = () => {
- onload();
- };
- return {searchParams}
;
- }
- return {
- __esModule: true,
- default: CameraImage,
- };
-});
-
-describe('AutoUpdatingCameraImage', () => {
- let dateNowSpy;
- beforeEach(() => {
- dateNowSpy = vi.spyOn(Date, 'now').mockReturnValue(0);
- });
-
- test('shows FPS by default', async () => {
- render( );
- expect(screen.queryByText('Displaying at 0fps')).toBeInTheDocument();
- });
-
- test('does not show FPS if turned off', async () => {
- render( );
- expect(screen.queryByText('Displaying at 0fps')).not.toBeInTheDocument();
- });
-
- test('on load, sets a new cache key to search params', async () => {
- dateNowSpy.mockReturnValueOnce(100).mockReturnValueOnce(200).mockReturnValueOnce(300);
- render( );
- mockOnload();
- await screen.findByText('cache=100&foo');
- expect(screen.getByText('cache=100&foo')).toBeInTheDocument();
- });
-});
diff --git a/web-old/src/components/__tests__/Button.test.jsx b/web-old/src/components/__tests__/Button.test.jsx
deleted file mode 100644
index 1278c6e6d..000000000
--- a/web-old/src/components/__tests__/Button.test.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { h } from 'preact';
-import Button from '../Button';
-import { render, screen } from '@testing-library/preact';
-
-describe('Button', () => {
- test('renders children', async () => {
- render(
-
- hello
- hi
-
- );
- expect(screen.queryByText('hello')).toBeInTheDocument();
- expect(screen.queryByText('hi')).toBeInTheDocument();
- });
-
- test('includes focus, active, and hover classes when enabled', async () => {
- render(click me );
-
- const classList = screen.queryByRole('button').classList;
- expect(classList.contains('focus:outline-none')).toBe(true);
- expect(classList.contains('focus:ring-2')).toBe(true);
- expect(classList.contains('hover:shadow-md')).toBe(true);
- expect(classList.contains('active:bg-blue-600')).toBe(true);
- });
-
- test('does not focus, active, and hover classes when enabled', async () => {
- render(click me );
-
- const classList = screen.queryByRole('button').classList;
- expect(classList.contains('focus:outline-none')).toBe(false);
- expect(classList.contains('focus:ring-2')).toBe(false);
- expect(classList.contains('hover:shadow-md')).toBe(false);
- expect(classList.contains('active:bg-blue-600')).toBe(false);
- });
-});
diff --git a/web-old/src/components/__tests__/CameraImage.test.jsx b/web-old/src/components/__tests__/CameraImage.test.jsx
deleted file mode 100644
index fe8db9fe6..000000000
--- a/web-old/src/components/__tests__/CameraImage.test.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { h } from 'preact';
-import * as Hooks from '../../hooks';
-import CameraImage from '../CameraImage';
-import { render, screen } from '@testing-library/preact';
-
-describe('CameraImage', () => {
- beforeEach(() => {
- vi.spyOn(Hooks, 'useResizeObserver').mockImplementation(() => [{ width: 0 }]);
- });
-
- test('renders an activity indicator while loading', async () => {
- render( );
- expect(screen.queryByLabelText('Loading…')).toBeInTheDocument();
- });
-});
diff --git a/web-old/src/components/__tests__/Card.test.jsx b/web-old/src/components/__tests__/Card.test.jsx
deleted file mode 100644
index 16d1c3c99..000000000
--- a/web-old/src/components/__tests__/Card.test.jsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { h } from 'preact';
-import Card from '../Card';
-import { render, screen } from '@testing-library/preact';
-
-describe('Card', () => {
- test('renders a Card with media', async () => {
- render( } />);
- expect(screen.queryByAltText('tacos')).toBeInTheDocument();
- });
-
- test('renders a Card with a link around media', async () => {
- render( } />);
- expect(screen.queryByAltText('tacos')).toBeInTheDocument();
- expect(screen.getByAltText('tacos').closest('a')).toHaveAttribute('href', '/tacos');
- });
-
- test('renders a Card with a header', async () => {
- render( );
- expect(screen.queryByText('Tacos!')).toBeInTheDocument();
- });
-
- test('renders a Card with a linked header', async () => {
- render( );
- expect(screen.queryByText('Tacos!')).toBeInTheDocument();
- expect(screen.queryByText('Tacos!').closest('a')).toHaveAttribute('href', '/tacos');
- });
-
- test('renders content', async () => {
- const content = hello
;
- render( );
- expect(screen.queryByTestId('content')).toBeInTheDocument();
- });
-
- test('renders buttons', async () => {
- const buttons = [
- { name: 'Tacos', href: '/tacos' },
- { name: 'Burritos', href: '/burritos' },
- ];
- render( );
- expect(screen.queryByText('Tacos')).toHaveAttribute('role', 'button');
- expect(screen.queryByText('Tacos')).toHaveAttribute('href', '/tacos');
-
- expect(screen.queryByText('Burritos')).toHaveAttribute('role', 'button');
- expect(screen.queryByText('Burritos')).toHaveAttribute('href', '/burritos');
- });
-});
diff --git a/web-old/src/components/__tests__/Dialog.test.jsx b/web-old/src/components/__tests__/Dialog.test.jsx
deleted file mode 100644
index 24852e1ff..000000000
--- a/web-old/src/components/__tests__/Dialog.test.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { h } from 'preact';
-import Dialog from '../Dialog';
-import { render, screen } from '@testing-library/preact';
-
-describe('Dialog', () => {
- let portal;
-
- beforeAll(() => {
- portal = document.createElement('div');
- portal.id = 'dialogs';
- document.body.appendChild(portal);
- });
-
- afterAll(() => {
- document.body.removeChild(portal);
- });
-
- test('renders to a portal', async () => {
- render(Sample );
- expect(screen.getByText('Sample')).toBeInTheDocument();
- expect(screen.getByRole('modal').closest('#dialogs')).not.toBeNull();
- });
-});
diff --git a/web-old/src/components/__tests__/Heading.test.jsx b/web-old/src/components/__tests__/Heading.test.jsx
deleted file mode 100644
index 25eb493b0..000000000
--- a/web-old/src/components/__tests__/Heading.test.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { h } from 'preact';
-import Heading from '../Heading';
-import { render, screen } from '@testing-library/preact';
-
-describe('Heading', () => {
- test('renders content with default size', async () => {
- render(Hello );
- expect(screen.queryByText('Hello')).toBeInTheDocument();
- expect(screen.queryByText('Hello').classList.contains('text-2xl')).toBe(true);
- });
-
- test('renders with custom size', async () => {
- render(Hello );
- expect(screen.queryByText('Hello')).toBeInTheDocument();
- expect(screen.queryByText('Hello').classList.contains('text-2xl')).toBe(false);
- expect(screen.queryByText('Hello').classList.contains('text-lg')).toBe(true);
- });
-
- test('renders with custom className', async () => {
- render(Hello );
- expect(screen.queryByText('Hello')).toBeInTheDocument();
- expect(screen.queryByText('Hello').classList.contains('text-2xl')).toBe(true);
- expect(screen.queryByText('Hello').classList.contains('tacos')).toBe(true);
- });
-});
diff --git a/web-old/src/components/__tests__/Link.test.jsx b/web-old/src/components/__tests__/Link.test.jsx
deleted file mode 100644
index 8bf007944..000000000
--- a/web-old/src/components/__tests__/Link.test.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { h } from 'preact';
-import Link from '../Link';
-import { render, screen } from 'testing-library';
-
-// eslint-disable-next-line jest/no-disabled-tests
-describe.skip('Link', () => {
- test('renders a link', async () => {
- render( Hello);
- expect(screen.queryByText('Hello')).toMatchInlineSnapshot(`
-
- Hello
-
- `);
- });
-});
diff --git a/web-old/src/components/__tests__/Menu.test.jsx b/web-old/src/components/__tests__/Menu.test.jsx
deleted file mode 100644
index 640ac9565..000000000
--- a/web-old/src/components/__tests__/Menu.test.jsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { h } from 'preact';
-import Menu, { MenuItem } from '../Menu';
-import { fireEvent, render, screen } from '@testing-library/preact';
-import { useRef } from 'preact/hooks';
-
-describe('Menu', () => {
- test('renders a dialog', async () => {
- function Test() {
- const relativeRef = useRef();
- return (
-
- );
- }
-
- render( );
- expect(screen.queryByRole('listbox')).toBeInTheDocument();
- });
-});
-
-describe('MenuItem', () => {
- test('renders a menu item', async () => {
- render( );
- expect(screen.queryByRole('option')).toHaveTextContent('Tacos');
- });
-
- test('calls onSelect when clicked', async () => {
- const handleSelect = vi.fn();
- render( );
- fireEvent.click(screen.queryByRole('option'));
- expect(handleSelect).toHaveBeenCalledWith('tacos-value', 'Tacos');
- });
-
- test('renders and icon when passed', async () => {
- function Icon() {
- return
;
- }
- render( );
- expect(screen.queryByTestId('icon')).toBeInTheDocument();
- });
-
- test('applies different styles when focused', async () => {
- const { rerender } = render( );
- const classes = Array.from(screen.queryByRole('option').classList);
- rerender( );
- const focusClasses = Array.from(screen.queryByRole('option').classList);
-
- expect(focusClasses.length).toBeGreaterThan(classes.length);
- });
-});
diff --git a/web-old/src/components/__tests__/NavigationDrawer.test.jsx b/web-old/src/components/__tests__/NavigationDrawer.test.jsx
deleted file mode 100644
index ccf60f047..000000000
--- a/web-old/src/components/__tests__/NavigationDrawer.test.jsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import { h } from 'preact';
-import * as Context from '../../context';
-import NavigationDrawer, { Destination } from '../NavigationDrawer';
-import { fireEvent, render, screen } from '@testing-library/preact';
-
-describe('NavigationDrawer', () => {
- let useDrawer, setShowDrawer;
-
- beforeEach(() => {
- setShowDrawer = vi.fn();
- useDrawer = vi.spyOn(Context, 'useDrawer').mockImplementation(() => ({ showDrawer: true, setShowDrawer }));
- });
-
- test('renders a navigation drawer', async () => {
- render(
-
- Hello
-
- );
- expect(screen.queryByTestId('children')).toHaveTextContent('Hello');
- expect(screen.queryByTestId('drawer').classList.contains('translate-x-full')).toBe(false);
- expect(screen.queryByTestId('drawer').classList.contains('translate-x-0')).toBe(true);
- });
-
- test('is dismissed when the scrim is clicked', async () => {
- useDrawer
- .mockReturnValueOnce({ showDrawer: true, setShowDrawer })
- .mockReturnValueOnce({ showDrawer: false, setShowDrawer });
- render( );
- fireEvent.click(screen.queryByTestId('scrim'));
- expect(setShowDrawer).toHaveBeenCalledWith(false);
- });
-
- test('is not visible when not set to show', async () => {
- useDrawer.mockReturnValue({ showDrawer: false, setShowDrawer });
- render( );
- expect(screen.queryByTestId('scrim')).not.toBeInTheDocument();
- expect(screen.queryByTestId('drawer').classList.contains('-translate-x-full')).toBe(true);
- expect(screen.queryByTestId('drawer').classList.contains('translate-x-0')).toBe(false);
- });
-});
-
-describe('Destination', () => {
- let setShowDrawer;
-
- beforeEach(() => {
- setShowDrawer = vi.fn();
- vi.spyOn(Context, 'useDrawer').mockImplementation(() => ({ showDrawer: true, setShowDrawer }));
- });
-
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('dismisses the drawer moments after being clicked', async () => {
- vi.useFakeTimers();
- render(
-
-
-
- );
- fireEvent.click(screen.queryByText('Tacos'));
- vi.runAllTimers();
- expect(setShowDrawer).toHaveBeenCalledWith(false);
- });
-});
diff --git a/web-old/src/components/__tests__/Prompt.test.jsx b/web-old/src/components/__tests__/Prompt.test.jsx
deleted file mode 100644
index e10435761..000000000
--- a/web-old/src/components/__tests__/Prompt.test.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { h } from 'preact';
-import Prompt from '../Prompt';
-import { fireEvent, render, screen } from '@testing-library/preact';
-
-describe('Prompt', () => {
- let portal;
-
- beforeAll(() => {
- portal = document.createElement('div');
- portal.id = 'dialogs';
- document.body.appendChild(portal);
- });
-
- afterAll(() => {
- document.body.removeChild(portal);
- });
-
- test('renders to a portal', async () => {
- render( );
- expect(screen.getByText('Tacos')).toBeInTheDocument();
- expect(screen.getByRole('modal').closest('#dialogs')).not.toBeNull();
- });
-
- test('renders action buttons', async () => {
- const handleClick = vi.fn();
- render(
-
- );
- fireEvent.click(screen.getByRole('button', { name: 'Okay' }));
- expect(handleClick).toHaveBeenCalled();
- });
-});
diff --git a/web-old/src/components/__tests__/RelativeModal.test.jsx b/web-old/src/components/__tests__/RelativeModal.test.jsx
deleted file mode 100644
index e988c70d3..000000000
--- a/web-old/src/components/__tests__/RelativeModal.test.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import { h, createRef } from 'preact';
-import RelativeModal from '../RelativeModal';
-import userEvent from '@testing-library/user-event';
-import { fireEvent, render, screen } from '@testing-library/preact';
-
-describe('RelativeModal', () => {
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('keeps tab focus', async () => {
- const ref = createRef();
- render(
-
- );
-
- const inputs = screen.queryAllByTestId(/modal-input/);
- expect(document.activeElement).toBe(inputs[0]);
- userEvent.tab();
- expect(document.activeElement).toBe(inputs[1]);
- userEvent.tab();
- expect(document.activeElement).toBe(inputs[0]);
- });
-
- test('pressing ESC dismisses', async () => {
- const handleDismiss = vi.fn();
- const ref = createRef();
- render(
-
- );
-
- const dialog = screen.queryByRole('dialog');
- expect(dialog).toBeInTheDocument();
-
- fireEvent.keyDown(document.activeElement, { key: 'Escape', code: 'Escape' });
- expect(handleDismiss).toHaveBeenCalled();
- });
-
- test('clicking a scrim dismisses', async () => {
- const handleDismiss = vi.fn();
- const ref = createRef();
- render(
-
- );
-
- fireEvent.click(screen.queryByTestId('scrim'));
- expect(handleDismiss).toHaveBeenCalled();
- });
-});
diff --git a/web-old/src/components/__tests__/Select.test.jsx b/web-old/src/components/__tests__/Select.test.jsx
deleted file mode 100644
index 00579ce40..000000000
--- a/web-old/src/components/__tests__/Select.test.jsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { h } from 'preact';
-import Select from '../Select';
-import { fireEvent, render, screen } from '@testing-library/preact';
-
-describe('Select', () => {
- test('on focus, shows a menu', async () => {
- const handleChange = vi.fn();
- render(
-
- );
-
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
- fireEvent.click(screen.getByRole('textbox'));
- expect(screen.queryByRole('listbox')).toBeInTheDocument();
- expect(screen.queryByRole('option', { name: 'all' })).toBeInTheDocument();
- expect(screen.queryByRole('option', { name: 'tacos' })).toBeInTheDocument();
- expect(screen.queryByRole('option', { name: 'burritos' })).toBeInTheDocument();
-
- fireEvent.click(screen.queryByRole('option', { name: 'tacos' }));
- expect(handleChange).toHaveBeenCalledWith({ dinner: 'tacos' });
- });
-
- test('allows keyboard navigation', async () => {
- const handleChange = vi.fn();
- render(
-
- );
-
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
- const input = screen.getByRole('textbox');
- fireEvent.focus(input);
- fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
- expect(screen.queryByRole('listbox')).toBeInTheDocument();
-
- fireEvent.keyDown(input, { key: 'ArrowDown', code: 'ArrowDown' });
- fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
- expect(handleChange).toHaveBeenCalledWith({ dinner: 'burritos' });
- });
-});
diff --git a/web-old/src/components/__tests__/Switch.test.jsx b/web-old/src/components/__tests__/Switch.test.jsx
deleted file mode 100644
index 354ed5c4f..000000000
--- a/web-old/src/components/__tests__/Switch.test.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { h } from 'preact';
-import Switch from '../Switch';
-import { fireEvent, render, screen } from '@testing-library/preact';
-
-describe('Switch', () => {
- test('renders a hidden checkbox', async () => {
- render(
-
-
-
-
- );
-
- const unchecked = screen.queryByTestId('unchecked-switch-input');
- expect(unchecked).toHaveAttribute('type', 'checkbox');
- expect(unchecked).not.toBeChecked();
-
- const checked = screen.queryByTestId('checked-switch-input');
- expect(checked).toHaveAttribute('type', 'checkbox');
- expect(checked).toBeChecked();
- });
-
- test('calls onChange callback when checked/unchecked', async () => {
- const handleChange = vi.fn();
- const { rerender } = render( );
- fireEvent.change(screen.queryByTestId('check-input'), { checked: true });
- expect(handleChange).toHaveBeenCalledWith('check', true);
-
- rerender( );
- fireEvent.change(screen.queryByTestId('check-input'), { checked: false });
- expect(handleChange).toHaveBeenCalledWith('check', false);
- });
-
- test('renders a label before', async () => {
- render( );
- const items = screen.queryAllByTestId(/check-.+/);
- expect(items[0]).toHaveTextContent('This is the label');
- expect(items[1]).toHaveAttribute('data-testid', 'check-input');
- });
-
- test('renders a label after', async () => {
- render( );
- const items = screen.queryAllByTestId(/check-.+/);
- expect(items[0]).toHaveAttribute('data-testid', 'check-input');
- expect(items[1]).toHaveTextContent('This is the label');
- });
-});
diff --git a/web-old/src/components/__tests__/TextField.test.jsx b/web-old/src/components/__tests__/TextField.test.jsx
deleted file mode 100644
index ce9aa52fe..000000000
--- a/web-old/src/components/__tests__/TextField.test.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { h } from 'preact';
-import TextField from '../TextField';
-import { render, screen, fireEvent } from '@testing-library/preact';
-
-describe('TextField', () => {
- test('can render a leading icon', async () => {
- render( );
- expect(screen.getByTestId('icon-leading')).toBeInTheDocument();
- });
-
- test('can render a trailing icon', async () => {
- render( );
- expect(screen.getByTestId('icon-trailing')).toBeInTheDocument();
- });
-
- test('can renders icons in correct positions', async () => {
- render( );
- const icons = screen.queryAllByTestId(/icon-.+/);
- expect(icons[0]).toHaveAttribute('data-testid', 'icon-leading');
- expect(icons[1]).toHaveAttribute('data-testid', 'icon-trailing');
- });
-
- test('onChange updates the value', async () => {
- const handleChangeText = vi.fn();
- render( );
-
- const input = screen.getByRole('textbox');
- fireEvent.input(input, { target: { value: 'i like tacos' } });
- expect(handleChangeText).toHaveBeenCalledWith('i like tacos');
- expect(input.value).toEqual('i like tacos');
- });
-
- test('still updates the value if an original value was given', async () => {
- render( );
-
- const input = screen.getByRole('textbox');
- fireEvent.input(input, { target: { value: 'i like tacos' } });
- expect(input.value).toEqual('i like tacos');
- });
-
- test('changes the value if the prop value changes', async () => {
- const { rerender } = render( );
-
- const input = screen.getByRole('textbox');
- fireEvent.input(input, { target: { value: 'i like tacos' } });
- expect(input.value).toEqual('i like tacos');
-
- rerender( );
- expect(input.value).toEqual('no, really, burritos');
- });
-});
-
-function FakeLeadingIcon() {
- return
;
-}
-
-function FakeTrailingIcon() {
- return
;
-}
diff --git a/web-old/src/components/__tests__/Toolltip.test.jsx b/web-old/src/components/__tests__/Toolltip.test.jsx
deleted file mode 100644
index 25634bd5a..000000000
--- a/web-old/src/components/__tests__/Toolltip.test.jsx
+++ /dev/null
@@ -1,115 +0,0 @@
-import { h, createRef } from 'preact';
-import Tooltip from '../Tooltip';
-import { render, screen } from '@testing-library/preact';
-
-describe('Tooltip', () => {
- test('renders in a relative position', async () => {
- vi
- .spyOn(window.HTMLElement.prototype, 'getBoundingClientRect')
- // relativeTo
- .mockReturnValueOnce({
- x: 100,
- y: 100,
- width: 50,
- height: 10,
- })
- // tooltip
- .mockReturnValueOnce({ width: 40, height: 15 });
-
- const ref = createRef();
- render(
-
- );
-
- const tooltip = await screen.findByRole('tooltip');
- const style = window.getComputedStyle(tooltip);
- expect(style.left).toEqual('103px');
- expect(style.top).toEqual('68.5px');
- });
-
- test('if too far right, renders to the left', async () => {
- window.innerWidth = 1024;
- vi
- .spyOn(window.HTMLElement.prototype, 'getBoundingClientRect')
- // relativeTo
- .mockReturnValueOnce({
- x: 1000,
- y: 100,
- width: 24,
- height: 10,
- })
- // tooltip
- .mockReturnValueOnce({ width: 50, height: 15 });
-
- const ref = createRef();
- render(
-
- );
-
- const tooltip = await screen.findByRole('tooltip');
- const style = window.getComputedStyle(tooltip);
- expect(style.left).toEqual('937px');
- expect(style.top).toEqual('97px');
- });
-
- test('if too far left, renders to the right', async () => {
- vi
- .spyOn(window.HTMLElement.prototype, 'getBoundingClientRect')
- // relativeTo
- .mockReturnValueOnce({
- x: 0,
- y: 100,
- width: 24,
- height: 10,
- })
- // tooltip
- .mockReturnValueOnce({ width: 50, height: 15 });
-
- const ref = createRef();
- render(
-
- );
-
- const tooltip = await screen.findByRole('tooltip');
- const style = window.getComputedStyle(tooltip);
- expect(style.left).toEqual('32px');
- expect(style.top).toEqual('97px');
- });
-
- test('if too close to top, renders to the bottom', async () => {
- window.scrollY = 90;
- vi
- .spyOn(window.HTMLElement.prototype, 'getBoundingClientRect')
- // relativeTo
- .mockReturnValueOnce({
- x: 100,
- y: 100,
- width: 24,
- height: 10,
- })
- // tooltip
- .mockReturnValueOnce({ width: 50, height: 15 });
-
- const ref = createRef();
- render(
-
- );
-
- const tooltip = await screen.findByRole('tooltip');
- const style = window.getComputedStyle(tooltip);
- expect(style.left).toEqual('84px');
- expect(style.top).toEqual('158.5px');
- });
-});
diff --git a/web-old/src/context/__tests__/index.test.jsx b/web-old/src/context/__tests__/index.test.jsx
deleted file mode 100644
index 60e8a2e7e..000000000
--- a/web-old/src/context/__tests__/index.test.jsx
+++ /dev/null
@@ -1,196 +0,0 @@
-import { h } from 'preact';
-import { set as setData } from 'idb-keyval';
-import { DarkModeProvider, useDarkMode, usePersistence } from '..';
-import { fireEvent, render, screen } from 'testing-library';
-import { useCallback } from 'preact/hooks';
-import * as WS from '../../api/ws';
-
-function DarkModeChecker() {
- const { currentMode } = useDarkMode();
- return {currentMode}
;
-}
-
-describe('DarkMode', () => {
- beforeEach(() => {
- vi.spyOn(WS, 'WsProvider').mockImplementation(({ children }) => children);
- });
-
- test('uses media by default', async () => {
- render(
-
-
-
- );
- const el = await screen.findByTestId('media');
- expect(el).toBeInTheDocument();
- });
-
- test('uses the mode stored in idb - dark', async () => {
- setData('darkmode', 'dark');
- render(
-
-
-
- );
- const el = await screen.findByTestId('dark');
- expect(el).toBeInTheDocument();
- expect(document.body.classList.contains('dark')).toBe(true);
- });
-
- test('uses the mode stored in idb - light', async () => {
- setData('darkmode', 'light');
- render(
-
-
-
- );
- const el = await screen.findByTestId('light');
- expect(el).toBeInTheDocument();
- expect(document.body.classList.contains('dark')).toBe(false);
- });
-
- test('allows updating the mode', async () => {
- setData('darkmode', 'dark');
-
- function Updater() {
- const { setDarkMode } = useDarkMode();
- const handleClick = useCallback(() => {
- setDarkMode('light');
- }, [setDarkMode]);
- return click me
;
- }
-
- render(
-
-
-
-
- );
-
- const dark = await screen.findByTestId('dark');
- expect(dark).toBeInTheDocument();
- expect(document.body.classList.contains('dark')).toBe(true);
-
- const button = await screen.findByText('click me');
- fireEvent.click(button);
-
- const light = await screen.findByTestId('light');
- expect(light).toBeInTheDocument();
- expect(document.body.classList.contains('dark')).toBe(false);
- });
-
- test('when using media, matches on preference', async () => {
- setData('darkmode', 'media');
- vi.spyOn(window, 'matchMedia').mockImplementation((query) => {
- if (query === '(prefers-color-scheme: dark)') {
- return { matches: true, addEventListener: vi.fn(), removeEventListener: vi.fn() };
- }
-
- throw new Error(`Unexpected query to matchMedia: ${query}`);
- });
- render(
-
-
-
- );
-
- const el = await screen.findByTestId('dark');
- expect(el).toBeInTheDocument();
- expect(document.body.classList.contains('dark')).toBe(true);
- });
-});
-
-describe('usePersistence', () => {
- test('returns a defaultValue initially', async () => {
- function Component() {
- const [value, , loaded] = usePersistence('tacos', 'my-default');
- return (
-
-
{loaded ? 'loaded' : 'not loaded'}
-
{value}
-
- );
- }
-
- render( );
-
- expect(screen.getByTestId('loaded')).toMatchInlineSnapshot(`
-
- not loaded
-
- `);
- expect(screen.getByTestId('value')).toMatchInlineSnapshot(`
-
- my-default
-
- `);
- });
-
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('updates with the previously-persisted value', async () => {
- setData('tacos', 'are delicious');
-
- function Component() {
- const [value, , loaded] = usePersistence('tacos', 'my-default');
- return (
-
-
{loaded ? 'loaded' : 'not loaded'}
-
{value}
-
- );
- }
-
- render( );
-
- await screen.findByText('loaded');
-
- expect(screen.getByTestId('loaded')).toMatchInlineSnapshot(`
-
- loaded
-
- `);
- expect(screen.getByTestId('value')).toMatchInlineSnapshot(`
-
- are delicious
-
- `);
- });
-
- test('can be updated manually', async () => {
- setData('darkmode', 'are delicious');
-
- function Component() {
- const [value, setValue] = usePersistence('tacos', 'my-default');
- const handleClick = useCallback(() => {
- setValue('super delicious');
- }, [setValue]);
- return (
-
- );
- }
-
- render( );
-
- const button = await screen.findByText('click me');
- fireEvent.click(button);
-
- expect(screen.getByTestId('value')).toMatchInlineSnapshot(`
-
- super delicious
-
- `);
- });
-});
diff --git a/web-old/src/context/index.jsx b/web-old/src/context/index.jsx
deleted file mode 100644
index 416eeb174..000000000
--- a/web-old/src/context/index.jsx
+++ /dev/null
@@ -1,111 +0,0 @@
-import { h, createContext } from 'preact';
-import { get as getData, set as setData } from 'idb-keyval';
-import { useCallback, useContext, useEffect, useLayoutEffect, useState } from 'preact/hooks';
-
-const DarkMode = createContext(null);
-
-export function DarkModeProvider({ children }) {
- const [persistedMode, setPersistedMode] = useState(null);
- const [currentMode, setCurrentMode] = useState(persistedMode !== 'media' ? persistedMode : null);
-
- const setDarkMode = useCallback(
- (value) => {
- setPersistedMode(value);
- setData('darkmode', value);
- setCurrentMode(value);
- },
- [setPersistedMode]
- );
-
- useEffect(() => {
- async function load() {
- const darkmode = await getData('darkmode');
- setDarkMode(darkmode || 'media');
- }
-
- load();
- }, [setDarkMode]);
-
- const handleMediaMatch = useCallback(
- ({ matches }) => {
- if (matches) {
- setCurrentMode('dark');
- } else {
- setCurrentMode('light');
- }
- },
- [setCurrentMode]
- );
-
- useEffect(() => {
- if (persistedMode !== 'media') {
- return;
- }
-
- const query = window.matchMedia('(prefers-color-scheme: dark)');
- query.addEventListener('change', handleMediaMatch);
- handleMediaMatch(query);
- }, [persistedMode, handleMediaMatch]);
-
- useLayoutEffect(() => {
- if (currentMode === 'dark') {
- document.body.classList.add('dark');
- } else {
- document.body.classList.remove('dark');
- }
- }, [currentMode]);
-
- return !persistedMode ? null : (
- {children}
- );
-}
-
-export function useDarkMode() {
- return useContext(DarkMode);
-}
-
-const Drawer = createContext(null);
-
-export function DrawerProvider({ children }) {
- const [showDrawer, setShowDrawer] = useState(false);
-
- return {children} ;
-}
-
-export function useDrawer() {
- return useContext(Drawer);
-}
-
-export function usePersistence(key, defaultValue = undefined) {
- const [value, setInternalValue] = useState(defaultValue);
- const [loaded, setLoaded] = useState(false);
-
- const setValue = useCallback(
- (value) => {
- setInternalValue(value);
- async function update() {
- await setData(key, value);
- }
-
- update();
- },
- [key]
- );
-
- useEffect(() => {
- setLoaded(false);
- setInternalValue(defaultValue);
-
- async function load() {
- const value = await getData(key);
- if (typeof value !== 'undefined') {
- setValue(value);
- }
- setLoaded(true);
- }
-
- load();
- }, [key, defaultValue, setValue]);
-
- return [value, setValue, loaded];
-}
diff --git a/web-old/src/env.js b/web-old/src/env.js
deleted file mode 100644
index 2ea76dc8f..000000000
--- a/web-old/src/env.js
+++ /dev/null
@@ -1 +0,0 @@
-export const ENV = import.meta.env.MODE;
\ No newline at end of file
diff --git a/web-old/src/hooks/index.jsx b/web-old/src/hooks/index.jsx
deleted file mode 100644
index 79a9390af..000000000
--- a/web-old/src/hooks/index.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
-
-export function useResizeObserver(...refs) {
- const [dimensions, setDimensions] = useState(
- new Array(refs.length).fill({ width: 0, height: 0, x: -Infinity, y: -Infinity })
- );
- const resizeObserver = useMemo(
- () =>
- new ResizeObserver((entries) => {
- window.requestAnimationFrame(() => {
- setDimensions(entries.map((entry) => entry.contentRect));
- });
- }),
- []
- );
-
- useEffect(() => {
- refs.forEach((ref) => {
- resizeObserver.observe(ref.current);
- });
-
- return () => {
- refs.forEach((ref) => {
- resizeObserver.unobserve(ref.current);
- });
- };
- }, [refs, resizeObserver]);
-
- return dimensions;
-}
-
-export function useIntersectionObserver() {
- const [entry, setEntry] = useState({});
- const [node, setNode] = useState(null);
-
- const observer = useRef(null);
-
- useEffect(() => {
- if (observer.current) {
- observer.current.disconnect();
- }
-
- observer.current = new IntersectionObserver((entries) => {
- window.requestAnimationFrame(() => {
- setEntry(entries[0]);
- });
- });
-
- if (node) {
- observer.current.observe(node);
- }
-
- return () => {
- observer.current.disconnect();
- };
- }, [node]);
-
- return [entry, setNode];
-}
diff --git a/web-old/src/hooks/useClickOutside.jsx b/web-old/src/hooks/useClickOutside.jsx
deleted file mode 100644
index 8fc14660c..000000000
--- a/web-old/src/hooks/useClickOutside.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { useEffect, useRef } from 'preact/hooks';
-
-// https://stackoverflow.com/a/54292872/2693528
-export const useClickOutside = (callback) => {
- const callbackRef = useRef(); // initialize mutable ref, which stores callback
- const innerRef = useRef(); // returned to client, who marks "border" element
-
- // update cb on each render, so second useEffect has access to current value
- useEffect(() => {
- callbackRef.current = callback;
- });
-
- useEffect(() => {
- document.addEventListener('click', handleClick);
- return () => document.removeEventListener('click', handleClick);
- function handleClick(e) {
- if (innerRef.current && callbackRef.current && !innerRef.current.contains(e.target)) callbackRef.current(e);
- }
- }, []);
-
- return innerRef; // convenience for client (doesn't need to init ref himself)
-};
diff --git a/web-old/src/hooks/useSearchString.jsx b/web-old/src/hooks/useSearchString.jsx
deleted file mode 100644
index b4fdaf3d0..000000000
--- a/web-old/src/hooks/useSearchString.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { useState, useCallback } from 'preact/hooks';
-
-const defaultSearchString = (limit) => `include_thumbnails=0&limit=${limit}`;
-
-export const useSearchString = (limit, searchParams) => {
- const { searchParams: initialSearchParams } = new URL(window.location);
- const _searchParams = searchParams || initialSearchParams.toString();
-
- const [searchString, changeSearchString] = useState(`${defaultSearchString(limit)}&${_searchParams}`);
-
- const setSearchString = useCallback(
- (limit, searchString) => {
- changeSearchString(`${defaultSearchString(limit)}&${searchString}`);
- },
- [changeSearchString]
- );
-
- const removeDefaultSearchKeys = useCallback((searchParams) => {
- searchParams.delete('limit');
- searchParams.delete('include_thumbnails');
- // removed deletion of "before" as its used by DatePicker
- // searchParams.delete('before');
- }, []);
-
- return { searchString, setSearchString, removeDefaultSearchKeys };
-};
diff --git a/web-old/src/icons/About.jsx b/web-old/src/icons/About.jsx
deleted file mode 100644
index 6271b2d52..000000000
--- a/web-old/src/icons/About.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function About({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(About);
diff --git a/web-old/src/icons/ActiveObject.jsx b/web-old/src/icons/ActiveObject.jsx
deleted file mode 100644
index 75f8da5e6..000000000
--- a/web-old/src/icons/ActiveObject.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function ActiveObject({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(ActiveObject);
diff --git a/web-old/src/icons/ArrowDownDouble.jsx b/web-old/src/icons/ArrowDownDouble.jsx
deleted file mode 100644
index 7685542e9..000000000
--- a/web-old/src/icons/ArrowDownDouble.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function ArrowDownDouble({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(ArrowDownDouble);
diff --git a/web-old/src/icons/ArrowDropdown.jsx b/web-old/src/icons/ArrowDropdown.jsx
deleted file mode 100644
index 0563e1194..000000000
--- a/web-old/src/icons/ArrowDropdown.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function ArrowDropdown({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(ArrowDropdown);
diff --git a/web-old/src/icons/ArrowDropup.jsx b/web-old/src/icons/ArrowDropup.jsx
deleted file mode 100644
index 8805e274c..000000000
--- a/web-old/src/icons/ArrowDropup.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function ArrowDropup({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(ArrowDropup);
diff --git a/web-old/src/icons/ArrowLeft.jsx b/web-old/src/icons/ArrowLeft.jsx
deleted file mode 100644
index 6ff892695..000000000
--- a/web-old/src/icons/ArrowLeft.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function ArrowLeft({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(ArrowLeft);
diff --git a/web-old/src/icons/ArrowLeftDouble.jsx b/web-old/src/icons/ArrowLeftDouble.jsx
deleted file mode 100644
index eaa25395c..000000000
--- a/web-old/src/icons/ArrowLeftDouble.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function ArrowLeftDouble({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(ArrowLeftDouble);
diff --git a/web-old/src/icons/ArrowRight.jsx b/web-old/src/icons/ArrowRight.jsx
deleted file mode 100644
index 455548887..000000000
--- a/web-old/src/icons/ArrowRight.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function ArrowRight({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(ArrowRight);
diff --git a/web-old/src/icons/ArrowRightDouble.jsx b/web-old/src/icons/ArrowRightDouble.jsx
deleted file mode 100644
index fc1960836..000000000
--- a/web-old/src/icons/ArrowRightDouble.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function ArrowRightDouble({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(ArrowRightDouble);
diff --git a/web-old/src/icons/ArrowUpDouble.jsx b/web-old/src/icons/ArrowUpDouble.jsx
deleted file mode 100644
index 7468a2b91..000000000
--- a/web-old/src/icons/ArrowUpDouble.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function ArrowUpDouble({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(ArrowUpDouble);
diff --git a/web-old/src/icons/Audio.jsx b/web-old/src/icons/Audio.jsx
deleted file mode 100644
index 4e178ccf0..000000000
--- a/web-old/src/icons/Audio.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Audio({ className = 'h-6 w-6', stroke = 'currentColor', onClick = () => {} }) {
- return (
-
-
-
-
-
- );
-}
-
-export default memo(Audio);
diff --git a/web-old/src/icons/AutoAwesome.jsx b/web-old/src/icons/AutoAwesome.jsx
deleted file mode 100644
index f464d3b96..000000000
--- a/web-old/src/icons/AutoAwesome.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function AutoAwesome({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(AutoAwesome);
diff --git a/web-old/src/icons/Calendar.jsx b/web-old/src/icons/Calendar.jsx
deleted file mode 100644
index fa4af76fa..000000000
--- a/web-old/src/icons/Calendar.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Calendar({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(Calendar);
diff --git a/web-old/src/icons/Camera.jsx b/web-old/src/icons/Camera.jsx
deleted file mode 100644
index fd0fcd13f..000000000
--- a/web-old/src/icons/Camera.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Camera({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(Camera);
diff --git a/web-old/src/icons/Clip.jsx b/web-old/src/icons/Clip.jsx
deleted file mode 100644
index a7fd81588..000000000
--- a/web-old/src/icons/Clip.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Clip({ className = 'h-6 w-6', stroke = 'currentColor', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(Clip);
diff --git a/web-old/src/icons/Clock.jsx b/web-old/src/icons/Clock.jsx
deleted file mode 100644
index e813e006d..000000000
--- a/web-old/src/icons/Clock.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Clock({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(Clock);
diff --git a/web-old/src/icons/Close.jsx b/web-old/src/icons/Close.jsx
deleted file mode 100644
index d40105c0c..000000000
--- a/web-old/src/icons/Close.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Close({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(Close);
diff --git a/web-old/src/icons/DarkMode.jsx b/web-old/src/icons/DarkMode.jsx
deleted file mode 100644
index 8a2abc5b4..000000000
--- a/web-old/src/icons/DarkMode.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function DarkMode({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(DarkMode);
diff --git a/web-old/src/icons/Delete.jsx b/web-old/src/icons/Delete.jsx
deleted file mode 100644
index f00da15ae..000000000
--- a/web-old/src/icons/Delete.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Delete({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(Delete);
diff --git a/web-old/src/icons/DeliveryTruck.jsx b/web-old/src/icons/DeliveryTruck.jsx
deleted file mode 100644
index 01a48e5f2..000000000
--- a/web-old/src/icons/DeliveryTruck.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function StationaryObject({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(StationaryObject);
diff --git a/web-old/src/icons/Download.jsx b/web-old/src/icons/Download.jsx
deleted file mode 100644
index cd6227b83..000000000
--- a/web-old/src/icons/Download.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Download({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(Download);
diff --git a/web-old/src/icons/Exit.jsx b/web-old/src/icons/Exit.jsx
deleted file mode 100644
index 35878d833..000000000
--- a/web-old/src/icons/Exit.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-function Exit({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(Exit);
diff --git a/web-old/src/icons/Face.jsx b/web-old/src/icons/Face.jsx
deleted file mode 100644
index f68218711..000000000
--- a/web-old/src/icons/Face.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Zone({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(Zone);
diff --git a/web-old/src/icons/FrigateRestart.jsx b/web-old/src/icons/FrigateRestart.jsx
deleted file mode 100644
index 9240678c7..000000000
--- a/web-old/src/icons/FrigateRestart.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function FrigateRestart({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(FrigateRestart);
diff --git a/web-old/src/icons/LicensePlate.jsx b/web-old/src/icons/LicensePlate.jsx
deleted file mode 100644
index e2f4aae8f..000000000
--- a/web-old/src/icons/LicensePlate.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function StationaryObject({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(StationaryObject);
diff --git a/web-old/src/icons/LightMode.jsx b/web-old/src/icons/LightMode.jsx
deleted file mode 100644
index 0609391d5..000000000
--- a/web-old/src/icons/LightMode.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function LightMode({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(LightMode);
diff --git a/web-old/src/icons/Menu.jsx b/web-old/src/icons/Menu.jsx
deleted file mode 100644
index 76ea9dd61..000000000
--- a/web-old/src/icons/Menu.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Menu({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(Menu);
diff --git a/web-old/src/icons/MenuOpen.jsx b/web-old/src/icons/MenuOpen.jsx
deleted file mode 100644
index c3b28308d..000000000
--- a/web-old/src/icons/MenuOpen.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function MenuOpen({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(MenuOpen);
diff --git a/web-old/src/icons/More.jsx b/web-old/src/icons/More.jsx
deleted file mode 100644
index 9747caa07..000000000
--- a/web-old/src/icons/More.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function More({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(More);
diff --git a/web-old/src/icons/Motion.jsx b/web-old/src/icons/Motion.jsx
deleted file mode 100644
index 18320d465..000000000
--- a/web-old/src/icons/Motion.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Motion({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(Motion);
diff --git a/web-old/src/icons/Next.jsx b/web-old/src/icons/Next.jsx
deleted file mode 100644
index b54e737e6..000000000
--- a/web-old/src/icons/Next.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Next({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(Next);
diff --git a/web-old/src/icons/Pause.jsx b/web-old/src/icons/Pause.jsx
deleted file mode 100644
index 3b6a143d6..000000000
--- a/web-old/src/icons/Pause.jsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Pause({ className = '' }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(Pause);
diff --git a/web-old/src/icons/Play.jsx b/web-old/src/icons/Play.jsx
deleted file mode 100644
index 5d1182631..000000000
--- a/web-old/src/icons/Play.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Play({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(Play);
diff --git a/web-old/src/icons/Previous.jsx b/web-old/src/icons/Previous.jsx
deleted file mode 100644
index c59dfcdef..000000000
--- a/web-old/src/icons/Previous.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Previous() {
- return (
-
-
-
- );
-}
-
-export default memo(Previous);
diff --git a/web-old/src/icons/Score.jsx b/web-old/src/icons/Score.jsx
deleted file mode 100644
index 2abed4b9e..000000000
--- a/web-old/src/icons/Score.jsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Score({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'currentColor', onClick = () => {} }) {
- return (
-
- percent
-
-
- );
-}
-
-export default memo(Score);
diff --git a/web-old/src/icons/SelectOnly.jsx b/web-old/src/icons/SelectOnly.jsx
deleted file mode 100644
index f0aca6bd8..000000000
--- a/web-old/src/icons/SelectOnly.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function SelectOnly({ className = 'h-5 w-5', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(SelectOnly);
diff --git a/web-old/src/icons/Settings.jsx b/web-old/src/icons/Settings.jsx
deleted file mode 100644
index a2dbafb60..000000000
--- a/web-old/src/icons/Settings.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Settings({ className = '' }) {
- return (
-
-
-
-
-
-
- );
-}
-
-export default memo(Settings);
diff --git a/web-old/src/icons/Snapshot.jsx b/web-old/src/icons/Snapshot.jsx
deleted file mode 100644
index 696b0808a..000000000
--- a/web-old/src/icons/Snapshot.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Snapshot({ className = 'h-6 w-6', stroke = 'currentColor', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(Snapshot);
diff --git a/web-old/src/icons/Speaker.jsx b/web-old/src/icons/Speaker.jsx
deleted file mode 100644
index e775e8365..000000000
--- a/web-old/src/icons/Speaker.jsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-
-export function Speaker({
- className = 'h-7 w-7',
- stroke = 'currentColor',
- onClick = () => {},
-}) {
- return (
-
-
-
- );
-}
-export default memo(Speaker);
diff --git a/web-old/src/icons/StarRecording.jsx b/web-old/src/icons/StarRecording.jsx
deleted file mode 100644
index e4923b68a..000000000
--- a/web-old/src/icons/StarRecording.jsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function StarRecording({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(StarRecording);
diff --git a/web-old/src/icons/StationaryObject.jsx b/web-old/src/icons/StationaryObject.jsx
deleted file mode 100644
index 12ff746bc..000000000
--- a/web-old/src/icons/StationaryObject.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function StationaryObject({ className = '' }) {
- return (
-
-
-
- );
-}
-
-export default memo(StationaryObject);
diff --git a/web-old/src/icons/Submitted.jsx b/web-old/src/icons/Submitted.jsx
deleted file mode 100644
index e7612a79f..000000000
--- a/web-old/src/icons/Submitted.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Submitted({ className = 'h-6 w-6', inner_fill = 'none', outer_stroke = 'currentColor', onClick = () => {} }) {
- return (
-
-
-
-
-
- );
-}
-
-export default memo(Submitted);
diff --git a/web-old/src/icons/UploadPlus.jsx b/web-old/src/icons/UploadPlus.jsx
deleted file mode 100644
index 7fd2f884a..000000000
--- a/web-old/src/icons/UploadPlus.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function UploadPlus({ className = 'h-6 w-6', stroke = 'currentColor', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(UploadPlus);
diff --git a/web-old/src/icons/WebUI.jsx b/web-old/src/icons/WebUI.jsx
deleted file mode 100644
index 214f30a60..000000000
--- a/web-old/src/icons/WebUI.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function WebUI({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
- );
-}
-
-export default memo(WebUI);
diff --git a/web-old/src/icons/Zone.jsx b/web-old/src/icons/Zone.jsx
deleted file mode 100644
index b19205d1f..000000000
--- a/web-old/src/icons/Zone.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { h } from 'preact';
-import { memo } from 'preact/compat';
-
-export function Zone({ className = 'h-6 w-6', stroke = 'currentColor', fill = 'none', onClick = () => {} }) {
- return (
-
-
-
-
- );
-}
-
-export default memo(Zone);
diff --git a/web-old/src/index.css b/web-old/src/index.css
deleted file mode 100644
index f45694699..000000000
--- a/web-old/src/index.css
+++ /dev/null
@@ -1,55 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-.activityindicator {
- border-top-color: currentColor;
- -webkit-animation: spinner 0.75s linear infinite;
- animation: spinner 0.75s linear infinite;
-}
-
-@-webkit-keyframes spinner {
- 0% {
- -webkit-transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- }
-}
-
-@keyframes spinner {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
-}
-
-.jsmpeg canvas {
- position: static !important;
-}
-
-.hide-scroll::-webkit-scrollbar {
- display: none;
-}
-
-.hide-scroll {
- -ms-overflow-style: none; /* IE and Edge */
- scrollbar-width: none; /* Firefox */
-}
-
-/*
- Hide some videoplayer controls on mobile devices to
- align the video player and bottom control bar properly.
-*/
-@media only screen and (max-width: 700px) {
- .small-player .vjs-time-control,
- .small-player .vjs-time-divider {
- display: none;
- }
- div.vjs-control-bar > .skip-back.skip-5,
- div.vjs-control-bar > .skip-forward.skip-10 {
- display: none;
- }
-}
diff --git a/web-old/src/main.tsx b/web-old/src/main.tsx
deleted file mode 100644
index e01449d2b..000000000
--- a/web-old/src/main.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import { render } from 'preact'
-import App from './app'
-import { ApiProvider } from './api';
-import './index.css'
-
-render(
-
- , document.getElementById('app') as HTMLElement)
diff --git a/web-old/src/preact.d.ts b/web-old/src/preact.d.ts
deleted file mode 100644
index 98101ac9b..000000000
--- a/web-old/src/preact.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-import JSX = preact.JSX
-
-// temporary until codebase is converted to typescript
-declare module "*";
\ No newline at end of file
diff --git a/web-old/src/routes/Birdseye.jsx b/web-old/src/routes/Birdseye.jsx
deleted file mode 100644
index 3ff1ffac1..000000000
--- a/web-old/src/routes/Birdseye.jsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import { h, Fragment } from 'preact';
-import { usePersistence } from '../context';
-import ActivityIndicator from '../components/ActivityIndicator';
-import JSMpegPlayer from '../components/JSMpegPlayer';
-import Heading from '../components/Heading';
-import WebRtcPlayer from '../components/WebRtcPlayer';
-import '../components/MsePlayer';
-import useSWR from 'swr';
-import { useMemo } from 'preact/hooks';
-import CameraControlPanel from '../components/CameraControlPanel';
-import { baseUrl } from '../api/baseUrl';
-
-export default function Birdseye() {
- const { data: config } = useSWR('config');
-
- const [viewSource, setViewSource, sourceIsLoaded] = usePersistence('birdseye-source', getDefaultLiveMode(config));
- const sourceValues = ['mse', 'webrtc', 'jsmpeg'];
-
- const ptzCameras = useMemo(() => {
- if (!config) {
- return [];
- }
-
- return Object.entries(config.cameras)
- .filter(([_, conf]) => conf.onvif?.host && conf.onvif.host != '')
- .map(([_, camera]) => camera.name);
- }, [config]);
-
- const [isMaxWidth, setIsMaxWidth] = usePersistence('birdseye-width', false);
-
- if (!config || !sourceIsLoaded) {
- return ;
- }
-
- let player;
- const playerClass = ptzCameras.length || isMaxWidth ? 'w-full' : 'max-w-5xl xl:w-1/2';
- if (viewSource == 'mse' && config.birdseye.restream) {
- if ('MediaSource' in window || 'ManagedMediaSource' in window) {
- player = (
-
-
-
-
-
- );
- } else {
- player = (
-
-
- MSE is only supported on iOS 17.1+. You'll need to update if available or use jsmpeg / webRTC streams. See the docs for more info.
-
-
- );
- }
- } else if (viewSource == 'webrtc') {
- player = (
-
-
-
-
-
- );
- } else {
- player = (
-
-
-
-
-
- );
- }
-
- return (
-
-
-
- Birdseye
-
-
- {!ptzCameras.length && (
- setIsMaxWidth(!isMaxWidth)}
- >
- Toggle width
-
- )}
-
- {config.birdseye.restream && (
- setViewSource(e.target.value)}
- key="width-changer"
- >
- {sourceValues.map((item) => (
-
- {item}
-
- ))}
-
- )}
-
-
-
-
- {' '}
- {/* Use dynamic class */}
- {player}
-
-
- {ptzCameras.length ? (
-
-
Control Panel
- {ptzCameras.map((camera) => (
-
- {camera.replaceAll('_', ' ')}
-
-
- ))}
-
- ) : null}
-
-
- );
-}
-
-function getDefaultLiveMode(config) {
- if (config) {
- if (config.birdseye.restream) {
- return config.ui.live_mode;
- }
-
- return 'jsmpeg';
- }
-
- return undefined;
-}
diff --git a/web-old/src/routes/Camera.jsx b/web-old/src/routes/Camera.jsx
deleted file mode 100644
index 9260b41fc..000000000
--- a/web-old/src/routes/Camera.jsx
+++ /dev/null
@@ -1,234 +0,0 @@
-import { h, Fragment } from 'preact';
-import AutoUpdatingCameraImage from '../components/AutoUpdatingCameraImage';
-import ActivityIndicator from '../components/ActivityIndicator';
-import JSMpegPlayer from '../components/JSMpegPlayer';
-import Button from '../components/Button';
-import Card from '../components/Card';
-import Heading from '../components/Heading';
-import Link from '../components/Link';
-import SettingsIcon from '../icons/Settings';
-import Switch from '../components/Switch';
-import ButtonsTabbed from '../components/ButtonsTabbed';
-import { usePersistence } from '../context';
-import { useCallback, useMemo, useState } from 'preact/hooks';
-import { useApiHost } from '../api';
-import useSWR from 'swr';
-import WebRtcPlayer from '../components/WebRtcPlayer';
-import '../components/MsePlayer';
-import CameraControlPanel from '../components/CameraControlPanel';
-import { baseUrl } from '../api/baseUrl';
-
-const emptyObject = Object.freeze({});
-
-export default function Camera({ camera }) {
- const { data: config } = useSWR('config');
- const { data: trackedLabels } = useSWR(['labels', { camera }]);
- const apiHost = useApiHost();
- const [showSettings, setShowSettings] = useState(false);
- const [viewMode, setViewMode] = useState('live');
-
- const cameraConfig = config?.cameras[camera];
- const restreamEnabled =
- cameraConfig && Object.keys(config.go2rtc.streams || {}).includes(cameraConfig.live.stream_name);
- const jsmpegWidth = cameraConfig
- ? Math.round(cameraConfig.live.height * (cameraConfig.detect.width / cameraConfig.detect.height))
- : 0;
- const [viewSource, setViewSource, sourceIsLoaded] = usePersistence(
- `${camera}-source`,
- getDefaultLiveMode(config, cameraConfig, restreamEnabled)
- );
- const sourceValues = restreamEnabled ? ['mse', 'webrtc', 'jsmpeg'] : ['jsmpeg'];
- const [options, setOptions] = usePersistence(`${camera}-feed`, emptyObject);
-
- const handleSetOption = useCallback(
- (id, value) => {
- const newOptions = { ...options, [id]: value };
- setOptions(newOptions);
- },
- [options, setOptions]
- );
-
- const searchParams = useMemo(
- () =>
- new URLSearchParams(
- Object.keys(options).reduce((memo, key) => {
- memo.push([key, options[key] === true ? '1' : '0']);
- return memo;
- }, [])
- ),
- [options]
- );
-
- const handleToggleSettings = useCallback(() => {
- setShowSettings(!showSettings);
- }, [showSettings, setShowSettings]);
-
- if (!cameraConfig || !sourceIsLoaded) {
- return ;
- }
-
- if (!restreamEnabled) {
- setViewSource('jsmpeg');
- }
-
- const optionContent = showSettings ? (
-
-
-
-
-
-
-
- Mask & Zone creator
-
- ) : null;
-
- let player;
- if (viewMode === 'live') {
- if (viewSource == 'mse' && restreamEnabled) {
- if ('MediaSource' in window || 'ManagedMediaSource' in window) {
- player = (
-
-
-
-
-
- );
- } else {
- player = (
-
-
- MSE is only supported on iOS 17.1+. You'll need to update if available or use jsmpeg / webRTC streams. See the docs for more info.
-
-
- );
- }
- } else if (viewSource == 'webrtc' && restreamEnabled) {
- player = (
-
-
-
-
-
- );
- } else {
- player = (
-
-
-
-
-
- );
- }
- } else if (viewMode === 'debug') {
- player = (
-
-
-
-
-
-
- {' '}
- {showSettings ? 'Hide' : 'Show'} Options
-
- {showSettings ? : null}
-
- );
- }
-
- return (
-
-
-
- {camera.replaceAll('_', ' ')}
-
- setViewSource(e.target.value)}
- >
- {sourceValues.map((item) => (
-
- {item}
-
- ))}
-
-
-
-
-
- {player}
-
- {cameraConfig?.onvif?.host && (
-
- Control Panel
-
-
- )}
-
-
-
Tracked objects
-
- {(trackedLabels || []).map((objectType) => (
- }
- />
- ))}
-
-
-
- );
-}
-
-function getDefaultLiveMode(config, cameraConfig, restreamEnabled) {
- if (cameraConfig) {
- if (restreamEnabled) {
- return config.ui.live_mode;
- }
-
- return 'jsmpeg';
- }
-
- return undefined;
-}
diff --git a/web-old/src/routes/CameraMap.jsx b/web-old/src/routes/CameraMap.jsx
deleted file mode 100644
index a7b96e851..000000000
--- a/web-old/src/routes/CameraMap.jsx
+++ /dev/null
@@ -1,752 +0,0 @@
-import { h } from 'preact';
-import Card from '../components/Card.jsx';
-import Button from '../components/Button.jsx';
-import Heading from '../components/Heading.jsx';
-import Switch from '../components/Switch.jsx';
-import { useResizeObserver } from '../hooks';
-import { useCallback, useMemo, useRef, useState } from 'preact/hooks';
-import { useApiHost } from '../api';
-import useSWR from 'swr';
-import axios from 'axios';
-export default function CameraMasks({ camera }) {
- const { data: config } = useSWR('config');
- const apiHost = useApiHost();
- const imageRef = useRef(null);
- const [snap, setSnap] = useState(true);
-
- const cameraConfig = config.cameras[camera];
- const {
- motion: { mask: motionMask },
- objects: { filters: objectFilters },
- zones,
- } = cameraConfig;
-
- const { width, height } = cameraConfig.detect;
-
- const [{ width: scaledWidth }] = useResizeObserver(imageRef);
- const imageScale = scaledWidth / width;
-
- const [motionMaskPoints, setMotionMaskPoints] = useState(
- Array.isArray(motionMask)
- ? motionMask.map((mask) => getPolylinePoints(mask))
- : motionMask
- ? [getPolylinePoints(motionMask)]
- : []
- );
-
- const [zonePoints, setZonePoints] = useState(
- Object.keys(zones).reduce((memo, zone) => ({ ...memo, [zone]: getPolylinePoints(zones[zone].coordinates) }), {})
- );
-
- const [objectMaskPoints, setObjectMaskPoints] = useState(
- Object.keys(objectFilters).reduce(
- (memo, name) => ({
- ...memo,
- [name]: Array.isArray(objectFilters[name].mask)
- ? objectFilters[name].mask.map((mask) => getPolylinePoints(mask))
- : objectFilters[name].mask
- ? [getPolylinePoints(objectFilters[name].mask)]
- : [],
- }),
- {}
- )
- );
-
- const [editing, setEditing] = useState({ set: motionMaskPoints, key: 0, fn: setMotionMaskPoints });
- const [success, setSuccess] = useState();
- const [error, setError] = useState();
-
- const handleUpdateEditable = useCallback(
- (newPoints) => {
- let newSet;
- if (Array.isArray(editing.set)) {
- newSet = [...editing.set];
- newSet[editing.key] = newPoints;
- } else if (editing.subkey !== undefined) {
- newSet = { ...editing.set };
- newSet[editing.key][editing.subkey] = newPoints;
- } else {
- newSet = { ...editing.set, [editing.key]: newPoints };
- }
- editing.set = newSet;
- editing.fn(newSet);
- },
- [editing]
- );
-
- // Motion mask methods
- const handleAddMask = useCallback(() => {
- const newMotionMaskPoints = [...motionMaskPoints, []];
- setMotionMaskPoints(newMotionMaskPoints);
- setEditing({ set: newMotionMaskPoints, key: newMotionMaskPoints.length - 1, fn: setMotionMaskPoints });
- }, [motionMaskPoints, setMotionMaskPoints]);
-
- const handleEditMask = useCallback(
- (key) => {
- setEditing({ set: motionMaskPoints, key, fn: setMotionMaskPoints });
- },
- [setEditing, motionMaskPoints, setMotionMaskPoints]
- );
-
- const handleRemoveMask = useCallback(
- (key) => {
- const newMotionMaskPoints = [...motionMaskPoints];
- newMotionMaskPoints.splice(key, 1);
- setMotionMaskPoints(newMotionMaskPoints);
- },
- [motionMaskPoints, setMotionMaskPoints]
- );
-
- const handleCopyMotionMasks = useCallback(() => {
- const textToCopy = ` motion:
- mask:
- ${motionMaskPoints.map((mask) => ` - ${polylinePointsToPolyline(mask)}`).join('\n')}`;
-
- if (window.navigator.clipboard && window.navigator.clipboard.writeText) {
- // Use Clipboard API if available
- window.navigator.clipboard.writeText(textToCopy).catch((err) => {
- throw new Error('Failed to copy text: ', err);
- });
- } else {
- // Fallback to document.execCommand('copy')
- const textarea = document.createElement('textarea');
- textarea.value = textToCopy;
- document.body.appendChild(textarea);
- textarea.select();
-
- try {
- const successful = document.execCommand('copy');
- if (!successful) {
- throw new Error('Failed to copy text');
- }
- } catch (err) {
- throw new Error('Failed to copy text: ', err);
- }
-
- document.body.removeChild(textarea);
- }
- }, [motionMaskPoints]);
-
- const handleSaveMotionMasks = useCallback(async () => {
- try {
- const queryParameters = motionMaskPoints
- .map((mask, index) => `cameras.${camera}.motion.mask.${index}=${polylinePointsToPolyline(mask)}`)
- .join('&');
- const endpoint = `config/set?${queryParameters}`;
- const response = await axios.put(endpoint);
- if (response.status === 200) {
- setSuccess(response.data.message);
- }
- } catch (error) {
- if (error.response) {
- setError(error.response.data.message);
- } else {
- setError(error.message);
- }
- }
- }, [camera, motionMaskPoints]);
-
- // Zone methods
- const handleEditZone = useCallback(
- (key) => {
- setEditing({ set: zonePoints, key, fn: setZonePoints });
- },
- [setEditing, zonePoints, setZonePoints]
- );
-
- const handleAddZone = useCallback(() => {
- const n = Object.keys(zonePoints).filter((name) => name.startsWith('zone_')).length;
- const zoneName = `zone_${n}`;
- const newZonePoints = { ...zonePoints, [zoneName]: [] };
- setZonePoints(newZonePoints);
- setEditing({ set: newZonePoints, key: zoneName, fn: setZonePoints });
- }, [zonePoints, setZonePoints]);
-
- const handleRemoveZone = useCallback(
- (key) => {
- const newZonePoints = { ...zonePoints };
- delete newZonePoints[key];
- setZonePoints(newZonePoints);
- },
- [zonePoints, setZonePoints]
- );
-
- const handleCopyZones = useCallback(async () => {
- const textToCopy = ` zones:
-${Object.keys(zonePoints)
- .map(
- (zoneName) => ` ${zoneName}:
- coordinates: ${polylinePointsToPolyline(zonePoints[zoneName])}`
- )
- .join('\n')}`;
-
- if (window.navigator.clipboard && window.navigator.clipboard.writeText) {
- // Use Clipboard API if available
- window.navigator.clipboard.writeText(textToCopy).catch((err) => {
- throw new Error('Failed to copy text: ', err);
- });
- } else {
- // Fallback to document.execCommand('copy')
- const textarea = document.createElement('textarea');
- textarea.value = textToCopy;
- document.body.appendChild(textarea);
- textarea.select();
-
- try {
- const successful = document.execCommand('copy');
- if (!successful) {
- throw new Error('Failed to copy text');
- }
- } catch (err) {
- throw new Error('Failed to copy text: ', err);
- }
-
- document.body.removeChild(textarea);
- }
- }, [zonePoints]);
-
- const handleSaveZones = useCallback(async () => {
- try {
- const queryParameters = Object.keys(zonePoints)
- .map(
- (zoneName) =>
- `cameras.${camera}.zones.${zoneName}.coordinates=${polylinePointsToPolyline(zonePoints[zoneName])}`
- )
- .join('&');
- const endpoint = `config/set?${queryParameters}`;
- const response = await axios.put(endpoint);
- if (response.status === 200) {
- setSuccess(response.data);
- }
- } catch (error) {
- if (error.response) {
- setError(error.response.data.message);
- } else {
- setError(error.message);
- }
- }
- }, [camera, zonePoints]);
-
- // Object methods
- const handleEditObjectMask = useCallback(
- (key, subkey) => {
- setEditing({ set: objectMaskPoints, key, subkey, fn: setObjectMaskPoints });
- },
- [setEditing, objectMaskPoints, setObjectMaskPoints]
- );
-
- const handleAddObjectMask = useCallback(() => {
- const n = Object.keys(objectMaskPoints).filter((name) => name.startsWith('object_')).length;
- const newObjectName = `object_${n}`;
- const newObjectMaskPoints = { ...objectMaskPoints, [newObjectName]: [[]] };
- setObjectMaskPoints(newObjectMaskPoints);
- setEditing({ set: newObjectMaskPoints, key: newObjectName, subkey: 0, fn: setObjectMaskPoints });
- }, [objectMaskPoints, setObjectMaskPoints, setEditing]);
-
- const handleRemoveObjectMask = useCallback(
- (key, subkey) => {
- const newObjectMaskPoints = { ...objectMaskPoints };
- delete newObjectMaskPoints[key][subkey];
- setObjectMaskPoints(newObjectMaskPoints);
- },
- [objectMaskPoints, setObjectMaskPoints]
- );
-
- const handleCopyObjectMasks = useCallback(async () => {
- await window.navigator.clipboard.writeText(` objects:
- filters:
-${Object.keys(objectMaskPoints)
- .map((objectName) =>
- objectMaskPoints[objectName].length
- ? ` ${objectName}:
- mask: ${polylinePointsToPolyline(objectMaskPoints[objectName])}`
- : ''
- )
- .filter(Boolean)
- .join('\n')}`);
- }, [objectMaskPoints]);
-
- const handleSaveObjectMasks = useCallback(async () => {
- try {
- const queryParameters = Object.keys(objectMaskPoints)
- .filter((objectName) => objectMaskPoints[objectName].length > 0)
- .map(
- (objectName, index) =>
- `cameras.${camera}.objects.filters.${objectName}.mask.${index}=${polylinePointsToPolyline(
- objectMaskPoints[objectName]
- )}`
- )
- .join('&');
- const endpoint = `config/set?${queryParameters}`;
- const response = await axios.put(endpoint);
- if (response.status === 200) {
- setSuccess(response.data);
- }
- } catch (error) {
- if (error.response) {
- setError(error.response.data.message);
- } else {
- setError(error.message);
- }
- }
- }, [camera, objectMaskPoints]);
-
- const handleAddToObjectMask = useCallback(
- (key) => {
- const newObjectMaskPoints = { ...objectMaskPoints, [key]: [...objectMaskPoints[key], []] };
- setObjectMaskPoints(newObjectMaskPoints);
- setEditing({
- set: newObjectMaskPoints,
- key,
- subkey: newObjectMaskPoints[key].length - 1,
- fn: setObjectMaskPoints,
- });
- },
- [objectMaskPoints, setObjectMaskPoints, setEditing]
- );
-
- const handleChangeSnap = useCallback(
- (id, value) => {
- setSnap(value);
- },
- [setSnap]
- );
-
- return (
-
-
{camera} mask & zone creator
-
-
- This tool can help you create masks & zones for your {camera} camera.
-
- Click to add a point.
- Click and hold on an existing point to move it.
- Right-Click on an existing point to delete it.
-
-
- }
- header="Instructions"
- />
-
-
- When done, copy each mask configuration into your config.yml file restart
- your Frigate instance to save your changes.
-
- }
- header="Warning"
- />
-
- {success && {success}
}
- {error && {error}
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-function maskYamlKeyPrefix() {
- return ' - ';
-}
-
-function zoneYamlKeyPrefix(_points, key) {
- return ` ${key}:
- coordinates: `;
-}
-
-function objectYamlKeyPrefix() {
- return ' - ';
-}
-
-const MaskInset = 20;
-
-function boundedSize(value, maxValue, snap) {
- const newValue = Math.min(Math.max(0, Math.round(value)), maxValue);
- if (snap) {
- if (newValue <= MaskInset) {
- return 0;
- } else if (maxValue - newValue <= MaskInset) {
- return maxValue;
- }
- }
-
- return newValue;
-}
-
-function EditableMask({ onChange, points, scale, snap, width, height, setError }) {
- const boundingRef = useRef(null);
-
- const handleMovePoint = useCallback(
- (index, newX, newY) => {
- if (newX < 0 && newY < 0) {
- return;
- }
- const x = boundedSize(newX / scale, width, snap);
- const y = boundedSize(newY / scale, height, snap);
-
- const newPoints = [...points];
- newPoints[index] = [x, y];
- onChange(newPoints);
- },
- [height, width, onChange, scale, points, snap]
- );
-
- // Add a new point between the closest two other points
- const handleAddPoint = useCallback(
- (event) => {
- if (!points) {
- setError('You must choose an item to edit or add a new item before adding a point.');
- return
- }
-
- const { offsetX, offsetY } = event;
- const scaledX = boundedSize((offsetX - MaskInset) / scale, width, snap);
- const scaledY = boundedSize((offsetY - MaskInset) / scale, height, snap);
- const newPoint = [scaledX, scaledY];
-
- const { index } = points.reduce(
- (result, point, i) => {
- const nextPoint = points.length === i + 1 ? points[0] : points[i + 1];
- const distance0 = Math.sqrt(Math.pow(point[0] - newPoint[0], 2) + Math.pow(point[1] - newPoint[1], 2));
- const distance1 = Math.sqrt(Math.pow(point[0] - nextPoint[0], 2) + Math.pow(point[1] - nextPoint[1], 2));
- const distance = distance0 + distance1;
- return distance < result.distance ? { distance, index: i } : result;
- },
- { distance: Infinity, index: -1 }
- );
- const newPoints = [...points];
- newPoints.splice(index, 0, newPoint);
- onChange(newPoints);
- },
- [height, width, scale, points, onChange, snap, setError]
- );
-
- const handleRemovePoint = useCallback(
- (index) => {
- const newPoints = [...points];
- newPoints.splice(index, 1);
- onChange(newPoints);
- },
- [points, onChange]
- );
-
- const scaledPoints = useMemo(() => scalePolylinePoints(points, scale), [points, scale]);
-
- return (
-
- {!scaledPoints
- ? null
- : scaledPoints.map(([x, y], i) => (
-
- ))}
-
-
- {!scaledPoints ? null : (
-
-
-
- )}
-
-
- );
-}
-
-function MaskValues({
- isMulti = false,
- editing,
- title,
- onAdd,
- onCopy,
- onSave,
- onCreate,
- onEdit,
- onRemove,
- points,
- yamlPrefix,
- yamlKeyPrefix,
-}) {
- const [showButtons, setShowButtons] = useState(false);
-
- const handleMousein = useCallback(() => {
- setShowButtons(true);
- }, [setShowButtons]);
-
- const handleMouseout = useCallback(
- (event) => {
- const el = event.toElement || event.relatedTarget;
- if (!el || el.parentNode === event.target) {
- return;
- }
- setShowButtons(false);
- },
- [setShowButtons]
- );
-
- const handleEdit = useCallback(
- (event) => {
- const { key, subkey } = event.target.dataset;
- onEdit(key, subkey);
- },
- [onEdit]
- );
-
- const handleRemove = useCallback(
- (event) => {
- const { key, subkey } = event.target.dataset;
- onRemove(key, subkey);
- },
- [onRemove]
- );
-
- const handleAdd = useCallback(
- (event) => {
- const { key } = event.target.dataset;
- onAdd(key);
- },
- [onAdd]
- );
-
- return (
-
-
-
- {title}
-
- Copy
- Add
- Save
-
-
- {yamlPrefix}
- {Object.keys(points).map((mainkey) => {
- if (isMulti) {
- return (
-
- {` ${mainkey}:\n mask:\n`}
- {onAdd && showButtons ? (
-
- {`Add to ${mainkey}`}
-
- ) : null}
- {points[mainkey].map((item, subkey) => (
-
- ))}
-
- );
- }
- return (
-
- );
- })}
-
-
- );
-}
-
-function Item({ mainkey, subkey, editing, handleEdit, points, showButtons, _handleAdd, handleRemove, yamlKeyPrefix }) {
- return (
-
- {`${yamlKeyPrefix(points, mainkey, subkey)}${polylinePointsToPolyline(points)}`}
- {showButtons ? (
-
- Remove
-
- ) : null}
-
- );
-}
-
-function getPolylinePoints(polyline) {
- if (!polyline) {
- return;
- }
-
- return polyline.split(',').reduce((memo, point, i) => {
- if (i % 2) {
- memo[memo.length - 1].push(parseInt(point, 10));
- } else {
- memo.push([parseInt(point, 10)]);
- }
- return memo;
- }, []);
-}
-
-function scalePolylinePoints(polylinePoints, scale) {
- if (!polylinePoints) {
- return;
- }
-
- return polylinePoints.map(([x, y]) => [Math.round(x * scale), Math.round(y * scale)]);
-}
-
-function polylinePointsToPolyline(polylinePoints) {
- if (!polylinePoints) {
- return;
- }
- return polylinePoints.reduce((memo, [x, y]) => `${memo}${x},${y},`, '').replace(/,$/, '');
-}
-
-const PolyPointRadius = 10;
-function PolyPoint({ boundingRef, index, x, y, onMove, onRemove }) {
- const [hidden, setHidden] = useState(false);
-
- const handleDragOver = useCallback(
- (event) => {
- if (
- !boundingRef.current ||
- (event.target !== boundingRef.current && !boundingRef.current.contains(event.target))
- ) {
- return;
- }
- onMove(index, event.layerX - PolyPointRadius * 2, event.layerY - PolyPointRadius * 2);
- },
- [onMove, index, boundingRef]
- );
-
- const handleDragStart = useCallback(() => {
- boundingRef.current && boundingRef.current.addEventListener('dragover', handleDragOver, false);
- setHidden(true);
- }, [setHidden, boundingRef, handleDragOver]);
-
- const handleDragEnd = useCallback(() => {
- boundingRef.current && boundingRef.current.removeEventListener('dragover', handleDragOver);
- setHidden(false);
- }, [setHidden, boundingRef, handleDragOver]);
-
- const handleRightClick = useCallback(
- (event) => {
- event.preventDefault();
- onRemove(index);
- },
- [onRemove, index]
- );
-
- const handleClick = useCallback((event) => {
- event.stopPropagation();
- event.preventDefault();
- }, []);
-
- return (
-
- );
-}
diff --git a/web-old/src/routes/Camera_V2.jsx b/web-old/src/routes/Camera_V2.jsx
deleted file mode 100644
index 15ee1a996..000000000
--- a/web-old/src/routes/Camera_V2.jsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import { h, Fragment } from 'preact';
-import JSMpegPlayer from '../components/JSMpegPlayer';
-import Heading from '../components/Heading';
-import { useState } from 'preact/hooks';
-import useSWR from 'swr';
-import { Tabs, TextTab } from '../components/Tabs';
-import { LiveChip } from '../components/LiveChip';
-import { DebugCamera } from '../components/DebugCamera';
-import HistoryViewer from '../components/HistoryViewer/HistoryViewer.tsx';
-
-export default function Camera({ camera }) {
- const { data: config } = useSWR('config');
-
- const [playerType, setPlayerType] = useState('live');
-
- const cameraConfig = config?.cameras[camera];
-
- const handleTabChange = (index) => {
- if (index === 0) {
- setPlayerType('history');
- } else if (index === 1) {
- setPlayerType('live');
- } else if (index === 2) {
- setPlayerType('debug');
- }
- };
-
- return (
-
-
-
-
- {(playerType === 'live' || playerType === 'debug') && (
-
-
- {camera}
-
-
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-const RenderPlayer = function ({ camera, cameraConfig, playerType }) {
- const liveWidth = Math.round(cameraConfig.live.height * (cameraConfig.detect.width / cameraConfig.detect.height));
- if (playerType === 'live') {
- return (
-
-
-
-
-
- );
- } else if (playerType === 'history') {
- return ;
- } else if (playerType === 'debug') {
- return ;
- }
- return ;
-};
diff --git a/web-old/src/routes/Cameras.jsx b/web-old/src/routes/Cameras.jsx
deleted file mode 100644
index 18128f738..000000000
--- a/web-old/src/routes/Cameras.jsx
+++ /dev/null
@@ -1,186 +0,0 @@
-import { h, Fragment } from 'preact';
-import ActivityIndicator from '../components/ActivityIndicator';
-import Card from '../components/Card';
-import CameraImage from '../components/CameraImage';
-import AudioIcon from '../icons/Audio';
-import ClipIcon from '../icons/Clip';
-import MotionIcon from '../icons/Motion';
-import SettingsIcon from '../icons/Settings';
-import SnapshotIcon from '../icons/Snapshot';
-import { useAudioState, useDetectState, useRecordingsState, useSnapshotsState } from '../api/ws';
-import { useMemo } from 'preact/hooks';
-import useSWR from 'swr';
-import { useRef, useState } from 'react';
-import { useResizeObserver } from '../hooks';
-import Dialog from '../components/Dialog';
-import Switch from '../components/Switch';
-import Heading from '../components/Heading';
-import Button from '../components/Button';
-
-export default function Cameras() {
- const { data: config } = useSWR('config');
-
- const containerRef = useRef(null);
- const [{ width: containerWidth }] = useResizeObserver(containerRef);
- // Add scrollbar width (when visible) to the available observer width to eliminate screen juddering.
- // https://github.com/blakeblackshear/frigate/issues/1657
- let scrollBarWidth = 0;
- if (window.innerWidth && document.body.offsetWidth) {
- scrollBarWidth = window.innerWidth - document.body.offsetWidth;
- }
- const availableWidth = scrollBarWidth ? containerWidth + scrollBarWidth : containerWidth;
-
- return !config ? (
-
- ) : (
-
-
-
- );
-}
-
-function SortedCameras({ config, unsortedCameras, availableWidth }) {
- const sortedCameras = useMemo(
- () =>
- Object.entries(unsortedCameras)
- .filter(([_, conf]) => conf.ui.dashboard)
- .sort(([_, aConf], [__, bConf]) => aConf.ui.order - bConf.ui.order),
- [unsortedCameras]
- );
-
- return (
-
- {sortedCameras.map(([camera, conf]) => (
-
- ))}
-
- );
-}
-
-function Camera({ name, config, availableWidth }) {
- const { payload: detectValue, send: sendDetect } = useDetectState(name);
- const { payload: recordValue, send: sendRecordings } = useRecordingsState(name);
- const { payload: snapshotValue, send: sendSnapshots } = useSnapshotsState(name);
- const { payload: audioValue, send: sendAudio } = useAudioState(name);
-
- const [cameraOptions, setCameraOptions] = useState('');
-
- const href = `/cameras/${name}`;
- const buttons = useMemo(() => {
- return [
- { name: 'Events', href: `/events?cameras=${name}` },
- { name: 'Recordings', href: `/recording/${name}` },
- ];
- }, [name]);
- const cleanName = useMemo(() => {
- return `${name.replaceAll('_', ' ')}`;
- }, [name]);
- const icons = useMemo(
- () => (availableWidth < 448 ? [
- {
- icon: SettingsIcon,
- color: 'gray',
- onClick: () => {
- setCameraOptions(config.name);
- },
- },
- ] : [
- {
- name: `Toggle detect ${detectValue === 'ON' ? 'off' : 'on'}`,
- icon: MotionIcon,
- color: detectValue === 'ON' ? 'blue' : 'gray',
- onClick: () => {
- sendDetect(detectValue === 'ON' ? 'OFF' : 'ON', true);
- },
- },
- {
- name: config.record.enabled_in_config
- ? `Toggle recordings ${recordValue === 'ON' ? 'off' : 'on'}`
- : 'Recordings must be enabled in the config to be turned on in the UI.',
- icon: ClipIcon,
- color: config.record.enabled_in_config ? (recordValue === 'ON' ? 'blue' : 'gray') : 'red',
- onClick: () => {
- if (config.record.enabled_in_config) {
- sendRecordings(recordValue === 'ON' ? 'OFF' : 'ON', true);
- }
- },
- },
- {
- name: `Toggle snapshots ${snapshotValue === 'ON' ? 'off' : 'on'}`,
- icon: SnapshotIcon,
- color: snapshotValue === 'ON' ? 'blue' : 'gray',
- onClick: () => {
- sendSnapshots(snapshotValue === 'ON' ? 'OFF' : 'ON', true);
- },
- },
- config.audio.enabled_in_config
- ? {
- name: `Toggle audio detection ${audioValue === 'ON' ? 'off' : 'on'}`,
- icon: AudioIcon,
- color: audioValue === 'ON' ? 'blue' : 'gray',
- onClick: () => {
- sendAudio(audioValue === 'ON' ? 'OFF' : 'ON', true);
- },
- }
- : null,
- ]).filter((button) => button != null),
- [config, availableWidth, setCameraOptions, audioValue, sendAudio, detectValue, sendDetect, recordValue, sendRecordings, snapshotValue, sendSnapshots]
- );
-
- return (
-
- {cameraOptions && (
-
-
- {`${name.replaceAll('_', ' ')} Settings`}
- sendDetect(detectValue === 'ON' ? 'OFF' : 'ON', true)}
- label="Detect"
- labelPosition="before"
- />
- {config.record.enabled_in_config && sendRecordings(recordValue === 'ON' ? 'OFF' : 'ON', true)}
- label="Recordings"
- labelPosition="before"
- />}
- sendSnapshots(snapshotValue === 'ON' ? 'OFF' : 'ON', true)}
- label="Snapshots"
- labelPosition="before"
- />
- {config.audio.enabled_in_config && sendAudio(audioValue === 'ON' ? 'OFF' : 'ON', true)}
- label="Audio Detection"
- labelPosition="before"
- />}
-
-
- setCameraOptions('')} type="text">
- Close
-
-
-
- )}
-
- }
- />
-
- );
-}
diff --git a/web-old/src/routes/Config.jsx b/web-old/src/routes/Config.jsx
deleted file mode 100644
index 21d2160a7..000000000
--- a/web-old/src/routes/Config.jsx
+++ /dev/null
@@ -1,118 +0,0 @@
-import { h } from 'preact';
-import useSWR from 'swr';
-import axios from 'axios';
-import { useApiHost } from '../api';
-import ActivityIndicator from '../components/ActivityIndicator';
-import Heading from '../components/Heading';
-import { useEffect, useState } from 'preact/hooks';
-import Button from '../components/Button';
-import { editor, Uri } from 'monaco-editor';
-import { setDiagnosticsOptions } from 'monaco-yaml';
-import copy from 'copy-to-clipboard';
-
-export default function Config() {
- const apiHost = useApiHost();
-
- const { data: config } = useSWR('config/raw');
- const [success, setSuccess] = useState();
- const [error, setError] = useState();
-
- const onHandleSaveConfig = async (e, save_option) => {
- if (e) {
- e.stopPropagation();
- }
-
- axios
- .post(`config/save?save_option=${save_option}`, window.editor.getValue(), {
- headers: { 'Content-Type': 'text/plain' },
- })
- .then((response) => {
- if (response.status === 200) {
- setError('');
- setSuccess(response.data.message);
- }
- })
- .catch((error) => {
- setSuccess('');
-
- if (error.response) {
- setError(error.response.data.message);
- } else {
- setError(error.message);
- }
- });
- };
-
- const handleCopyConfig = async () => {
- copy(window.editor.getValue());
- };
-
- useEffect(() => {
- if (!config) {
- return;
- }
-
- if (document.getElementById('container').children.length > 0) {
- // we don't need to recreate the editor if it already exists
- return;
- }
-
- const modelUri = Uri.parse('a://b/api/config/schema.json');
-
- let yamlModel;
- if (editor.getModels().length > 0) {
- yamlModel = editor.getModel(modelUri);
- } else {
- yamlModel = editor.createModel(config, 'yaml', modelUri);
- }
-
- setDiagnosticsOptions({
- enableSchemaRequest: true,
- hover: true,
- completion: true,
- validate: true,
- format: true,
- schemas: [
- {
- uri: `${apiHost}api/config/schema.json`,
- fileMatch: [String(modelUri)],
- },
- ],
- });
-
- window.editor = editor.create(document.getElementById('container'), {
- language: 'yaml',
- model: yamlModel,
- scrollBeyondLastLine: false,
- theme: 'vs-dark',
- });
- });
-
- if (!config) {
- return ;
- }
-
- return (
-
-
-
Config
-
- handleCopyConfig(e)}>
- Copy Config
-
- onHandleSaveConfig(e, 'restart')}>
- Save & Restart
-
- onHandleSaveConfig(e, 'saveonly')}>
- Save Only
-
-
-
-
- {success &&
{success}
}
- {error &&
{error}
}
-
-
-
- );
-}
diff --git a/web-old/src/routes/Events.jsx b/web-old/src/routes/Events.jsx
deleted file mode 100644
index 2b2b546ef..000000000
--- a/web-old/src/routes/Events.jsx
+++ /dev/null
@@ -1,942 +0,0 @@
-import { h, Fragment } from 'preact';
-import { route } from 'preact-router';
-import ActivityIndicator from '../components/ActivityIndicator';
-import Heading from '../components/Heading';
-import { Tabs, TextTab } from '../components/Tabs';
-import Link from '../components/Link';
-import { useApiHost } from '../api';
-import useSWR from 'swr';
-import useSWRInfinite from 'swr/infinite';
-import axios from 'axios';
-import { useState, useRef, useCallback, useMemo } from 'preact/hooks';
-import VideoPlayer from '../components/VideoPlayer';
-import { StarRecording } from '../icons/StarRecording';
-import { Submitted } from '../icons/Submitted';
-import { Snapshot } from '../icons/Snapshot';
-import { UploadPlus } from '../icons/UploadPlus';
-import { Clip } from '../icons/Clip';
-import { Zone } from '../icons/Zone';
-import { Camera } from '../icons/Camera';
-import { Clock } from '../icons/Clock';
-import { Delete } from '../icons/Delete';
-import { Download } from '../icons/Download';
-import Menu, { MenuItem } from '../components/Menu';
-import CalendarIcon from '../icons/Calendar';
-import Calendar from '../components/Calendar';
-import Button from '../components/Button';
-import Dialog from '../components/Dialog';
-import MultiSelect from '../components/MultiSelect';
-import { formatUnixTimestampToDateTime, getDurationFromTimestamps } from '../utils/dateUtil';
-import TimeAgo from '../components/TimeAgo';
-import Timepicker from '../components/TimePicker';
-import TimelineSummary from '../components/TimelineSummary';
-import TimelineEventOverlay from '../components/TimelineEventOverlay';
-import { Score } from '../icons/Score';
-import { About } from '../icons/About';
-import MenuIcon from '../icons/Menu';
-import { MenuOpen } from '../icons/MenuOpen';
-
-const API_LIMIT = 25;
-
-const daysAgo = (num) => {
- let date = new Date();
- date.setDate(date.getDate() - num);
- return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() / 1000;
-};
-
-const monthsAgo = (num) => {
- let date = new Date();
- date.setMonth(date.getMonth() - num);
- return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() / 1000;
-};
-
-export default function Events({ path, ...props }) {
- const apiHost = useApiHost();
- const { data: config } = useSWR('config');
- const timezone = useMemo(() => config?.ui?.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone, [config]);
- const [searchParams, setSearchParams] = useState({
- before: null,
- after: null,
- cameras: props.cameras ?? 'all',
- labels: props.labels ?? 'all',
- zones: props.zones ?? 'all',
- sub_labels: props.sub_labels ?? 'all',
- time_range: '00:00,24:00',
- timezone,
- favorites: props.favorites ?? 0,
- is_submitted: props.is_submitted ?? -1,
- event: props.event,
- });
- const [state, setState] = useState({
- showDownloadMenu: false,
- showDatePicker: false,
- showCalendar: false,
- showPlusSubmit: false,
- });
- const [plusSubmitEvent, setPlusSubmitEvent] = useState({
- id: null,
- label: null,
- validBox: null,
- });
- const [uploading, setUploading] = useState([]);
- const [viewEvent, setViewEvent] = useState(props.event);
- const [eventOverlay, setEventOverlay] = useState();
- const [eventDetailType, setEventDetailType] = useState('clip');
- const [downloadEvent, setDownloadEvent] = useState({
- id: null,
- label: null,
- box: null,
- has_clip: false,
- has_snapshot: false,
- plus_id: undefined,
- end_time: null,
- });
- const [deleteFavoriteState, setDeleteFavoriteState] = useState({
- deletingFavoriteEventId: null,
- showDeleteFavorite: false,
- });
-
- const [showInProgress, setShowInProgress] = useState((props.event || props.cameras || props.labels) == null);
-
- const eventsFetcher = useCallback(
- (path, params) => {
- if (searchParams.event) {
- path = `${path}/${searchParams.event}`;
- return axios.get(path).then((res) => [res.data]);
- }
- params = { ...params, in_progress: 0, include_thumbnails: 0, limit: API_LIMIT };
- return axios.get(path, { params }).then((res) => res.data);
- },
- [searchParams]
- );
-
- const getKey = useCallback(
- (index, prevData) => {
- if (index > 0) {
- const lastDate = prevData[prevData.length - 1].start_time;
- const pagedParams = { ...searchParams, before: lastDate };
- return ['events', pagedParams];
- }
-
- return ['events', searchParams];
- },
- [searchParams]
- );
-
- const { data: ongoingEvents, mutate: refreshOngoingEvents } = useSWR([
- 'events',
- { in_progress: 1, include_thumbnails: 0 },
- ]);
- const {
- data: eventPages,
- mutate: refreshEvents,
- size,
- setSize,
- isValidating,
- } = useSWRInfinite(getKey, eventsFetcher);
- const mutate = () => {
- refreshEvents();
- refreshOngoingEvents();
- };
-
- const { data: allLabels } = useSWR(['labels']);
- const { data: allSubLabels } = useSWR(['sub_labels', { split_joined: 1 }]);
-
- const filterValues = useMemo(
- () => ({
- cameras: Object.keys(config?.cameras || {}),
- zones: [
- ...Object.values(config?.cameras || {})
- .reduce((memo, camera) => {
- memo = memo.concat(Object.keys(camera?.zones || {}));
- return memo;
- }, [])
- .filter((value, i, self) => self.indexOf(value) === i),
- 'None',
- ],
- labels: Object.values(allLabels || {}),
- sub_labels: (allSubLabels || []).length > 0 ? [...Object.values(allSubLabels), 'None'] : [],
- }),
- [config, allLabels, allSubLabels]
- );
-
- const onSave = async (e, eventId, save) => {
- e.stopPropagation();
- let response;
- if (save) {
- response = await axios.post(`events/${eventId}/retain`);
- } else {
- response = await axios.delete(`events/${eventId}/retain`);
- }
- if (response.status === 200) {
- mutate();
- }
- };
-
- const onDelete = async (e, eventId, saved) => {
- e.stopPropagation();
-
- if (saved) {
- setDeleteFavoriteState({ deletingFavoriteEventId: eventId, showDeleteFavorite: true });
- } else {
- const response = await axios.delete(`events/${eventId}`);
- if (response.status === 200) {
- mutate();
- }
- }
- };
-
- const onToggleNamedFilter = (name, item) => {
- let items;
-
- if (searchParams[name] == 'all') {
- const currentItems = Array.from(filterValues[name]);
-
- // don't remove all if only one option
- if (currentItems.length > 1) {
- currentItems.splice(currentItems.indexOf(item), 1);
- items = currentItems.join(',');
- } else {
- items = ['all'];
- }
- } else {
- let currentItems = searchParams[name].length > 0 ? searchParams[name].split(',') : [];
-
- if (currentItems.includes(item)) {
- // don't remove the last item in the filter list
- if (currentItems.length > 1) {
- currentItems.splice(currentItems.indexOf(item), 1);
- }
-
- items = currentItems.join(',');
- } else if (currentItems.length + 1 == filterValues[name].length) {
- items = ['all'];
- } else {
- currentItems.push(item);
- items = currentItems.join(',');
- }
- }
-
- onFilter(name, items);
- };
-
- const onEventFrameSelected = (event, frame, seekSeconds) => {
- if (this.player) {
- this.player.pause();
- this.player.currentTime(seekSeconds);
- setEventOverlay(frame);
- }
- };
-
- const datePicker = useRef();
-
- const downloadButton = useRef();
-
- const onDownloadClick = (e, event) => {
- e.stopPropagation();
- setDownloadEvent((_prev) => ({
- id: event.id,
- box: event?.data?.box || event.box,
- label: event.label,
- has_clip: event.has_clip,
- has_snapshot: event.has_snapshot,
- plus_id: event.plus_id,
- end_time: event.end_time,
- }));
- downloadButton.current = e.target;
- setState({ ...state, showDownloadMenu: true });
- };
-
- const showSubmitToPlus = (event_id, label, box, e) => {
- if (e) {
- e.stopPropagation();
- }
- // if any of the box coordinates are > 1, then the box data is from an older version
- // and not valid to submit to plus with the snapshot image
- setPlusSubmitEvent({ id: event_id, label, validBox: !box.some((d) => d > 1) });
- setState({ ...state, showDownloadMenu: false, showPlusSubmit: true });
- };
-
- const handleSelectDateRange = useCallback(
- (dates) => {
- setShowInProgress(false);
- setSearchParams({ ...searchParams, before: dates.before, after: dates.after });
- setState({ ...state, showDatePicker: false });
- },
- [searchParams, setSearchParams, state, setState]
- );
-
- const handleSelectTimeRange = useCallback(
- (timeRange) => {
- setSearchParams({ ...searchParams, time_range: timeRange });
- },
- [searchParams]
- );
-
- const onFilter = useCallback(
- (name, value) => {
- setShowInProgress(false);
- const updatedParams = { ...searchParams, [name]: value };
- setSearchParams(updatedParams);
- const queryString = Object.keys(updatedParams)
- .map((key) => {
- if (updatedParams[key] && updatedParams[key] != 'all') {
- return `${key}=${updatedParams[key]}`;
- }
- return null;
- })
- .filter((val) => val)
- .join('&');
- route(`${path}?${queryString}`);
- },
- [path, searchParams, setSearchParams]
- );
-
- const onClickFilterSubmitted = useCallback(() => {
- if (++searchParams.is_submitted > 1) {
- searchParams.is_submitted = -1;
- }
- onFilter('is_submitted', searchParams.is_submitted);
- }, [searchParams, onFilter]);
-
- const isDone = (eventPages?.[eventPages.length - 1]?.length ?? 0) < API_LIMIT;
-
- // hooks for infinite scroll
- const observer = useRef();
- const lastEventRef = useCallback(
- (node) => {
- if (isValidating) return;
- if (observer.current) observer.current.disconnect();
- try {
- observer.current = new IntersectionObserver((entries) => {
- if (entries[0].isIntersecting && !isDone) {
- setSize(size + 1);
- }
- });
- if (node) observer.current.observe(node);
- } catch (e) {
- // no op
- }
- },
- [size, setSize, isValidating, isDone]
- );
-
- const onSendToPlus = async (id, false_positive, validBox) => {
- if (uploading.includes(id)) {
- return;
- }
-
- setUploading((prev) => [...prev, id]);
-
- const response = false_positive
- ? await axios.put(`events/${id}/false_positive`)
- : await axios.post(`events/${id}/plus`, validBox ? { include_annotation: 1 } : {});
-
- if (response.status === 200) {
- mutate(
- (pages) =>
- pages.map((page) =>
- page.map((event) => {
- if (event.id === id) {
- return { ...event, plus_id: response.data.plus_id };
- }
- return event;
- })
- ),
- false
- );
- }
-
- setUploading((prev) => prev.filter((i) => i !== id));
-
- if (state.showDownloadMenu && downloadEvent.id === id) {
- setState({ ...state, showDownloadMenu: false });
- }
-
- setState({ ...state, showPlusSubmit: false });
- };
-
- const handleEventDetailTabChange = (index) => {
- setEventDetailType(index == 0 ? 'clip' : 'image');
- };
-
- if (!config) {
- return ;
- }
-
- return (
-
-
Events
-
-
onToggleNamedFilter('cameras', item)}
- onShowAll={() => onFilter('cameras', ['all'])}
- onSelectSingle={(item) => onFilter('cameras', item)}
- />
- onToggleNamedFilter('labels', item)}
- onShowAll={() => onFilter('labels', ['all'])}
- onSelectSingle={(item) => onFilter('labels', item)}
- />
- onToggleNamedFilter('zones', item)}
- onShowAll={() => onFilter('zones', ['all'])}
- onSelectSingle={(item) => onFilter('zones', item)}
- />
- {filterValues.sub_labels.length > 0 && (
- onToggleNamedFilter('sub_labels', item)}
- onShowAll={() => onFilter('sub_labels', ['all'])}
- onSelectSingle={(item) => onFilter('sub_labels', item)}
- />
- )}
- {searchParams.event && (
- onFilter('event', null)} type="text">
- View All
-
- )}
-
-
- {config.plus.enabled && (
- onClickFilterSubmitted()}
- inner_fill={searchParams.is_submitted == 1 ? 'currentColor' : 'gray'}
- outer_stroke={searchParams.is_submitted >= 0 ? 'currentColor' : 'gray'}
- />
- )}
-
- onFilter('favorites', searchParams.favorites ? 0 : 1)}
- fill={searchParams.favorites == 1 ? 'currentColor' : 'none'}
- />
-
-
-
- setState({ ...state, showDatePicker: true })}
- />
-
-
- {state.showDownloadMenu && (
-
setState({ ...state, showDownloadMenu: false })} relativeTo={downloadButton}>
- {downloadEvent.has_snapshot && (
-
- )}
- {downloadEvent.has_clip && (
-
- )}
- {(event?.data?.type || 'object') == 'object' &&
- downloadEvent.end_time &&
- downloadEvent.has_snapshot &&
- !downloadEvent.plus_id && (
- showSubmitToPlus(downloadEvent.id, downloadEvent.label, downloadEvent.box)}
- />
- )}
- {downloadEvent.plus_id && (
- setState({ ...state, showDownloadMenu: false })}
- />
- )}
-
- )}
- {state.showDatePicker && (
-
setState({ ...state, setShowDatePicker: false })}
- relativeTo={datePicker}
- >
-
-
-
-
-
-
- {
- setState({ ...state, showCalendar: true, showDatePicker: false });
- }}
- />
-
- )}
-
- {state.showCalendar && (
-
- setState({ ...state, showCalendar: false })}
- relativeTo={datePicker}
- >
- setState({ ...state, showCalendar: false })}
- >
-
-
-
-
- )}
- {state.showPlusSubmit && (
-
- {config.plus.enabled ? (
- <>
-
-
Submit to Frigate+
-
-
-
- {plusSubmitEvent.validBox ? (
-
- Objects in locations you want to avoid are not false positives. Submitting them as false positives
- will confuse the model.
-
- ) : (
-
- Events prior to version 0.13 can only be submitted to Frigate+ without annotations.
-
- )}
-
- {plusSubmitEvent.validBox ? (
-
- setState({ ...state, showPlusSubmit: false })} type="text">
- {uploading.includes(plusSubmitEvent.id) ? 'Close' : 'Cancel'}
-
- onSendToPlus(plusSubmitEvent.id, true, plusSubmitEvent.validBox)}
- disabled={uploading.includes(plusSubmitEvent.id)}
- type="text"
- >
- This is not a {plusSubmitEvent.label}
-
- onSendToPlus(plusSubmitEvent.id, false, plusSubmitEvent.validBox)}
- disabled={uploading.includes(plusSubmitEvent.id)}
- type="text"
- >
- This is a {plusSubmitEvent.label}
-
-
- ) : (
-
- setState({ ...state, showPlusSubmit: false })}
- disabled={uploading.includes(plusSubmitEvent.id)}
- type="text"
- >
- {uploading.includes(plusSubmitEvent.id) ? 'Close' : 'Cancel'}
-
- onSendToPlus(plusSubmitEvent.id, false, plusSubmitEvent.validBox)}
- disabled={uploading.includes(plusSubmitEvent.id)}
- type="text"
- >
- Submit to Frigate+
-
-
- )}
- >
- ) : (
- <>
-
-
- setState({ ...state, showPlusSubmit: false })} type="text">
- Close
-
-
- >
- )}
-
- )}
- {deleteFavoriteState.showDeleteFavorite && (
-
-
-
Delete Saved Event?
-
Confirm deletion of saved event.
-
-
- setDeleteFavoriteState({ ...state, showDeleteFavorite: false })}
- type="text"
- >
- Cancel
-
- {
- setDeleteFavoriteState({ ...state, showDeleteFavorite: false });
- onDelete(e, deleteFavoriteState.deletingFavoriteEventId, false);
- }}
- type="text"
- >
- Delete
-
-
-
- )}
-
- {ongoingEvents ? (
-
-
-
- Ongoing Events
-
-
-
-
-
setShowInProgress(!showInProgress)}
- >
- {showInProgress ? : }
-
-
- {showInProgress &&
- ongoingEvents.map((event, _) => {
- return (
-
{
- this.player = null;
- }}
- onDownloadClick={onDownloadClick}
- onReady={(player) => {
- this.player = player;
- this.player.on('playing', () => {
- setEventOverlay(undefined);
- });
- }}
- onSave={onSave}
- showSubmitToPlus={showSubmitToPlus}
- />
- );
- })}
-
- ) : null}
-
- Past Events
-
- {eventPages ? (
- eventPages.map((page, i) => {
- const lastPage = eventPages.length === i + 1;
- return page.map((event, j) => {
- const lastEvent = lastPage && page.length === j + 1;
- return (
-
{
- this.player = null;
- }}
- onDownloadClick={onDownloadClick}
- onReady={(player) => {
- this.player = player;
- this.player.on('playing', () => {
- setEventOverlay(undefined);
- });
- }}
- onSave={onSave}
- showSubmitToPlus={showSubmitToPlus}
- />
- );
- });
- })
- ) : (
-
- )}
-
-
-
- );
-}
-
-function Event({
- className = '',
- config,
- event,
- eventDetailType,
- eventOverlay,
- viewEvent,
- setViewEvent,
- lastEvent,
- lastEventRef,
- uploading,
- handleEventDetailTabChange,
- onEventFrameSelected,
- onDelete,
- onDispose,
- onDownloadClick,
- onReady,
- onSave,
- showSubmitToPlus,
-}) {
- const apiHost = useApiHost();
-
- return (
-
-
(viewEvent === event.id ? setViewEvent(null) : setViewEvent(event.id))}
- >
-
-
onSave(e, event.id, !event.retain_indefinitely)}
- fill={event.retain_indefinitely ? 'currentColor' : 'none'}
- />
- {event.end_time ? null : (
-
- In progress
-
- )}
-
-
-
-
- {event.label.replaceAll('_', ' ')}
- {event.sub_label ? `: ${event.sub_label.replaceAll('_', ' ')}` : null}
-
-
-
-
- {formatUnixTimestampToDateTime(event.start_time, { ...config.ui })}
-
- -
-
-
-
- ( {getDurationFromTimestamps(event.start_time, event.end_time)} )
-
-
-
-
- {event.camera.replaceAll('_', ' ')}
-
- {event.zones.length ? (
-
-
- {event.zones.join(', ').replaceAll('_', ' ')}
-
- ) : null}
-
-
- {(event?.data?.top_score || event.top_score || 0) == 0
- ? null
- : `${event.label}: ${((event?.data?.top_score || event.top_score) * 100).toFixed(0)}%`}
- {(event?.data?.sub_label_score || 0) == 0
- ? null
- : `, ${event.sub_label}: ${(event?.data?.sub_label_score * 100).toFixed(0)}%`}
-
-
-
- {event.end_time && event.has_snapshot && (event?.data?.type || 'object') == 'object' && (
-
- {event.plus_id ? (
-
-
- Edit in Frigate+
-
-
- ) : (
- showSubmitToPlus(event.id, event.label, event?.data?.box || event.box, e)}
- >
- {uploading.includes(event.id) ? 'Uploading...' : 'Send to Frigate+'}
-
- )}
-
- )}
-
-
- onDelete(e, event.id, event.retain_indefinitely)}
- />
-
- onDownloadClick(e, event)}
- />
-
-
-
- {viewEvent !== event.id ? null : (
-
-
-
-
-
-
-
-
-
-
- {eventDetailType == 'clip' && event.has_clip ? (
-
-
onEventFrameSelected(event, frame, seekSeconds)}
- />
-
-
- {eventOverlay ? (
-
- ) : null}
-
-
-
- ) : null}
-
- {eventDetailType == 'image' || !event.has_clip ? (
-
-
-
- ) : null}
-
-
-
- )}
-
- );
-}
diff --git a/web-old/src/routes/Export.jsx b/web-old/src/routes/Export.jsx
deleted file mode 100644
index 84a6cff57..000000000
--- a/web-old/src/routes/Export.jsx
+++ /dev/null
@@ -1,263 +0,0 @@
-import Heading from '../components/Heading';
-import { useState } from 'preact/hooks';
-import useSWR, { mutate } from 'swr';
-import Button from '../components/Button';
-import axios from 'axios';
-import { baseUrl } from '../api/baseUrl';
-import { Fragment } from 'preact';
-import ActivityIndicator from '../components/ActivityIndicator';
-import { Play } from '../icons/Play';
-import { Delete } from '../icons/Delete';
-import LargeDialog from '../components/DialogLarge';
-import VideoPlayer from '../components/VideoPlayer';
-import Dialog from '../components/Dialog';
-
-export default function Export() {
- const { data: config } = useSWR('config');
- const { data: exports } = useSWR('exports/', (url) => axios({ baseURL: baseUrl, url }).then((res) => res.data));
-
- // Export States
- const [camera, setCamera] = useState('select');
- const [playback, setPlayback] = useState('select');
- const [message, setMessage] = useState({ text: '', error: false });
-
- const currentDate = new Date();
- currentDate.setHours(0, 0, 0, 0);
- const offsetMs = currentDate.getTimezoneOffset() * 60 * 1000;
- const localDate = new Date(currentDate.getTime() - offsetMs);
- const localISODate = localDate.toISOString().split('T')[0];
-
- const [startDate, setStartDate] = useState(localISODate);
- const [startTime, setStartTime] = useState('00:00:00');
- const [endDate, setEndDate] = useState(localISODate);
- const [endTime, setEndTime] = useState('23:59:59');
-
- // Export States
-
- const [selectedClip, setSelectedClip] = useState();
- const [deleteClip, setDeleteClip] = useState();
-
- const onHandleExport = () => {
- if (camera == 'select') {
- setMessage({ text: 'A camera needs to be selected.', error: true });
- return;
- }
-
- if (playback == 'select') {
- setMessage({ text: 'A playback factor needs to be selected.', error: true });
- return;
- }
-
- if (!startDate || !startTime || !endDate || !endTime) {
- setMessage({ text: 'A start and end time needs to be selected', error: true });
- return;
- }
-
- const start = new Date(`${startDate}T${startTime}`).getTime() / 1000;
- const end = new Date(`${endDate}T${endTime}`).getTime() / 1000;
-
- if (end <= start) {
- setMessage({ text: 'The end time must be after the start time.', error: true });
- return;
- }
-
- axios
- .post(`export/${camera}/start/${start}/end/${end}`, { playback })
- .then((response) => {
- if (response.status == 200) {
- setMessage({ text: 'Successfully started export. View the file in the /exports folder.', error: false });
- }
- })
- .catch((error) => {
- if (error.response?.data?.message) {
- setMessage({ text: `Failed to start export: ${error.response.data.message}`, error: true });
- } else {
- setMessage({ text: `Failed to start export: ${error.message}`, error: true });
- }
- });
- };
-
- const onHandleDelete = (clip) => {
- axios.delete(`export/${clip}`).then((response) => {
- if (response.status == 200) {
- setDeleteClip();
- mutate();
- }
- });
- };
-
- return (
-
-
Export
-
- {message.text && (
-
{message.text}
- )}
-
- {selectedClip && (
-
-
- Playback
- {
- this.player = player;
- }}
- onDispose={() => {
- this.player = null;
- }}
- />
-
-
- setSelectedClip('')} type="text">
- Close
-
-
-
- )}
-
- {deleteClip && (
-
-
-
Delete Export?
-
Confirm deletion of {deleteClip}.
-
-
- setDeleteClip('')} type="text">
- Close
-
- onHandleDelete(deleteClip)} type="text">
- Delete
-
-
-
- )}
-
-
-
-
- {exports && (
-
- Exports
- setSelectedClip(clip)}
- onDeleteClip={(clip) => setDeleteClip(clip)}
- />
-
- )}
-
-
- );
-}
-
-function Exports({ exports, onSetClip, onDeleteClip }) {
- return (
-
- {exports.map((item) => (
-
- {item.name.startsWith('in_progress') ? (
-
-
-
{item.name.substring(12, item.name.length - 4)}
-
- ) : (
-
- )}
-
- ))}
-
- );
-}
diff --git a/web-old/src/routes/Logs.jsx b/web-old/src/routes/Logs.jsx
deleted file mode 100644
index def5469df..000000000
--- a/web-old/src/routes/Logs.jsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import { h } from 'preact';
-import Heading from '../components/Heading';
-import { useCallback, useEffect, useState } from 'preact/hooks';
-import ButtonsTabbed from '../components/ButtonsTabbed';
-import useSWR from 'swr';
-import Button from '../components/Button';
-import copy from 'copy-to-clipboard';
-
-export default function Logs() {
- const [logService, setLogService] = useState('frigate');
- const [logs, setLogs] = useState('frigate');
-
- const { data: frigateLogs } = useSWR('logs/frigate');
- const { data: go2rtcLogs } = useSWR('logs/go2rtc');
- const { data: nginxLogs } = useSWR('logs/nginx');
-
- const handleCopyLogs = useCallback(() => {
- copy(logs);
- }, [logs]);
-
- useEffect(() => {
- switch (logService) {
- case 'frigate':
- setLogs(frigateLogs);
- break;
- case 'go2rtc':
- setLogs(go2rtcLogs);
- break;
- case 'nginx':
- setLogs(nginxLogs);
- break;
- }
- }, [frigateLogs, go2rtcLogs, nginxLogs, logService, setLogs]);
-
- return (
-
-
Logs
-
-
-
-
- Copy to Clipboard
-
-
-
- {logs}
-
-
- );
-}
diff --git a/web-old/src/routes/Recording.jsx b/web-old/src/routes/Recording.jsx
deleted file mode 100644
index 405549e8b..000000000
--- a/web-old/src/routes/Recording.jsx
+++ /dev/null
@@ -1,165 +0,0 @@
-import { h } from 'preact';
-import { parseISO, endOfHour, startOfHour, getUnixTime } from 'date-fns';
-import { useEffect, useMemo } from 'preact/hooks';
-import ActivityIndicator from '../components/ActivityIndicator';
-import Heading from '../components/Heading';
-import RecordingPlaylist from '../components/RecordingPlaylist';
-import VideoPlayer from '../components/VideoPlayer';
-import { useApiHost } from '../api';
-import useSWR from 'swr';
-
-export default function Recording({ camera, date, hour = '00', minute = '00', second = '00' }) {
- const { data: config } = useSWR('config');
- const currentDate = useMemo(
- () => (date ? parseISO(`${date}T${hour || '00'}:${minute || '00'}:${second || '00'}`) : new Date()),
- [date, hour, minute, second]
- );
- const timezone = useMemo(() => config.ui?.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone, [config]);
-
- const apiHost = useApiHost();
- const { data: recordingsSummary } = useSWR([`${camera}/recordings/summary`, { timezone }], {
- revalidateOnFocus: false,
- });
-
- const recordingParams = {
- before: getUnixTime(endOfHour(currentDate)),
- after: getUnixTime(startOfHour(currentDate)),
- };
- const { data: recordings } = useSWR([`${camera}/recordings`, recordingParams], { revalidateOnFocus: false });
-
- // calculates the seek seconds by adding up all the seconds in the segments prior to the playback time
- const seekSeconds = useMemo(() => {
- if (!recordings) {
- return undefined;
- }
- const currentUnix = getUnixTime(currentDate);
-
- const hourStart = getUnixTime(startOfHour(currentDate));
- let seekSeconds = 0;
- recordings.every((segment) => {
- // if the next segment is past the desired time, stop calculating
- if (segment.start_time > currentUnix) {
- return false;
- }
- // if the segment starts before the hour, skip the seconds before the hour
- const start = segment.start_time < hourStart ? hourStart : segment.start_time;
- // if the segment ends after the selected time, use the selected time for end
- const end = segment.end_time > currentUnix ? currentUnix : segment.end_time;
- seekSeconds += end - start;
- return true;
- });
- return seekSeconds;
- }, [recordings, currentDate]);
-
- const playlist = useMemo(() => {
- if (!recordingsSummary) {
- return [];
- }
-
- const selectedDayRecordingData = recordingsSummary.find((s) => !date || s.day === date);
-
- if (!selectedDayRecordingData) {
- return [];
- }
-
- const [year, month, day] = selectedDayRecordingData.day.split('-');
- return selectedDayRecordingData.hours
- .map((h) => {
- return {
- name: h.hour,
- description: `${camera} recording @ ${h.hour}:00.`,
- sources: [
- {
- src: `${apiHost}vod/${year}-${month}/${day}/${h.hour}/${camera}/${timezone.replaceAll(
- '/',
- ','
- )}/master.m3u8`,
- type: 'application/vnd.apple.mpegurl',
- },
- ],
- };
- })
- .reverse();
- }, [apiHost, date, recordingsSummary, camera, timezone]);
-
- const playlistIndex = useMemo(() => {
- const index = playlist.findIndex((item) => item.name === hour);
- if (index === -1) {
- return 0;
- }
- return index;
- }, [playlist, hour]);
-
- useEffect(() => {
- if (this.player) {
- this.player.playlist(playlist);
- }
- }, [playlist]);
-
- useEffect(() => {
- if (this.player) {
- this.player.playlist.currentItem(playlistIndex);
- }
- }, [playlistIndex]);
-
- useEffect(() => {
- if (seekSeconds === undefined) {
- return;
- }
- if (this.player) {
- // if the playlist has moved on to the next item, then reset
- if (this.player.playlist.currentItem() !== playlistIndex) {
- this.player.playlist.currentItem(playlistIndex);
- }
- this.player.currentTime(seekSeconds);
- // try and play since the user is likely to have interacted with the dom
- this.player.play();
- }
- }, [seekSeconds, playlistIndex]);
-
- if (!recordingsSummary || !config) {
- return ;
- }
-
- if (recordingsSummary.length === 0) {
- return (
-
-
{camera} Recordings
-
-
No Recordings Found
-
Make sure you have enabled the record role in your configuration for the {camera} camera.
-
-
- );
- }
-
- return (
-
-
{camera.replaceAll('_', ' ')} Recordings
-
Dates and times are based on the timezone {timezone}
-
-
{
- player.on('ratechange', () => player.defaultPlaybackRate(player.playbackRate()));
- if (player.playlist) {
- player.playlist(playlist);
- player.playlist.autoadvance(0);
- player.playlist.currentItem(playlistIndex);
- if (seekSeconds !== undefined) {
- player.currentTime(seekSeconds);
- }
- this.player = player;
- }
- }}
- onDispose={() => {
- this.player = null;
- }}
- >
-
-
-
- );
-}
diff --git a/web-old/src/routes/Storage.jsx b/web-old/src/routes/Storage.jsx
deleted file mode 100644
index 4e187ef86..000000000
--- a/web-old/src/routes/Storage.jsx
+++ /dev/null
@@ -1,175 +0,0 @@
-import { h, Fragment } from 'preact';
-import ActivityIndicator from '../components/ActivityIndicator';
-import Heading from '../components/Heading';
-import { useWs } from '../api/ws';
-import useSWR from 'swr';
-import { Table, Tbody, Thead, Tr, Th, Td } from '../components/Table';
-import Link from '../components/Link';
-import Button from '../components/Button';
-import { About } from '../icons/About';
-
-const emptyObject = Object.freeze({});
-
-export default function Storage() {
- const { data: storage } = useSWR('recordings/storage');
-
- const {
- value: { payload: stats },
- } = useWs('stats');
- const { data: initialStats } = useSWR('stats');
-
- const { service } = stats || initialStats || emptyObject;
-
- if (!service || !storage) {
- return ;
- }
-
- const getUnitSize = (MB) => {
- if (isNaN(MB) || MB < 0) return 'Invalid number';
- if (MB < 1024) return `${MB} MiB`;
- if (MB < 1048576) return `${(MB / 1024).toFixed(2)} GiB`;
-
- return `${(MB / 1048576).toFixed(2)} TiB`;
- };
-
- let storage_usage;
- if (
- service &&
- service['storage']['/media/frigate/recordings']['total'] != service['storage']['/media/frigate/clips']['total']
- ) {
- storage_usage = (
-
-
- Recordings
- {getUnitSize(service['storage']['/media/frigate/recordings']['used'])}
- {getUnitSize(service['storage']['/media/frigate/recordings']['total'])}
-
-
- Snapshots
- {getUnitSize(service['storage']['/media/frigate/clips']['used'])}
- {getUnitSize(service['storage']['/media/frigate/clips']['total'])}
-
-
- );
- } else {
- storage_usage = (
-
-
- Recordings & Snapshots
- {getUnitSize(service['storage']['/media/frigate/recordings']['used'])}
- {getUnitSize(service['storage']['/media/frigate/recordings']['total'])}
-
-
- );
- }
-
- return (
-
-
Storage
-
-
- Overview
-
-
-
-
-
-
-
- Location
- Used
- Total
-
-
- {storage_usage}
-
-
-
-
-
-
-
-
-
- Location
- Used
- Total
-
-
-
-
- /dev/shm
- {getUnitSize(service['storage']['/dev/shm']['used'])}
- {getUnitSize(service['storage']['/dev/shm']['total'])}
-
-
- /tmp/cache
- {getUnitSize(service['storage']['/tmp/cache']['used'])}
- {getUnitSize(service['storage']['/tmp/cache']['total'])}
-
-
-
-
-
-
-
-
-
- {Object.entries(storage).map(([name, camera]) => (
-
-
- {name.replaceAll('_', ' ')}
-
-
-
-
-
- Usage
- Stream Bandwidth
-
-
-
-
- {Math.round(camera['usage_percent'] ?? 0)}%
- {camera['bandwidth'] ? `${getUnitSize(camera['bandwidth'])}/hr` : 'Calculating...'}
-
-
-
-
-
- ))}
-
-
-
- );
-}
diff --git a/web-old/src/routes/StyleGuide.jsx b/web-old/src/routes/StyleGuide.jsx
deleted file mode 100644
index d1c0e2310..000000000
--- a/web-old/src/routes/StyleGuide.jsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import { h } from 'preact';
-import ArrowDropdown from '../icons/ArrowDropdown';
-import ArrowDropup from '../icons/ArrowDropup';
-import Button from '../components/Button';
-import Dialog from '../components/Dialog';
-import Heading from '../components/Heading';
-import Select from '../components/Select';
-import Switch from '../components/Switch';
-import TextField from '../components/TextField';
-import { useCallback, useState } from 'preact/hooks';
-
-export default function StyleGuide() {
- const [switches, setSwitches] = useState({ 0: false, 1: true, 2: false, 3: false });
- const [showDialog, setShowDialog] = useState(false);
-
- const handleSwitch = useCallback(
- (id, checked) => {
- setSwitches({ ...switches, [id]: checked });
- },
- [switches]
- );
-
- const handleDismissDialog = () => {
- setShowDialog(false);
- };
-
- return (
-
-
Button
-
- Default
- Danger
- Save
- Gray
- Disabled
-
-
- Default
-
- Danger
-
-
- Save
-
-
- Gray
-
-
- Disabled
-
-
-
- Default
-
- Danger
-
-
- Save
-
-
- Gray
-
-
- Disabled
-
-
-
-
Dialog
-
{
- setShowDialog(true);
- }}
- >
- Show Dialog
-
- {showDialog ? (
-
- ) : null}
-
-
Switch
-
-
-
-
-
-
-
-
-
-
-
Select
-
-
-
-
-
TextField
-
-
-
-
-
-
-
-
- );
-}
diff --git a/web-old/src/routes/System.jsx b/web-old/src/routes/System.jsx
deleted file mode 100644
index 77b37686f..000000000
--- a/web-old/src/routes/System.jsx
+++ /dev/null
@@ -1,487 +0,0 @@
-import { h, Fragment } from 'preact';
-import ActivityIndicator from '../components/ActivityIndicator';
-import Button from '../components/Button';
-import Heading from '../components/Heading';
-import Link from '../components/Link';
-import { useWs } from '../api/ws';
-import useSWR from 'swr';
-import axios from 'axios';
-import { Table, Tbody, Thead, Tr, Th, Td } from '../components/Table';
-import { useState } from 'preact/hooks';
-import Dialog from '../components/Dialog';
-import TimeAgo from '../components/TimeAgo';
-import copy from 'copy-to-clipboard';
-import { About } from '../icons/About';
-import { WebUI } from '../icons/WebUI';
-
-const emptyObject = Object.freeze({});
-
-export default function System() {
- const [state, setState] = useState({ showFfprobe: false, ffprobe: '' });
- const { data: config } = useSWR('config');
-
- const {
- value: { payload: stats },
- } = useWs('stats');
- const { data: initialStats } = useSWR('stats');
-
- const {
- cpu_usages,
- gpu_usages,
- bandwidth_usages,
- detectors,
- service = {},
- detection_fps: _,
- processes,
- cameras,
- } = stats || initialStats || emptyObject;
-
- const detectorNames = Object.keys(detectors || emptyObject);
- const gpuNames = Object.keys(gpu_usages || emptyObject);
- const cameraNames = Object.keys(cameras || emptyObject);
- const processesNames = Object.keys(processes || emptyObject);
-
- const { data: go2rtc } = useSWR('go2rtc/api');
-
- const onHandleFfprobe = async (camera, e) => {
- if (e) {
- e.stopPropagation();
- }
-
- setState({ ...state, showFfprobe: true });
- const response = await axios.get('ffprobe', {
- params: {
- paths: `camera:${camera}`,
- },
- });
-
- if (response.status === 200) {
- setState({ ...state, showFfprobe: true, ffprobe: response.data });
- } else {
- setState({ ...state, showFfprobe: true, ffprobe: 'There was an error getting the ffprobe output.' });
- }
- };
-
- const onCopyFfprobe = async () => {
- copy(JSON.stringify(state.ffprobe).replace(/[\\\s]+/gi, ''));
- setState({ ...state, ffprobe: '', showFfprobe: false });
- };
-
- const onHandleVainfo = async (e) => {
- if (e) {
- e.stopPropagation();
- }
-
- const response = await axios.get('vainfo');
-
- if (response.status === 200) {
- setState({
- ...state,
- showVainfo: true,
- vainfo: response.data,
- });
- } else {
- setState({ ...state, showVainfo: true, vainfo: 'There was an error getting the vainfo output.' });
- }
- };
-
- const onCopyVainfo = async () => {
- copy(JSON.stringify(state.vainfo).replace(/[\\\s]+/gi, ''));
- setState({ ...state, vainfo: '', showVainfo: false });
- };
-
- return (
-
-
-
- System {service.version}
-
- {config && (
-
- go2rtc {go2rtc && `${go2rtc.version} `}
-
- streams info
-
-
- )}
-
-
- {service.last_updated && (
-
-
- Last refreshed:
-
-
- )}
-
- {state.showFfprobe && (
-
-
-
Ffprobe Output
- {state.ffprobe != '' ? (
-
- {state.ffprobe.map((stream, idx) => (
-
-
Stream {idx}:
-
Return Code: {stream.return_code}
-
- {stream.return_code == 0 ? (
-
- {stream.stdout.streams.map((codec, idx) => (
-
- {codec.width ? (
-
-
Video:
-
-
Codec: {codec.codec_long_name}
-
- Resolution: {codec.width}x{codec.height}
-
-
FPS: {codec.avg_frame_rate == '0/0' ? 'Unknown' : codec.avg_frame_rate}
-
-
- ) : (
-
-
Audio:
-
-
Codec: {codec.codec_long_name}
-
-
- )}
-
- ))}
-
- ) : (
-
-
Error: {stream.stderr}
-
- )}
-
- ))}
-
- ) : (
-
- )}
-
-
- onCopyFfprobe()} type="text">
- Copy
-
- setState({ ...state, ffprobe: '', showFfprobe: false })}
- type="text"
- >
- Close
-
-
-
- )}
-
- {state.showVainfo && (
-
-
-
Vainfo Output
- {state.vainfo != '' ? (
-
-
Return Code: {state.vainfo.return_code}
-
-
Process {state.vainfo.return_code == 0 ? 'Output' : 'Error'}:
-
-
{state.vainfo.return_code == 0 ? state.vainfo.stdout : state.vainfo.stderr}
-
- ) : (
-
- )}
-
-
- onCopyVainfo()} type="text">
- Copy
-
- setState({ ...state, vainfo: '', showVainfo: false })} type="text">
- Close
-
-
-
- )}
-
- {!detectors ? (
-
- ) : (
-
-
-
- {detectorNames.map((detector) => (
-
-
{detector}
-
-
-
-
- P-ID
- Inference Speed
- CPU %
- Memory %
- {config.telemetry.network_bandwidth && Network Bandwidth }
-
-
-
-
- {detectors[detector]['pid']}
- {detectors[detector]['inference_speed']} ms
- {cpu_usages[detectors[detector]['pid']]?.['cpu'] || '- '}%
- {cpu_usages[detectors[detector]['pid']]?.['mem'] || '- '}%
- {config.telemetry.network_bandwidth && (
- {bandwidth_usages[detectors[detector]['pid']]?.['bandwidth'] || '- '}KB/s
- )}
-
-
-
-
-
- ))}
-
-
-
-
-
onHandleVainfo(e)}>vainfo
-
-
- {!gpu_usages ? (
-
-
- Hardware acceleration has not been setup, see the docs to setup hardware acceleration.
-
-
- ) : (
-
- {gpuNames.map((gpu) => (
-
-
{gpu}
-
- {gpu_usages[gpu]['gpu'] == -1 ? (
-
- There was an error getting usage stats. This does not mean hardware acceleration is not working.
- Either your GPU does not support this or Frigate does not have proper access to get statistics.
- This is expected for the Home Assistant addon.
-
- ) : (
-
-
-
- GPU %
- Memory %
- {'dec' in gpu_usages[gpu] && Decoder % }
- {'enc' in gpu_usages[gpu] && Encoder % }
-
-
-
-
- {gpu_usages[gpu]['gpu']}
- {gpu_usages[gpu]['mem']}
- {'dec' in gpu_usages[gpu] && {gpu_usages[gpu]['dec']} }
- {'enc' in gpu_usages[gpu] && {gpu_usages[gpu]['enc']} }
-
-
-
- )}
-
-
- ))}
-
- )}
-
-
- {!cameras ? (
-
- ) : (
-
- {cameraNames.map(
- (camera) =>
- config.cameras[camera]['enabled'] && (
-
-
-
{camera.replaceAll('_', ' ')}
-
- {config.cameras[camera]['webui_url'] && (
-
- Web UI
-
-
- )}
- onHandleFfprobe(camera, e)}>
- ffprobe
-
-
-
-
-
-
-
- Process
- P-ID
- FPS
- CPU %
- Memory %
- {config.telemetry.network_bandwidth && Network Bandwidth }
-
-
-
-
-
- ffmpeg
- copy(cpu_usages[cameras[camera]['ffmpeg_pid']]?.['cmdline'])}
- >
-
-
-
- {cameras[camera]['ffmpeg_pid'] || '- '}
- {cameras[camera]['camera_fps'] || '- '}
- {cpu_usages[cameras[camera]['ffmpeg_pid']]?.['cpu'] || '- '}%
- {cpu_usages[cameras[camera]['ffmpeg_pid']]?.['mem'] || '- '}%
- {config.telemetry.network_bandwidth && (
- {bandwidth_usages[cameras[camera]['ffmpeg_pid']]?.['bandwidth'] || '- '}KB/s
- )}
-
-
- Capture
- {cameras[camera]['capture_pid'] || '- '}
- {cameras[camera]['process_fps'] || '- '}
- {cpu_usages[cameras[camera]['capture_pid']]?.['cpu'] || '- '}%
- {cpu_usages[cameras[camera]['capture_pid']]?.['mem'] || '- '}%
- {config.telemetry.network_bandwidth && - }
-
-
- Detect
- {cameras[camera]['pid'] || '- '}
-
- {(() => {
- if (cameras[camera]['pid'] && cameras[camera]['detection_enabled'] == 1)
- return (
-
- {cameras[camera]['detection_fps']} ({cameras[camera]['skipped_fps']} skipped)
-
- );
- else if (cameras[camera]['pid'] && cameras[camera]['detection_enabled'] == 0)
- return disabled ;
-
- return - ;
- })()}
-
- {cpu_usages[cameras[camera]['pid']]?.['cpu'] || '- '}%
- {cpu_usages[cameras[camera]['pid']]?.['mem'] || '- '}%
- {config.telemetry.network_bandwidth && - }
-
-
-
-
-
- )
- )}
-
- )}
-
-
-
- Other Processes
-
-
-
-
-
-
- {processesNames.map((process) => (
-
-
-
-
-
-
- P-ID
- CPU %
- Avg CPU %
- Memory %
- {config.telemetry.network_bandwidth && Network Bandwidth }
-
-
-
-
- {processes[process]['pid'] || '- '}
- {cpu_usages[processes[process]['pid']]?.['cpu'] || '- '}%
- {cpu_usages[processes[process]['pid']]?.['cpu_average'] || '- '}%
- {cpu_usages[processes[process]['pid']]?.['mem'] || '- '}%
- {config.telemetry.network_bandwidth && (
- {bandwidth_usages[processes[process]['pid']]?.['bandwidth'] || '- '}KB/s
- )}
-
-
-
-
-
- ))}
-
-
- System stats update automatically every {config.mqtt.stats_interval} seconds.
-
- )}
-
- );
-}
diff --git a/web-old/src/routes/__tests__/Camera.test.jsx b/web-old/src/routes/__tests__/Camera.test.jsx
deleted file mode 100644
index ef679681c..000000000
--- a/web-old/src/routes/__tests__/Camera.test.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { h } from 'preact';
-import * as AutoUpdatingCameraImage from '../../components/AutoUpdatingCameraImage';
-import * as WS from '../../api/ws';
-import Camera from '../Camera';
-import { set as setData } from 'idb-keyval';
-import * as JSMpegPlayer from '../../components/JSMpegPlayer';
-import { fireEvent, render, screen, waitForElementToBeRemoved } from 'testing-library';
-
-describe('Camera Route', () => {
- beforeEach(() => {
- vi.spyOn(AutoUpdatingCameraImage, 'default').mockImplementation(({ searchParams }) => {
- return {searchParams.toString()}
;
- });
- vi.spyOn(JSMpegPlayer, 'default').mockImplementation(() => {
- return
;
- });
- vi.spyOn(WS, 'WsProvider').mockImplementation(({ children }) => children);
- });
-
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('reads camera feed options from persistence', async () => {
- setData('front-source', 'mse')
- setData('front-feed', {
- bbox: true,
- timestamp: false,
- zones: true,
- mask: false,
- motion: true,
- regions: false,
- });
-
- render( );
- await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading…'), { timeout: 100 });
-
- fireEvent.click(screen.queryByText('Debug'));
- fireEvent.click(screen.queryByText('Show Options'));
- expect(screen.queryByTestId('mock-image')).toHaveTextContent(
- 'bbox=1×tamp=0&zones=1&mask=0&motion=1®ions=0'
- );
- });
-
-
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('updates camera feed options to persistence', async () => {
- setData('front-feed', {});
-
- render( );
-
- await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading…'), { timeout: 100 });
-
- fireEvent.click(screen.queryByText('Debug'));
- fireEvent.click(screen.queryByText('Show Options'));
- fireEvent.change(screen.queryByTestId('bbox-input'), { target: { checked: true } });
- fireEvent.change(screen.queryByTestId('timestamp-input'), { target: { checked: true } });
- fireEvent.click(screen.queryByText('Hide Options'));
-
- expect(screen.queryByTestId('mock-image')).toHaveTextContent('bbox=1×tamp=1');
- });
-});
diff --git a/web-old/src/routes/__tests__/Cameras.test.jsx b/web-old/src/routes/__tests__/Cameras.test.jsx
deleted file mode 100644
index 22964a5c3..000000000
--- a/web-old/src/routes/__tests__/Cameras.test.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/* eslint-disable jest/no-disabled-tests */
-import { h } from 'preact';
-import * as CameraImage from '../../components/CameraImage';
-import * as Hooks from '../../hooks';
-import * as WS from '../../api/ws';
-import Cameras from '../Cameras';
-import { fireEvent, render, screen, waitForElementToBeRemoved } from 'testing-library';
-
-describe('Cameras Route', () => {
- beforeEach(() => {
- vi.spyOn(CameraImage, 'default').mockImplementation(() =>
);
- vi.spyOn(WS, 'useWs').mockImplementation(() => ({ value: { payload: 'OFF' }, send: vi.fn() }));
- vi.spyOn(Hooks, 'useResizeObserver').mockImplementation(() => [{ width: 1000 }]);
- });
-
- test('shows an ActivityIndicator if not yet loaded', async () => {
- render( );
- expect(screen.queryByLabelText('Loading…')).toBeInTheDocument();
- });
-
- test.skip('shows cameras', async () => {
- render( );
-
- await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading…'));
-
- expect(screen.queryByText('front')).toBeInTheDocument();
- expect(screen.queryByText('front').closest('a')).toHaveAttribute('href', '/cameras/front');
-
- expect(screen.queryByText('side')).toBeInTheDocument();
- expect(screen.queryByText('side').closest('a')).toHaveAttribute('href', '/cameras/side');
- });
-
- test.skip('shows recordings link', async () => {
- render( );
-
- await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading…'));
-
- expect(screen.queryAllByText('Recordings')).toHaveLength(2);
- });
-
- test.skip('buttons toggle detect, clips, and snapshots', async () => {
- const sendDetect = vi.fn();
- const sendRecordings = vi.fn();
- const sendSnapshots = vi.fn();
- vi.spyOn(WS, 'useDetectState').mockImplementation(() => {
- return { payload: 'ON', send: sendDetect };
- });
- vi.spyOn(WS, 'useRecordingsState').mockImplementation(() => {
- return { payload: 'OFF', send: sendRecordings };
- });
- vi.spyOn(WS, 'useSnapshotsState').mockImplementation(() => {
- return { payload: 'ON', send: sendSnapshots };
- });
-
- render( );
-
- await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading…'));
-
- fireEvent.click(screen.getAllByLabelText('Toggle detect off')[0]);
- expect(sendDetect).toHaveBeenCalledWith('OFF', true);
- expect(sendDetect).toHaveBeenCalledTimes(1);
-
- fireEvent.click(screen.getAllByLabelText('Toggle snapshots off')[0]);
- expect(sendSnapshots).toHaveBeenCalledWith('OFF', true);
-
- fireEvent.click(screen.getAllByLabelText('Toggle recordings on')[0]);
- expect(sendRecordings).toHaveBeenCalledWith('ON', true);
-
- expect(sendDetect).toHaveBeenCalledTimes(1);
- expect(sendSnapshots).toHaveBeenCalledTimes(1);
- expect(sendRecordings).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/web-old/src/routes/__tests__/Events.test.jsx b/web-old/src/routes/__tests__/Events.test.jsx
deleted file mode 100644
index 11f1d06f0..000000000
--- a/web-old/src/routes/__tests__/Events.test.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { h } from 'preact';
-import Events from '../Events';
-import { render, screen, waitForElementToBeRemoved } from 'testing-library';
-
-describe('Events Route', () => {
- beforeEach(() => {});
-
- test('shows an ActivityIndicator if not yet loaded', async () => {
- render( );
- expect(screen.queryByLabelText('Loading…')).toBeInTheDocument();
- });
-
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('does not show ActivityIndicator after loaded', async () => {
- render( );
-
- await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading…'));
-
- expect(screen.queryByLabelText('Loading…')).not.toBeInTheDocument();
- });
-});
diff --git a/web-old/src/routes/__tests__/Recording.test.jsx b/web-old/src/routes/__tests__/Recording.test.jsx
deleted file mode 100644
index fd682e0e7..000000000
--- a/web-old/src/routes/__tests__/Recording.test.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { h } from 'preact';
-import * as CameraImage from '../../components/CameraImage';
-import * as WS from '../../api/ws';
-import * as Hooks from '../../hooks';
-import Cameras from '../Cameras';
-import { render, screen, waitForElementToBeRemoved } from 'testing-library';
-
-describe('Recording Route', () => {
- beforeEach(() => {
- vi.spyOn(CameraImage, 'default').mockImplementation(() =>
);
- vi.spyOn(WS, 'useWs').mockImplementation(() => ({ value: { payload: 'OFF' }, send: jest.fn() }));
- vi.spyOn(Hooks, 'useResizeObserver').mockImplementation(() => [{ width: 1000 }]);
- });
-
- test('shows an ActivityIndicator if not yet loaded', async () => {
- render( );
- expect(screen.queryByLabelText('Loading…')).toBeInTheDocument();
- });
-
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('shows no recordings warning', async () => {
- render( );
-
- await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading…'));
-
- expect(screen.queryAllByText('No Recordings Found')).toHaveLength(0);
- });
-});
diff --git a/web-old/src/routes/__tests__/System.test.jsx b/web-old/src/routes/__tests__/System.test.jsx
deleted file mode 100644
index bf353d01d..000000000
--- a/web-old/src/routes/__tests__/System.test.jsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { h } from 'preact';
-import System from '../System';
-import { render, screen, waitForElementToBeRemoved } from 'testing-library';
-
-describe('System Route', () => {
- beforeEach(() => {});
-
- test('shows an ActivityIndicator if stats are null', async () => {
- render( );
- expect(screen.queryByLabelText('Loading…')).toBeInTheDocument();
- });
-
- // eslint-disable-next-line jest/no-disabled-tests
- test.skip('shows stats and config', async () => {
- render( );
-
- await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading…'));
-
- expect(screen.queryByTestId('detectors')).toBeInTheDocument();
- expect(screen.queryByText('coral')).toBeInTheDocument();
-
- expect(screen.queryByTestId('cameras')).toBeInTheDocument();
- expect(screen.queryByText('front')).toBeInTheDocument();
- expect(screen.queryByText('side')).toBeInTheDocument();
-
- expect(screen.queryByText('Config')).toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Copy to Clipboard' })).toBeInTheDocument();
- });
-});
diff --git a/web-old/src/routes/index.js b/web-old/src/routes/index.js
deleted file mode 100644
index 322a2b69a..000000000
--- a/web-old/src/routes/index.js
+++ /dev/null
@@ -1,59 +0,0 @@
-export async function getCameraMap(_url, _cb, _props) {
- const module = await import('./CameraMap.jsx');
- return module.default;
-}
-
-export async function getCamera(_url, _cb, _props) {
- const module = await import('./Camera.jsx');
- return module.default;
-}
-
-export async function getCameraV2(_url, _cb, _props) {
- const module = await import('./Camera_V2.jsx');
- return module.default;
-}
-
-export async function getBirdseye(_url, _cb, _props) {
- const module = await import('./Birdseye.jsx');
- return module.default;
-}
-
-export async function getEvents(_url, _cb, _props) {
- const module = await import('./Events.jsx');
- return module.default;
-}
-
-export async function getExports(_url, _cb, _props) {
- const module = await import('./Export.jsx');
- return module.default;
-}
-
-export async function getRecording(_url, _cb, _props) {
- const module = await import('./Recording.jsx');
- return module.default;
-}
-
-export async function getSystem(_url, _cb, _props) {
- const module = await import('./System.jsx');
- return module.default;
-}
-
-export async function getStorage(_url, _cb, _props) {
- const module = await import('./Storage.jsx');
- return module.default;
-}
-
-export async function getConfig(_url, _cb, _props) {
- const module = await import('./Config.jsx');
- return module.default;
-}
-
-export async function getLogs(_url, _cb, _props) {
- const module = await import('./Logs.jsx');
- return module.default;
-}
-
-export async function getStyleGuide(_url, _cb, _props) {
- const module = await import('./StyleGuide.jsx');
- return module.default;
-}
diff --git a/web-old/src/utils/Timeline/timelineEventUtils.ts b/web-old/src/utils/Timeline/timelineEventUtils.ts
deleted file mode 100644
index 484afbd40..000000000
--- a/web-old/src/utils/Timeline/timelineEventUtils.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import type { TimelineEvent } from '../../components/Timeline/TimelineEvent';
-import type { TimelineEventBlock } from '../../components/Timeline/TimelineEventBlock';
-import { epochToLong, longToDate } from '../dateUtil';
-
-export const checkEventForOverlap = (firstEvent: TimelineEvent, secondEvent: TimelineEvent) => {
- if (secondEvent.startTime < firstEvent.endTime && secondEvent.startTime > firstEvent.startTime) {
- return true;
- }
- return false;
-};
-
-export const getTimelineEventBlocksFromTimelineEvents = (events: TimelineEvent[], xOffset: number): TimelineEventBlock[] => {
- const firstEvent = events[0];
- const firstEventTime = longToDate(firstEvent.start_time);
- return events
- .map((e, index) => {
- const startTime = longToDate(e.start_time);
- const endTime = e.end_time ? longToDate(e.end_time) : new Date();
- const seconds = Math.round(Math.abs(endTime.getTime() - startTime.getTime()) / 1000);
- const positionX = Math.round(Math.abs(startTime.getTime() - firstEventTime.getTime()) / 1000 + xOffset);
- return {
- ...e,
- startTime,
- endTime,
- width: seconds,
- positionX,
- index,
- } as TimelineEventBlock;
- })
- .reduce((rowMap, current) => {
- for (let i = 0; i < rowMap.length; i++) {
- const row = rowMap[i] ?? [];
- const lastItem = row[row.length - 1];
- if (lastItem) {
- const isOverlap = checkEventForOverlap(lastItem, current);
- if (isOverlap) {
- continue;
- }
- }
- rowMap[i] = [...row, current];
- return rowMap;
- }
- rowMap.push([current]);
- return rowMap;
- }, [] as TimelineEventBlock[][])
- .flatMap((rows, rowPosition) => {
- rows.forEach((eventBlock) => {
- const OFFSET_DISTANCE_IN_PIXELS = 10;
- eventBlock.yOffset = OFFSET_DISTANCE_IN_PIXELS * rowPosition;
- });
- return rows;
- })
- .sort((a, b) => a.startTime.getTime() - b.startTime.getTime());
-};
-
-export const findLargestYOffsetInBlocks = (blocks: TimelineEventBlock[]): number => {
- return blocks.reduce((largestYOffset, current) => {
- if (current.yOffset > largestYOffset) {
- return current.yOffset;
- }
- return largestYOffset;
- }, 0);
-};
-
-export const getTimelineWidthFromBlocks = (blocks: TimelineEventBlock[], offset: number): number => {
- const firstBlock = blocks[0];
- if (firstBlock) {
- const startTimeEpoch = firstBlock.startTime.getTime();
- const endTimeEpoch = Date.now();
- const timelineDurationLong = epochToLong(endTimeEpoch - startTimeEpoch);
- return timelineDurationLong + offset * 2;
- }
- return 0;
-};
diff --git a/web-old/src/utils/dateUtil.ts b/web-old/src/utils/dateUtil.ts
deleted file mode 100644
index 03d5de849..000000000
--- a/web-old/src/utils/dateUtil.ts
+++ /dev/null
@@ -1,235 +0,0 @@
-import strftime from 'strftime';
-import { fromUnixTime, intervalToDuration, formatDuration } from 'date-fns';
-export const longToDate = (long: number): Date => new Date(long * 1000);
-export const epochToLong = (date: number): number => date / 1000;
-export const dateToLong = (date: Date): number => epochToLong(date.getTime());
-
-const getDateTimeYesterday = (dateTime: Date): Date => {
- const twentyFourHoursInMilliseconds = 24 * 60 * 60 * 1000;
- return new Date(dateTime.getTime() - twentyFourHoursInMilliseconds);
-};
-
-const getNowYesterday = (): Date => {
- return getDateTimeYesterday(new Date());
-};
-
-export const getNowYesterdayInLong = (): number => {
- return dateToLong(getNowYesterday());
-};
-
-/**
- * This function takes in a Unix timestamp, configuration options for date/time display, and an optional strftime format string,
- * and returns a formatted date/time string.
- *
- * If the Unix timestamp is not provided, it returns "Invalid time".
- *
- * The configuration options determine how the date and time are formatted.
- * The `timezone` option allows you to specify a specific timezone for the output, otherwise the user's browser timezone will be used.
- * The `use12hour` option allows you to display time in a 12-hour format if true, and 24-hour format if false.
- * The `dateStyle` and `timeStyle` options allow you to specify pre-defined formats for displaying the date and time.
- * The `strftime_fmt` option allows you to specify a custom format using the strftime syntax.
- *
- * If both `strftime_fmt` and `dateStyle`/`timeStyle` are provided, `strftime_fmt` takes precedence.
- *
- * @param unixTimestamp The Unix timestamp to format
- * @param config An object containing the configuration options for date/time display
- * @returns The formatted date/time string, or "Invalid time" if the Unix timestamp is not provided or invalid.
- */
-interface DateTimeStyle {
- timezone: string;
- time_format: 'browser' | '12hour' | '24hour';
- date_style: 'full' | 'long' | 'medium' | 'short';
- time_style: 'full' | 'long' | 'medium' | 'short';
- strftime_fmt: string;
-}
-
-// only used as a fallback if the browser does not support dateStyle/timeStyle in Intl.DateTimeFormat
-const formatMap: {
- [k: string]: {
- date: { year: 'numeric' | '2-digit'; month: 'long' | 'short' | '2-digit'; day: 'numeric' | '2-digit' };
- time: { hour: 'numeric'; minute: 'numeric'; second?: 'numeric'; timeZoneName?: 'short' | 'long' };
- };
-} = {
- full: {
- date: { year: 'numeric', month: 'long', day: 'numeric' },
- time: { hour: 'numeric', minute: 'numeric', second: 'numeric', timeZoneName: 'long' },
- },
- long: {
- date: { year: 'numeric', month: 'long', day: 'numeric' },
- time: { hour: 'numeric', minute: 'numeric', second: 'numeric', timeZoneName: 'long' },
- },
- medium: {
- date: { year: 'numeric', month: 'short', day: 'numeric' },
- time: { hour: 'numeric', minute: 'numeric', second: 'numeric' },
- },
- short: { date: { year: '2-digit', month: '2-digit', day: '2-digit' }, time: { hour: 'numeric', minute: 'numeric' } },
-};
-
-/**
- * Attempts to get the system's time zone using Intl.DateTimeFormat. If that fails (for instance, in environments
- * where Intl is not fully supported), it calculates the UTC offset for the current system time and returns
- * it in a string format.
- *
- * Keeping the Intl.DateTimeFormat for now, as this is the recommended way to get the time zone.
- * https://stackoverflow.com/a/34602679
- *
- * Intl.DateTimeFormat function as of April 2023, works in 95.03% of the browsers used globally
- * https://caniuse.com/mdn-javascript_builtins_intl_datetimeformat_resolvedoptions_computed_timezone
- *
- * @returns {string} The resolved time zone or a calculated UTC offset.
- * The returned string will either be a named time zone (e.g., "America/Los_Angeles"), or it will follow
- * the format "UTC±HH:MM".
- */
-const getResolvedTimeZone = () => {
- try {
- return Intl.DateTimeFormat().resolvedOptions().timeZone;
- } catch (error) {
- const offsetMinutes = new Date().getTimezoneOffset();
- return `UTC${offsetMinutes < 0 ? '+' : '-'}${Math.abs(offsetMinutes / 60)
- .toString()
- .padStart(2, '0')}:${Math.abs(offsetMinutes % 60)
- .toString()
- .padStart(2, '0')}`;
- }
-};
-
-/**
- * Formats a Unix timestamp into a human-readable date/time string.
- *
- * The format of the output string is determined by a configuration object passed as an argument, which
- * may specify a time zone, 12- or 24-hour time, and various stylistic options for the date and time.
- * If these options are not specified, the function will use system defaults or sensible fallbacks.
- *
- * The function is robust to environments where the Intl API is not fully supported, and includes a
- * fallback method to create a formatted date/time string in such cases.
- *
- * @param {number} unixTimestamp - The Unix timestamp to be formatted.
- * @param {DateTimeStyle} config - User configuration object.
- * @returns {string} A formatted date/time string.
- *
- * @throws {Error} If the given unixTimestamp is not a valid number, the function will return 'Invalid time'.
- */
-export const formatUnixTimestampToDateTime = (unixTimestamp: number, config: DateTimeStyle): string => {
- const { timezone, time_format, date_style, time_style, strftime_fmt } = config;
- const locale = window.navigator?.language || 'en-us';
- if (isNaN(unixTimestamp)) {
- return 'Invalid time';
- }
-
- try {
- const date = new Date(unixTimestamp * 1000);
- const resolvedTimeZone = getResolvedTimeZone();
-
- // use strftime_fmt if defined in config
- if (strftime_fmt) {
- const offset = getUTCOffset(date, timezone || resolvedTimeZone);
- const strftime_locale = strftime.timezone(offset).localizeByIdentifier(locale);
- return strftime_locale(strftime_fmt, date);
- }
-
- // DateTime format options
- const options: Intl.DateTimeFormatOptions = {
- dateStyle: date_style,
- timeStyle: time_style,
- hour12: time_format !== 'browser' ? time_format == '12hour' : undefined,
- };
-
- // Only set timeZone option when resolvedTimeZone does not match UTC±HH:MM format, or when timezone is set in config
- const isUTCOffsetFormat = /^UTC[+-]\d{2}:\d{2}$/.test(resolvedTimeZone);
- if (timezone || !isUTCOffsetFormat) {
- options.timeZone = timezone || resolvedTimeZone;
- }
-
- const formatter = new Intl.DateTimeFormat(locale, options);
- const formattedDateTime = formatter.format(date);
-
- // Regex to check for existence of time. This is needed because dateStyle/timeStyle is not always supported.
- const containsTime = /\d{1,2}:\d{1,2}/.test(formattedDateTime);
-
- // fallback if the browser does not support dateStyle/timeStyle in Intl.DateTimeFormat
- // This works even tough the timezone is undefined, it will use the runtime's default time zone
- if (!containsTime) {
- const dateOptions = { ...formatMap[date_style]?.date, timeZone: options.timeZone, hour12: options.hour12 };
- const timeOptions = { ...formatMap[time_style]?.time, timeZone: options.timeZone, hour12: options.hour12 };
-
- return `${date.toLocaleDateString(locale, dateOptions)} ${date.toLocaleTimeString(locale, timeOptions)}`;
- }
-
- return formattedDateTime;
- } catch (error) {
- return 'Invalid time';
- }
-};
-
-interface DurationToken {
- xSeconds: string;
- xMinutes: string;
- xHours: string;
-}
-
-/**
- * This function takes in start and end time in unix timestamp,
- * and returns the duration between start and end time in hours, minutes and seconds.
- * If end time is not provided, it returns 'In Progress'
- * @param start_time: number - Unix timestamp for start time
- * @param end_time: number|null - Unix timestamp for end time
- * @returns string - duration or 'In Progress' if end time is not provided
- */
-export const getDurationFromTimestamps = (start_time: number, end_time: number | null): string => {
- if (isNaN(start_time)) {
- return 'Invalid start time';
- }
- let duration = 'In Progress';
- if (end_time !== null) {
- if (isNaN(end_time)) {
- return 'Invalid end time';
- }
- const start = fromUnixTime(start_time);
- const end = fromUnixTime(end_time);
- const formatDistanceLocale: DurationToken = {
- xSeconds: '{{count}}s',
- xMinutes: '{{count}}m',
- xHours: '{{count}}h',
- };
- const shortEnLocale = {
- formatDistance: (token: keyof DurationToken, count: number) =>
- formatDistanceLocale[token].replace('{{count}}', count.toString()),
- };
- duration = formatDuration(intervalToDuration({ start, end }), {
- format: ['hours', 'minutes', 'seconds'],
- locale: shortEnLocale,
- });
- }
- return duration;
-};
-
-/**
- * Adapted from https://stackoverflow.com/a/29268535 this takes a timezone string and
- * returns the offset of that timezone from UTC in minutes.
- * @param timezone string representation of the timezone the user is requesting
- * @returns number of minutes offset from UTC
- */
-const getUTCOffset = (date: Date, timezone: string): number => {
- // If timezone is in UTC±HH:MM format, parse it to get offset
- const utcOffsetMatch = timezone.match(/^UTC([+-])(\d{2}):(\d{2})$/);
- if (utcOffsetMatch) {
- const hours = parseInt(utcOffsetMatch[2], 10);
- const minutes = parseInt(utcOffsetMatch[3], 10);
- return (utcOffsetMatch[1] === '+' ? 1 : -1) * (hours * 60 + minutes);
- }
-
- // Otherwise, calculate offset using provided timezone
- const utcDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
- // locale of en-CA is required for proper locale format
- let iso = utcDate.toLocaleString('en-CA', { timeZone: timezone, hour12: false }).replace(', ', 'T');
- iso += `.${utcDate.getMilliseconds().toString().padStart(3, '0')}`;
- let target = new Date(`${iso}Z`);
-
- // safari doesn't like the default format
- if (isNaN(target.getTime())) {
- iso = iso.replace("T", " ").split(".")[0];
- target = new Date(`${iso}+000`);
- }
-
- return (target.getTime() - utcDate.getTime()) / 60 / 1000;
-};
diff --git a/web-old/src/utils/objectUtils.ts b/web-old/src/utils/objectUtils.ts
deleted file mode 100644
index 01aab7839..000000000
--- a/web-old/src/utils/objectUtils.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const isNullOrUndefined = (object?: unknown): boolean => object === null || object === undefined;
\ No newline at end of file
diff --git a/web-old/src/utils/tailwind/twTimelineEventUtil.ts b/web-old/src/utils/tailwind/twTimelineEventUtil.ts
deleted file mode 100644
index 1735c2bd2..000000000
--- a/web-old/src/utils/tailwind/twTimelineEventUtil.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { TimelineEvent } from '../../components/Timeline/TimelineEvent';
-
-export const getColorFromTimelineEvent = (event: TimelineEvent) => {
- const { label } = event;
- if (label === 'car') {
- return 'bg-red-400';
- } else if (label === 'person') {
- return 'bg-blue-400';
- } else if (label === 'dog') {
- return 'bg-green-400';
- }
-
- // unknown label
- return 'bg-gray-400';
-};
\ No newline at end of file
diff --git a/web-old/src/utils/windowUtils.ts b/web-old/src/utils/windowUtils.ts
deleted file mode 100644
index 96a2f3a8c..000000000
--- a/web-old/src/utils/windowUtils.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const convertRemToPixels = (rem: number): number => {
- return rem * parseFloat(getComputedStyle(document.documentElement).fontSize);
-};
diff --git a/web-old/src/vite-env.d.ts b/web-old/src/vite-env.d.ts
deleted file mode 100644
index 11f02fe2a..000000000
--- a/web-old/src/vite-env.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/web-old/tailwind.config.cjs b/web-old/tailwind.config.cjs
deleted file mode 100644
index 2134071c7..000000000
--- a/web-old/tailwind.config.cjs
+++ /dev/null
@@ -1,24 +0,0 @@
-module.exports = {
- content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
- darkMode: 'class',
- theme: {
- extend: {
- screens: {
- xs: '480px',
- '2xl': '1536px',
- '3xl': '1720px',
- },
- },
- boxShadow: {
- sm: '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)',
- DEFAULT: '0px 2px 1px -1px rgb(0 0 0 / 20%), 0px 1px 1px 0px rgb(0 0 0 / 14%), 0px 1px 3px 0px rgb(0 0 0 / 12%);',
- md: '0px 2px 2px -1px rgb(0 0 0 / 20%), 0px 1px 1px 0px rgb(0 0 0 / 14%), 0px 1px 3px 0px rgb(0 0 0 / 12%);',
- lg: '0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)',
- xl: '0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22)',
- '2xl': '0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22)',
- '3xl': '',
- none: '',
- },
- },
- plugins: [require('@tailwindcss/forms')],
-};
diff --git a/web-old/tsconfig.json b/web-old/tsconfig.json
deleted file mode 100644
index 9c1b1e0aa..000000000
--- a/web-old/tsconfig.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "compilerOptions": {
- "target": "ESNext",
- "useDefineForClassFields": true,
- "lib": ["DOM", "DOM.Iterable", "ESNext"],
- "allowJs": false,
- "skipLibCheck": true,
- "esModuleInterop": false,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "module": "ESNext",
- "moduleResolution": "Node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "noEmit": true,
- "jsx": "react-jsx",
- "jsxImportSource": "preact"
- },
- "include": ["src"],
- "references": [{ "path": "./tsconfig.node.json" }]
-}
diff --git a/web-old/tsconfig.node.json b/web-old/tsconfig.node.json
deleted file mode 100644
index 9d31e2aed..000000000
--- a/web-old/tsconfig.node.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "compilerOptions": {
- "composite": true,
- "module": "ESNext",
- "moduleResolution": "Node",
- "allowSyntheticDefaultImports": true
- },
- "include": ["vite.config.ts"]
-}
diff --git a/web-old/vite.config.ts b/web-old/vite.config.ts
deleted file mode 100644
index ee33d491a..000000000
--- a/web-old/vite.config.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-///
-import path from 'path';
-import { defineConfig } from 'vite';
-import preact from '@preact/preset-vite';
-import monacoEditorPlugin from 'vite-plugin-monaco-editor';
-
-// https://vitejs.dev/config/
-export default defineConfig({
- define: {
- 'import.meta.vitest': 'undefined',
- },
- server: {
- proxy: {
- '/api': {
- target: 'http://localhost:5000'
- },
- '/vod': {
- target: 'http://localhost:5000'
- },
- '/exports': {
- target: 'http://localhost:5000'
- },
- '/ws': {
- target: 'ws://localhost:5000',
- ws: true,
- },
- '/live': {
- target: 'ws://localhost:5000',
- changeOrigin: true,
- ws: true,
- },
- }
- },
- plugins: [
- preact(),
- monacoEditorPlugin.default({
- customWorkers: [{ label: 'yaml', entry: 'monaco-yaml/yaml.worker' }],
- languageWorkers: ['editorWorkerService'], // we don't use any of the default languages
- }),
- ],
- test: {
- environment: 'jsdom',
- alias: {
- 'testing-library': path.resolve(__dirname, './__test__/testing-library.js'),
- },
- setupFiles: ['./__test__/test-setup.ts'],
- includeSource: ['src/**/*.{js,jsx,ts,tsx}'],
- coverage: {
- reporter: ['text-summary', 'text'],
- },
- mockReset: true,
- restoreMocks: true,
- globals: true,
- },
-});
\ No newline at end of file
diff --git a/web/.eslintrc.cjs b/web/.eslintrc.cjs
index f22e1f8b6..deba5f544 100644
--- a/web/.eslintrc.cjs
+++ b/web/.eslintrc.cjs
@@ -1,12 +1,13 @@
module.exports = {
root: true,
- env: { browser: true, es2021: true, "vitest-globals/env": true },
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
- "plugin:prettier",
+ "plugin:vitest-globals/recommended",
+ "plugin:prettier/recommended",
],
+ env: { browser: true, es2021: true, "vitest-globals/env": true },
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
parserOptions: {
@@ -21,9 +22,11 @@ module.exports = {
version: 27,
},
},
- ignorePatterns: ["*.d.ts"],
- plugins: ["react-refresh"],
+ ignorePatterns: ["*.d.ts", "/src/components/ui/*"],
+ plugins: ["react-hooks", "react-refresh"],
rules: {
+ "react-hooks/rules-of-hooks": "error",
+ "react-hooks/exhaustive-deps": "error",
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
diff --git a/web/package-lock.json b/web/package-lock.json
index 4073ae3a6..8a59b62f8 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -12,8 +12,10 @@
"@hookform/resolvers": "^3.3.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-aspect-ratio": "^1.0.3",
+ "@radix-ui/react-context-menu": "^2.1.5",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
+ "@radix-ui/react-hover-card": "^1.0.7",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.1.3",
@@ -23,37 +25,42 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
+ "@radix-ui/react-toggle": "^1.0.3",
+ "@radix-ui/react-toggle-group": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.7",
"apexcharts": "^3.45.1",
"axios": "^1.6.2",
"class-variance-authority": "^0.7.0",
- "clsx": "^2.0.0",
+ "clsx": "^2.1.0",
"copy-to-clipboard": "^3.3.3",
"date-fns": "^2.30.0",
"idb-keyval": "^6.2.1",
"immer": "^10.0.3",
"lucide-react": "^0.294.0",
- "monaco-yaml": "^5.1.0",
+ "monaco-yaml": "^5.1.1",
"next-themes": "^0.2.1",
"react": "^18.2.0",
"react-apexcharts": "^1.4.1",
"react-day-picker": "^8.9.1",
+ "react-device-detect": "^2.2.3",
"react-dom": "^18.2.0",
"react-hook-form": "^7.48.2",
"react-icons": "^4.12.0",
"react-router-dom": "^6.20.1",
- "react-use-websocket": "^4.5.0",
+ "react-swipeable": "^7.0.1",
+ "react-tracked": "^1.7.11",
+ "react-transition-group": "^4.4.5",
+ "react-use-websocket": "^4.7.0",
"recoil": "^0.7.7",
"sonner": "^1.4.0",
"sort-by": "^1.2.0",
"strftime": "^0.10.2",
- "swr": "^2.2.4",
+ "swr": "^2.2.5",
"tailwind-merge": "^2.1.0",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.8.0",
"video.js": "^8.6.1",
"videojs-playlist": "^5.1.0",
- "vis-timeline": "^7.7.3",
"vite-plugin-monaco-editor": "^1.1.0",
"zod": "^3.22.4"
},
@@ -64,13 +71,14 @@
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@types/react-icons": "^3.0.0",
+ "@types/react-transition-group": "^4.4.10",
"@types/strftime": "^0.9.8",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
- "@vitejs/plugin-react-swc": "^3.5.0",
+ "@vitejs/plugin-react-swc": "^3.6.0",
"@vitest/coverage-v8": "^1.0.0",
"autoprefixer": "^10.4.16",
- "eslint": "^8.53.0",
+ "eslint": "^8.55.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest": "^27.6.0",
"eslint-plugin-prettier": "^5.0.1",
@@ -80,13 +88,13 @@
"fake-indexeddb": "^5.0.1",
"jest-websocket-mock": "^2.5.0",
"jsdom": "^23.0.1",
- "msw": "^2.0.10",
+ "msw": "^2.2.1",
"postcss": "^8.4.32",
- "prettier": "^3.1.0",
- "tailwindcss": "^3.3.5",
+ "prettier": "^3.2.5",
+ "tailwindcss": "^3.4.1",
"typescript": "^5.2.2",
- "vite": "^5.0.0",
- "vitest": "^1.0.0"
+ "vite": "^5.1.4",
+ "vitest": "^1.3.1"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -198,15 +206,6 @@
"cookie": "^0.5.0"
}
},
- "node_modules/@bundled-es-modules/js-levenshtein": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@bundled-es-modules/js-levenshtein/-/js-levenshtein-2.0.1.tgz",
- "integrity": "sha512-DERMS3yfbAljKsQc0U2wcqGKUWpdFjwqWuoMugEJlqBnKO180/n+4SR/J8MRDt1AN48X1ovgoD9KrdVXcaa3Rg==",
- "dev": true,
- "dependencies": {
- "js-levenshtein": "^1.1.6"
- }
- },
"node_modules/@bundled-es-modules/statuses": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz",
@@ -221,18 +220,6 @@
"resolved": "https://registry.npmjs.org/@cycjimmy/jsmpeg-player/-/jsmpeg-player-6.0.5.tgz",
"integrity": "sha512-bVNHQ7VN9ecKT5AI/6RC7zpW/y4ca68a9txeR5Wiin+jKpUn/7buMe+5NPub89A8NNeNnKPQfrD2+c76ch36mA=="
},
- "node_modules/@egjs/hammerjs": {
- "version": "2.0.17",
- "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
- "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
- "peer": true,
- "dependencies": {
- "@types/hammerjs": "^2.0.36"
- },
- "engines": {
- "node": ">=0.8.0"
- }
- },
"node_modules/@esbuild/android-arm": {
"version": "0.19.8",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.8.tgz",
@@ -716,6 +703,53 @@
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true
},
+ "node_modules/@inquirer/confirm": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.0.0.tgz",
+ "integrity": "sha512-LHeuYP1D8NmQra1eR4UqvZMXwxEdDXyElJmmZfU44xdNLL6+GcQBS0uE16vyfZVjH8c22p9e+DStROfE/hyHrg==",
+ "dev": true,
+ "dependencies": {
+ "@inquirer/core": "^7.0.0",
+ "@inquirer/type": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/core": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-7.0.0.tgz",
+ "integrity": "sha512-g13W5yEt9r1sEVVriffJqQ8GWy94OnfxLCreNSOTw0HPVcszmc/If1KIf7YBmlwtX4klmvwpZHnQpl3N7VX2xA==",
+ "dev": true,
+ "dependencies": {
+ "@inquirer/type": "^1.2.0",
+ "@types/mute-stream": "^0.0.4",
+ "@types/node": "^20.11.16",
+ "@types/wrap-ansi": "^3.0.0",
+ "ansi-escapes": "^4.3.2",
+ "chalk": "^4.1.2",
+ "cli-spinners": "^2.9.2",
+ "cli-width": "^4.1.0",
+ "figures": "^3.2.0",
+ "mute-stream": "^1.0.0",
+ "run-async": "^3.0.0",
+ "signal-exit": "^4.1.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^6.2.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/type": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.2.0.tgz",
+ "integrity": "sha512-/vvkUkYhrjbm+RolU7V1aUFDydZVKNKqKHR5TsE+j5DXgXFwrsOPcoGUJ02K0O7q7O53CU2DOTMYCHeGZ25WHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@istanbuljs/schema": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
@@ -790,9 +824,9 @@
}
},
"node_modules/@mswjs/interceptors": {
- "version": "0.25.13",
- "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.25.13.tgz",
- "integrity": "sha512-xfjR81WwXPHwhDbqJRHlxYmboJuiSaIKpP4I5TJVFl/EmByOU13jOBT9hmEnxcjR3jvFYoqoNKt7MM9uqerj9A==",
+ "version": "0.25.16",
+ "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.25.16.tgz",
+ "integrity": "sha512-8QC8JyKztvoGAdPgyZy49c9vSHHAZjHagwl4RY9E8carULk8ym3iTaiawrT1YoLF/qb449h48f71XDPgkUSOUg==",
"dev": true,
"dependencies": {
"@open-draft/deferred-promise": "^2.2.0",
@@ -1180,6 +1214,34 @@
}
}
},
+ "node_modules/@radix-ui/react-context-menu": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.1.5.tgz",
+ "integrity": "sha512-R5XaDj06Xul1KGb+WP8qiOh7tKJNz2durpLBXAGZjSVtctcRFCuEvy2gtMwRJGePwQQE5nV77gs4FwRi8T+r2g==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-menu": "2.0.6",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-controllable-state": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-dialog": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz",
@@ -1331,6 +1393,37 @@
}
}
},
+ "node_modules/@radix-ui/react-hover-card": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.0.7.tgz",
+ "integrity": "sha512-OcUN2FU0YpmajD/qkph3XzMcK/NmSk9hGWnjV68p6QiZMgILugusgQwnLSDs3oFSJYGKf3Y49zgFedhGh04k9A==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-popper": "1.1.3",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-controllable-state": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-id": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz",
@@ -1798,6 +1891,60 @@
}
}
},
+ "node_modules/@radix-ui/react-toggle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz",
+ "integrity": "sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-controllable-state": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toggle-group": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz",
+ "integrity": "sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-direction": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-roving-focus": "1.0.4",
+ "@radix-ui/react-toggle": "1.0.3",
+ "@radix-ui/react-use-controllable-state": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-tooltip": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz",
@@ -2157,13 +2304,13 @@
"dev": true
},
"node_modules/@swc/core": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.100.tgz",
- "integrity": "sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.4.2.tgz",
+ "integrity": "sha512-vWgY07R/eqj1/a0vsRKLI9o9klGZfpLNOVEnrv4nrccxBgYPjcf22IWwAoaBJ+wpA7Q4fVjCUM8lP0m01dpxcg==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
- "@swc/counter": "^0.1.1",
+ "@swc/counter": "^0.1.2",
"@swc/types": "^0.1.5"
},
"engines": {
@@ -2174,15 +2321,16 @@
"url": "https://opencollective.com/swc"
},
"optionalDependencies": {
- "@swc/core-darwin-arm64": "1.3.100",
- "@swc/core-darwin-x64": "1.3.100",
- "@swc/core-linux-arm64-gnu": "1.3.100",
- "@swc/core-linux-arm64-musl": "1.3.100",
- "@swc/core-linux-x64-gnu": "1.3.100",
- "@swc/core-linux-x64-musl": "1.3.100",
- "@swc/core-win32-arm64-msvc": "1.3.100",
- "@swc/core-win32-ia32-msvc": "1.3.100",
- "@swc/core-win32-x64-msvc": "1.3.100"
+ "@swc/core-darwin-arm64": "1.4.2",
+ "@swc/core-darwin-x64": "1.4.2",
+ "@swc/core-linux-arm-gnueabihf": "1.4.2",
+ "@swc/core-linux-arm64-gnu": "1.4.2",
+ "@swc/core-linux-arm64-musl": "1.4.2",
+ "@swc/core-linux-x64-gnu": "1.4.2",
+ "@swc/core-linux-x64-musl": "1.4.2",
+ "@swc/core-win32-arm64-msvc": "1.4.2",
+ "@swc/core-win32-ia32-msvc": "1.4.2",
+ "@swc/core-win32-x64-msvc": "1.4.2"
},
"peerDependencies": {
"@swc/helpers": "^0.5.0"
@@ -2194,9 +2342,9 @@
}
},
"node_modules/@swc/core-darwin-arm64": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.100.tgz",
- "integrity": "sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.2.tgz",
+ "integrity": "sha512-1uSdAn1MRK5C1m/TvLZ2RDvr0zLvochgrZ2xL+lRzugLlCTlSA+Q4TWtrZaOz+vnnFVliCpw7c7qu0JouhgQIw==",
"cpu": [
"arm64"
],
@@ -2210,9 +2358,9 @@
}
},
"node_modules/@swc/core-darwin-x64": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.100.tgz",
- "integrity": "sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.2.tgz",
+ "integrity": "sha512-TYD28+dCQKeuxxcy7gLJUCFLqrwDZnHtC2z7cdeGfZpbI2mbfppfTf2wUPzqZk3gEC96zHd4Yr37V3Tvzar+lQ==",
"cpu": [
"x64"
],
@@ -2225,10 +2373,26 @@
"node": ">=10"
}
},
+ "node_modules/@swc/core-linux-arm-gnueabihf": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.2.tgz",
+ "integrity": "sha512-Eyqipf7ZPGj0vplKHo8JUOoU1un2sg5PjJMpEesX0k+6HKE2T8pdyeyXODN0YTFqzndSa/J43EEPXm+rHAsLFQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/@swc/core-linux-arm64-gnu": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.100.tgz",
- "integrity": "sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.2.tgz",
+ "integrity": "sha512-wZn02DH8VYPv3FC0ub4my52Rttsus/rFw+UUfzdb3tHMHXB66LqN+rR0ssIOZrH6K+VLN6qpTw9VizjyoH0BxA==",
"cpu": [
"arm64"
],
@@ -2242,9 +2406,9 @@
}
},
"node_modules/@swc/core-linux-arm64-musl": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.100.tgz",
- "integrity": "sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.2.tgz",
+ "integrity": "sha512-3G0D5z9hUj9bXNcwmA1eGiFTwe5rWkuL3DsoviTj73TKLpk7u64ND0XjEfO0huVv4vVu9H1jodrKb7nvln/dlw==",
"cpu": [
"arm64"
],
@@ -2258,9 +2422,9 @@
}
},
"node_modules/@swc/core-linux-x64-gnu": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.100.tgz",
- "integrity": "sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.2.tgz",
+ "integrity": "sha512-LFxn9U8cjmYHw3jrdPNqPAkBGglKE3tCZ8rA7hYyp0BFxuo7L2ZcEnPm4RFpmSCCsExFH+LEJWuMGgWERoktvg==",
"cpu": [
"x64"
],
@@ -2274,9 +2438,9 @@
}
},
"node_modules/@swc/core-linux-x64-musl": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.100.tgz",
- "integrity": "sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.2.tgz",
+ "integrity": "sha512-dp0fAmreeVVYTUcb4u9njTPrYzKnbIH0EhH2qvC9GOYNNREUu2GezSIDgonjOXkHiTCvopG4xU7y56XtXj4VrQ==",
"cpu": [
"x64"
],
@@ -2290,9 +2454,9 @@
}
},
"node_modules/@swc/core-win32-arm64-msvc": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.100.tgz",
- "integrity": "sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.2.tgz",
+ "integrity": "sha512-HlVIiLMQkzthAdqMslQhDkoXJ5+AOLUSTV6fm6shFKZKqc/9cJvr4S8UveNERL9zUficA36yM3bbfo36McwnvQ==",
"cpu": [
"arm64"
],
@@ -2306,9 +2470,9 @@
}
},
"node_modules/@swc/core-win32-ia32-msvc": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.100.tgz",
- "integrity": "sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.2.tgz",
+ "integrity": "sha512-WCF8faPGjCl4oIgugkp+kL9nl3nUATlzKXCEGFowMEmVVCFM0GsqlmGdPp1pjZoWc9tpYanoXQDnp5IvlDSLhA==",
"cpu": [
"ia32"
],
@@ -2322,9 +2486,9 @@
}
},
"node_modules/@swc/core-win32-x64-msvc": {
- "version": "1.3.100",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.100.tgz",
- "integrity": "sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.2.tgz",
+ "integrity": "sha512-oV71rwiSpA5xre2C5570BhCsg1HF97SNLsZ/12xv7zayGzqr3yvFALFJN8tHKpqUdCB4FGPjoP3JFdV3i+1wUw==",
"cpu": [
"x64"
],
@@ -2338,9 +2502,9 @@
}
},
"node_modules/@swc/counter": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz",
- "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==",
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
"dev": true
},
"node_modules/@swc/helpers": {
@@ -2425,16 +2589,16 @@
}
},
"node_modules/@types/cookie": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
- "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
"dev": true
},
- "node_modules/@types/hammerjs": {
- "version": "2.0.45",
- "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.45.tgz",
- "integrity": "sha512-qkcUlZmX6c4J8q45taBKTL3p+LbITgyx7qhlPYOdOHZB7B31K0mXbP5YA7i7SgDeEGuI9MnumiKPEMrxg8j3KQ==",
- "peer": true
+ "node_modules/@types/estree": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
+ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
+ "dev": true
},
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
@@ -2442,21 +2606,24 @@
"integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
"dev": true
},
- "node_modules/@types/js-levenshtein": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz",
- "integrity": "sha512-jd+Q+sD20Qfu9e2aEXogiO3vpOC1PYJOUdyN9gvs4Qrvkg4wF43L5OhqrPeokdv8TL0/mXoYfpkcoGZMNN2pkQ==",
- "dev": true
- },
"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=="
},
+ "node_modules/@types/mute-stream": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz",
+ "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/node": {
- "version": "20.10.3",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.3.tgz",
- "integrity": "sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg==",
+ "version": "20.11.19",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz",
+ "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -2498,6 +2665,15 @@
"react-icons": "*"
}
},
+ "node_modules/@types/react-transition-group": {
+ "version": "4.4.10",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz",
+ "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==",
+ "dev": true,
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/scheduler": {
"version": "0.16.8",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
@@ -2522,6 +2698,12 @@
"integrity": "sha512-QIvDlGAKyF3YJbT3QZnfC+RIvV5noyDbi+ZJ5rkaSRqxCGrYJefgXm3leZAjtoQOutZe1hCXbAg+p89/Vj4HlQ==",
"dev": true
},
+ "node_modules/@types/wrap-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz",
+ "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==",
+ "dev": true
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "6.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.1.tgz",
@@ -2804,12 +2986,12 @@
}
},
"node_modules/@vitejs/plugin-react-swc": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.5.0.tgz",
- "integrity": "sha512-1PrOvAaDpqlCV+Up8RkAh9qaiUjoDUcjtttyhXDKw53XA6Ve16SOp6cCOpRs8Dj8DqUQs6eTW5YkLcLJjrXAig==",
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.6.0.tgz",
+ "integrity": "sha512-XFRbsGgpGxGzEV5i5+vRiro1bwcIaZDIdBRP16qwm+jP68ue/S8FJTBEgOeojtVDYrbSua3XFp71kC8VJE6v+g==",
"dev": true,
"dependencies": {
- "@swc/core": "^1.3.96"
+ "@swc/core": "^1.3.107"
},
"peerDependencies": {
"vite": "^4 || ^5"
@@ -2843,13 +3025,13 @@
}
},
"node_modules/@vitest/expect": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.0.0.tgz",
- "integrity": "sha512-EbqHCSzQhAY8Su/uLsMCDXkC26LyqQO54kAqJy/DubBqwpRre1iMzvDMPWx+YPfNIN3w7/ydKaJWjH6qRoz0fA==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz",
+ "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==",
"dev": true,
"dependencies": {
- "@vitest/spy": "1.0.0",
- "@vitest/utils": "1.0.0",
+ "@vitest/spy": "1.3.1",
+ "@vitest/utils": "1.3.1",
"chai": "^4.3.10"
},
"funding": {
@@ -2857,12 +3039,12 @@
}
},
"node_modules/@vitest/runner": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.0.0.tgz",
- "integrity": "sha512-1CaYs4knCexozpGxNiT89foiIxidOdU220QpU6CKMN0qU05e3K5XNH8f4pW9KyXH37o1Zin1cLHkoLr/k7NyrQ==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz",
+ "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==",
"dev": true,
"dependencies": {
- "@vitest/utils": "1.0.0",
+ "@vitest/utils": "1.3.1",
"p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
@@ -2898,9 +3080,9 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.0.0.tgz",
- "integrity": "sha512-kAcQJGsaHMBLrY0QC6kMe7S+JgiMielX2qHqgWFxlUir5IVekJGokJcYTzoOp+MRN1Gue3Q6H5fZD4aC0XHloA==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz",
+ "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==",
"dev": true,
"dependencies": {
"magic-string": "^0.30.5",
@@ -2912,9 +3094,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.0.0.tgz",
- "integrity": "sha512-k2gZwSi7nkwcYMj1RNgb45jNUDV/opAGlsVvcmYrRXu2QljMSlyAa0Yut+n3S39XoEKp0I4ggVLABj0xVInynw==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz",
+ "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==",
"dev": true,
"dependencies": {
"tinyspy": "^2.2.0"
@@ -2924,12 +3106,13 @@
}
},
"node_modules/@vitest/utils": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.0.0.tgz",
- "integrity": "sha512-r9JhgaP2bUYSnKE9w0aNblCIK8SKpDhXfJgE4TzjDNq3G40Abo5WXJBEKYAteq5p+OWedSFUg6GirNOlH7pN7Q==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz",
+ "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==",
"dev": true,
"dependencies": {
"diff-sequences": "^29.6.3",
+ "estree-walker": "^3.0.3",
"loupe": "^2.3.7",
"pretty-format": "^29.7.0"
},
@@ -2972,9 +3155,9 @@
}
},
"node_modules/acorn-walk": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz",
- "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==",
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
+ "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
"dev": true,
"engines": {
"node": ">=0.4.0"
@@ -3221,26 +3404,6 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
- "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/big-integer": {
"version": "1.6.52",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
@@ -3258,17 +3421,6 @@
"node": ">=8"
}
},
- "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/bplist-parser": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
@@ -3333,30 +3485,6 @@
"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/bundle-name": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
@@ -3430,9 +3558,9 @@
]
},
"node_modules/chai": {
- "version": "4.3.10",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz",
- "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
+ "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
"dev": true,
"dependencies": {
"assertion-error": "^1.1.0",
@@ -3463,12 +3591,6 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
- "node_modules/chardet": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
- "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
- "dev": true
- },
"node_modules/check-error": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
@@ -3529,16 +3651,12 @@
"url": "https://joebell.co.uk"
}
},
- "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"
- },
+ "node_modules/class-variance-authority/node_modules/clsx": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
+ "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
"engines": {
- "node": ">=8"
+ "node": ">=6"
}
},
"node_modules/cli-spinners": {
@@ -3554,12 +3672,12 @@
}
},
"node_modules/cli-width": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
- "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
"dev": true,
"engines": {
- "node": ">= 10"
+ "node": ">= 12"
}
},
"node_modules/client-only": {
@@ -3598,19 +3716,10 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "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/clsx": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
- "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
+ "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
"engines": {
"node": ">=6"
}
@@ -3652,15 +3761,6 @@
"node": ">= 6"
}
},
- "node_modules/component-emitter": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
- "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==",
- "peer": true,
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -3720,12 +3820,6 @@
"node": ">=4"
}
},
- "node_modules/cssfilter": {
- "version": "0.0.10",
- "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
- "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==",
- "peer": true
- },
"node_modules/cssstyle": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
@@ -3741,8 +3835,7 @@
"node_modules/csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
- "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
- "devOptional": true
+ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
},
"node_modules/data-urls": {
"version": "5.0.0",
@@ -3897,18 +3990,6 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
- "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-lazy-prop": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
@@ -3992,6 +4073,15 @@
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true
},
+ "node_modules/dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "dependencies": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
"node_modules/dom-walk": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
@@ -4427,6 +4517,15 @@
"node": ">=4.0"
}
},
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -4459,20 +4558,6 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
- "node_modules/external-editor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
- "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
- "dev": true,
- "dependencies": {
- "chardet": "^0.7.0",
- "iconv-lite": "^0.4.24",
- "tmp": "^0.0.33"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/fake-indexeddb": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/fake-indexeddb/-/fake-indexeddb-5.0.1.tgz",
@@ -4624,9 +4709,9 @@
"dev": true
},
"node_modules/follow-redirects": {
- "version": "1.15.3",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
- "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
+ "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
"funding": [
{
"type": "individual",
@@ -4912,43 +4997,11 @@
"node": ">=16.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/idb-keyval": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
"integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
},
- "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": "5.3.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
@@ -5020,32 +5073,6 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
- "node_modules/inquirer": {
- "version": "8.2.6",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
- "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
- "dev": true,
- "dependencies": {
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.1.1",
- "cli-cursor": "^3.1.0",
- "cli-width": "^3.0.0",
- "external-editor": "^3.0.3",
- "figures": "^3.0.0",
- "lodash": "^4.17.21",
- "mute-stream": "0.0.8",
- "ora": "^5.4.1",
- "run-async": "^2.4.0",
- "rxjs": "^7.5.5",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0",
- "through": "^2.3.6",
- "wrap-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -5142,15 +5169,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "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-node-process": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
@@ -5192,18 +5210,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "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",
@@ -5329,15 +5335,6 @@
"jiti": "bin/jiti.js"
}
},
- "node_modules/js-levenshtein": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
- "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -5418,12 +5415,6 @@
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w=="
},
- "node_modules/keycharm": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.4.0.tgz",
- "integrity": "sha512-TyQTtsabOVv3MeOpR92sIKk/br9wxS+zGj4BG7CR8YbK4jM3tyIBaF0zhzeBUMx36/Q/iQLOKKOT+3jOQtemRQ==",
- "peer": true
- },
"node_modules/keycode": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
@@ -5507,22 +5498,6 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"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/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -5740,15 +5715,6 @@
"node": ">= 8"
}
},
- "node_modules/moment": {
- "version": "2.29.4",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
- "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
- "peer": true,
- "engines": {
- "node": "*"
- }
- },
"node_modules/monaco-editor": {
"version": "0.44.0",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz",
@@ -5756,12 +5722,13 @@
"peer": true
},
"node_modules/monaco-languageserver-types": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/monaco-languageserver-types/-/monaco-languageserver-types-0.2.3.tgz",
- "integrity": "sha512-QyV5R7s+rJ87bX1sRioMJZULWiTnMp0Vm+RLILgMEL0SqWuBsQBSW0EZunr4xMZhv6Qun3UZNCN4JrCCLURcgQ==",
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/monaco-languageserver-types/-/monaco-languageserver-types-0.3.2.tgz",
+ "integrity": "sha512-KiGVYK/DiX1pnacnOjGNlM85bhV3ZTyFlM+ce7B8+KpWCbF1XJVovu51YyuGfm+K7+K54mIpT4DFX16xmi+tYA==",
"dependencies": {
"monaco-types": "^0.1.0",
- "vscode-languageserver-protocol": "^3.0.0"
+ "vscode-languageserver-protocol": "^3.0.0",
+ "vscode-uri": "^3.0.0"
},
"funding": {
"url": "https://github.com/sponsors/remcohaszing"
@@ -5795,13 +5762,13 @@
}
},
"node_modules/monaco-yaml": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/monaco-yaml/-/monaco-yaml-5.1.0.tgz",
- "integrity": "sha512-DU+cgXSJdOFKQ4I4oLg0V+mHKq1dJX+7hbIE4fJsgegUf1zEHW3PNlGj6qabUU2HZIPJ5NmXEf005GU9YDzTYQ==",
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/monaco-yaml/-/monaco-yaml-5.1.1.tgz",
+ "integrity": "sha512-BuZ0/ZCGjrPNRzYMZ/MoxH8F/SdM+mATENXnpOhDYABi1Eh+QvxSszEct+ACSCarZiwLvy7m6yEF/pvW8XJkyQ==",
"dependencies": {
"@types/json-schema": "^7.0.0",
"jsonc-parser": "^3.0.0",
- "monaco-languageserver-types": "^0.2.0",
+ "monaco-languageserver-types": "^0.3.0",
"monaco-marker-data-provider": "^1.0.0",
"monaco-types": "^0.1.0",
"monaco-worker-manager": "^2.0.0",
@@ -5868,33 +5835,29 @@
"dev": true
},
"node_modules/msw": {
- "version": "2.0.10",
- "resolved": "https://registry.npmjs.org/msw/-/msw-2.0.10.tgz",
- "integrity": "sha512-JhKdzIEuMDSU7qak4CJjiSFW2J0R4Wm5AuLhFzimKs68Wx7PTyqjgnw7+7FpQ3kGi0yY49g/qEFmUmMyLmjb4w==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/msw/-/msw-2.2.1.tgz",
+ "integrity": "sha512-DCsZAQwan+2onEcpD86fiEnCKW4IvYzqcwDq/2TIoeNrmBqNp/mJW4wHQyxcoYrRPwgujin7wDFflqiSO1iT/w==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"@bundled-es-modules/cookie": "^2.0.0",
- "@bundled-es-modules/js-levenshtein": "^2.0.1",
"@bundled-es-modules/statuses": "^1.0.1",
+ "@inquirer/confirm": "^3.0.0",
"@mswjs/cookies": "^1.1.0",
- "@mswjs/interceptors": "^0.25.13",
+ "@mswjs/interceptors": "^0.25.16",
"@open-draft/until": "^2.1.0",
- "@types/cookie": "^0.4.1",
- "@types/js-levenshtein": "^1.1.1",
- "@types/statuses": "^2.0.1",
+ "@types/cookie": "^0.6.0",
+ "@types/statuses": "^2.0.4",
"chalk": "^4.1.2",
- "chokidar": "^3.4.2",
"graphql": "^16.8.1",
- "headers-polyfill": "^4.0.1",
- "inquirer": "^8.2.0",
+ "headers-polyfill": "^4.0.2",
"is-node-process": "^1.2.0",
- "js-levenshtein": "^1.1.6",
- "outvariant": "^1.4.0",
+ "outvariant": "^1.4.2",
"path-to-regexp": "^6.2.0",
- "strict-event-emitter": "^0.5.0",
- "type-fest": "^2.19.0",
- "yargs": "^17.3.1"
+ "strict-event-emitter": "^0.5.1",
+ "type-fest": "^4.9.0",
+ "yargs": "^17.7.2"
},
"bin": {
"msw": "cli/index.js"
@@ -5907,7 +5870,7 @@
"url": "https://opencollective.com/mswjs"
},
"peerDependencies": {
- "typescript": ">= 4.7.x <= 5.2.x"
+ "typescript": ">= 4.7.x <= 5.3.x"
},
"peerDependenciesMeta": {
"typescript": {
@@ -5916,22 +5879,25 @@
}
},
"node_modules/msw/node_modules/type-fest": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
- "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "version": "4.10.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz",
+ "integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==",
"dev": true,
"engines": {
- "node": ">=12.20"
+ "node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mute-stream": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
- "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
- "dev": true
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz",
+ "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==",
+ "dev": true,
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
},
"node_modules/mux.js": {
"version": "7.0.2",
@@ -6204,42 +6170,10 @@
"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/os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/outvariant": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz",
- "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.2.tgz",
+ "integrity": "sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==",
"dev": true
},
"node_modules/p-limit": {
@@ -6417,9 +6351,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.32",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
- "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
+ "version": "8.4.35",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
+ "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
"funding": [
{
"type": "opencollective",
@@ -6564,9 +6498,9 @@
}
},
"node_modules/prettier": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
- "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
+ "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
"dev": true,
"bin": {
"prettier": "bin/prettier.cjs"
@@ -6639,14 +6573,10 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
- "node_modules/propagating-hammerjs": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/propagating-hammerjs/-/propagating-hammerjs-2.0.1.tgz",
- "integrity": "sha512-PH3zG5whbSxMocphXJzVtvKr+vWAgfkqVvtuwjSJ/apmEACUoiw6auBAT5HYXpZOR0eGcTAfYG5Yl8h91O5Elg==",
- "peer": true,
- "peerDependencies": {
- "@egjs/hammerjs": "^2.0.17"
- }
+ "node_modules/proxy-compare": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.4.0.tgz",
+ "integrity": "sha512-FD8KmQUQD6Mfpd0hywCOzcon/dbkFP8XBd9F1ycbKtvVsfv6TsFUKJ2eC0Iz2y+KzlkdT1Z8SY6ZSgm07zOyqg=="
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
@@ -6729,6 +6659,18 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
+ "node_modules/react-device-detect": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.3.tgz",
+ "integrity": "sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==",
+ "dependencies": {
+ "ua-parser-js": "^1.0.33"
+ },
+ "peerDependencies": {
+ "react": ">= 0.14.0",
+ "react-dom": ">= 0.14.0"
+ }
+ },
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
@@ -6867,10 +6809,56 @@
}
}
},
+ "node_modules/react-swipeable": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/react-swipeable/-/react-swipeable-7.0.1.tgz",
+ "integrity": "sha512-RKB17JdQzvECfnVj9yDZsiYn3vH0eyva/ZbrCZXZR0qp66PBRhtg4F9yJcJTWYT5Adadi+x4NoG53BxKHwIYLQ==",
+ "peerDependencies": {
+ "react": "^16.8.3 || ^17 || ^18"
+ }
+ },
+ "node_modules/react-tracked": {
+ "version": "1.7.11",
+ "resolved": "https://registry.npmjs.org/react-tracked/-/react-tracked-1.7.11.tgz",
+ "integrity": "sha512-+XXv4dJH7NnLtSD/cPVL9omra4A3KRK91L33owevXZ81r7qF/a9DdCsVZa90jMGht/V1Ym9sasbmidsJykhULQ==",
+ "dependencies": {
+ "proxy-compare": "2.4.0",
+ "use-context-selector": "1.4.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": "*",
+ "react-native": "*",
+ "scheduler": ">=0.19.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.0"
+ }
+ },
"node_modules/react-use-websocket": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.5.0.tgz",
- "integrity": "sha512-oxYVLWM3Lv0InCfjW7hG/Hk0hkE0P1SiLd5/I3d5x0W4riAnDUkD4VEu7qNVAqxNjBF3nU7k0jLMOetLXpwfsA==",
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.7.0.tgz",
+ "integrity": "sha512-YjR62jB7vB94IZy5UPBGZSR3c0hxu796q9IuJ0vbNg7InJ7Z84NHOd/LHzVI5nAKtaGy1oqvf8EmjKxX+cNz4A==",
"peerDependencies": {
"react": ">= 18.0.0",
"react-dom": ">= 18.0.0"
@@ -6884,20 +6872,6 @@
"pify": "^2.3.0"
}
},
- "node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -6986,49 +6960,6 @@
"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/restore-cursor/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/restore-cursor/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/restore-cursor/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/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -7210,9 +7141,9 @@
}
},
"node_modules/run-async": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
- "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz",
+ "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==",
"dev": true,
"engines": {
"node": ">=0.12.0"
@@ -7248,35 +7179,6 @@
"individual": "^2.0.0"
}
},
- "node_modules/rxjs": {
- "version": "7.8.1",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
- "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
- "dev": true,
- "dependencies": {
- "tslib": "^2.1.0"
- }
- },
- "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/safe-json-parse": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz",
@@ -7452,15 +7354,6 @@
"integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==",
"dev": true
},
- "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",
@@ -7524,17 +7417,23 @@
}
},
"node_modules/strip-literal": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz",
- "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz",
+ "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==",
"dev": true,
"dependencies": {
- "acorn": "^8.10.0"
+ "js-tokens": "^8.0.2"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
+ "node_modules/strip-literal/node_modules/js-tokens": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz",
+ "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==",
+ "dev": true
+ },
"node_modules/styled-jsx": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
@@ -7705,9 +7604,9 @@
}
},
"node_modules/swr": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.4.tgz",
- "integrity": "sha512-njiZ/4RiIhoOlAaLYDqwz5qH/KZXVilRLvomrx83HjzCWTfa+InyfAjv05PSFxnmLzZkNO9ZfvgoqzAaEI4sGQ==",
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz",
+ "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==",
"dependencies": {
"client-only": "^0.0.1",
"use-sync-external-store": "^1.2.0"
@@ -7751,9 +7650,9 @@
}
},
"node_modules/tailwindcss": {
- "version": "3.3.5",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
- "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
+ "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@@ -7833,12 +7732,6 @@
"node": ">=0.8"
}
},
- "node_modules/through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
- "dev": true
- },
"node_modules/tinybench": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz",
@@ -7846,18 +7739,18 @@
"dev": true
},
"node_modules/tinypool": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.1.tgz",
- "integrity": "sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg==",
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.2.tgz",
+ "integrity": "sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==",
"dev": true,
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/tinyspy": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz",
- "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz",
+ "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==",
"dev": true,
"engines": {
"node": ">=14.0.0"
@@ -7875,18 +7768,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/tmp": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
- "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
- "dev": true,
- "dependencies": {
- "os-tmpdir": "~1.0.2"
- },
- "engines": {
- "node": ">=0.6.0"
- }
- },
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -8028,6 +7909,28 @@
"node": ">=14.17"
}
},
+ "node_modules/ua-parser-js": {
+ "version": "1.0.37",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz",
+ "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ua-parser-js"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/faisalman"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/faisalman"
+ }
+ ],
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/ufo": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz",
@@ -8132,6 +8035,25 @@
}
}
},
+ "node_modules/use-context-selector": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/use-context-selector/-/use-context-selector-1.4.1.tgz",
+ "integrity": "sha512-Io2ArvcRO+6MWIhkdfMFt+WKQX+Vb++W8DS2l03z/Vw/rz3BclKpM0ynr4LYGyU85Eke+Yx5oIhTY++QR0ZDoA==",
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": "*",
+ "react-native": "*",
+ "scheduler": ">=0.19.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
"node_modules/use-sidecar": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
@@ -8166,19 +8088,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
- "node_modules/uuid": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
- "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
- "funding": [
- "https://github.com/sponsors/broofa",
- "https://github.com/sponsors/ctavan"
- ],
- "peer": true,
- "bin": {
- "uuid": "dist/bin/uuid"
- }
- },
"node_modules/v8-to-istanbul": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz",
@@ -8266,65 +8175,14 @@
"global": "^4.3.1"
}
},
- "node_modules/vis-data": {
- "version": "7.1.9",
- "resolved": "https://registry.npmjs.org/vis-data/-/vis-data-7.1.9.tgz",
- "integrity": "sha512-COQsxlVrmcRIbZMMTYwD+C2bxYCFDNQ2EHESklPiInbD/Pk3JZ6qNL84Bp9wWjYjAzXfSlsNaFtRk+hO9yBPWA==",
- "peer": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/visjs"
- },
- "peerDependencies": {
- "uuid": "^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
- "vis-util": "^5.0.1"
- }
- },
- "node_modules/vis-timeline": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/vis-timeline/-/vis-timeline-7.7.3.tgz",
- "integrity": "sha512-hGMzTttdOFWaw1PPlJuCXU2/4UjnsIxT684Thg9fV6YU1JuKZJs3s3BrJgZ4hO3gu5i1hsMe1YIi96o+eNT0jg==",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/visjs"
- },
- "peerDependencies": {
- "@egjs/hammerjs": "^2.0.0",
- "component-emitter": "^1.3.0",
- "keycharm": "^0.2.0 || ^0.3.0 || ^0.4.0",
- "moment": "^2.24.0",
- "propagating-hammerjs": "^1.4.0 || ^2.0.0",
- "uuid": "^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
- "vis-data": "^6.3.0 || ^7.0.0",
- "vis-util": "^5.0.1",
- "xss": "^1.0.0"
- }
- },
- "node_modules/vis-util": {
- "version": "5.0.7",
- "resolved": "https://registry.npmjs.org/vis-util/-/vis-util-5.0.7.tgz",
- "integrity": "sha512-E3L03G3+trvc/X4LXvBfih3YIHcKS2WrP0XTdZefr6W6Qi/2nNCqZfe4JFfJU6DcQLm6Gxqj2Pfl+02859oL5A==",
- "peer": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/visjs"
- },
- "peerDependencies": {
- "@egjs/hammerjs": "^2.0.0",
- "component-emitter": "^1.3.0 || ^2.0.0"
- }
- },
"node_modules/vite": {
- "version": "5.0.5",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.5.tgz",
- "integrity": "sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg==",
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz",
+ "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==",
"dev": true,
"dependencies": {
"esbuild": "^0.19.3",
- "postcss": "^8.4.32",
+ "postcss": "^8.4.35",
"rollup": "^4.2.0"
},
"bin": {
@@ -8373,16 +8231,16 @@
}
},
"node_modules/vite-node": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.0.0.tgz",
- "integrity": "sha512-9pGEPYsHy+7Ok7d6FkvniCmMI58IJ4KfFSK0Xq2FHWPQoBRpJKubaNBvMcXm0+uAwS6K2Rh9qJOKijdgqrjN+Q==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz",
+ "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==",
"dev": true,
"dependencies": {
"cac": "^6.7.14",
"debug": "^4.3.4",
"pathe": "^1.1.1",
"picocolors": "^1.0.0",
- "vite": "^5.0.0-beta.15 || ^5.0.0"
+ "vite": "^5.0.0"
},
"bin": {
"vite-node": "vite-node.mjs"
@@ -8403,18 +8261,17 @@
}
},
"node_modules/vitest": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.0.0.tgz",
- "integrity": "sha512-jpablj5+ifiFHV3QGOxPews3uxBuu6rQUzTaQYtEd6ocBpdQBil6AvmmGRQ3Rn0WPgyzb+Ni+JekfMyng+qYng==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz",
+ "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==",
"dev": true,
"dependencies": {
- "@vitest/expect": "1.0.0",
- "@vitest/runner": "1.0.0",
- "@vitest/snapshot": "1.0.0",
- "@vitest/spy": "1.0.0",
- "@vitest/utils": "1.0.0",
- "acorn-walk": "^8.3.0",
- "cac": "^6.7.14",
+ "@vitest/expect": "1.3.1",
+ "@vitest/runner": "1.3.1",
+ "@vitest/snapshot": "1.3.1",
+ "@vitest/spy": "1.3.1",
+ "@vitest/utils": "1.3.1",
+ "acorn-walk": "^8.3.2",
"chai": "^4.3.10",
"debug": "^4.3.4",
"execa": "^8.0.1",
@@ -8423,11 +8280,11 @@
"pathe": "^1.1.1",
"picocolors": "^1.0.0",
"std-env": "^3.5.0",
- "strip-literal": "^1.3.0",
+ "strip-literal": "^2.0.0",
"tinybench": "^2.5.1",
- "tinypool": "^0.8.1",
- "vite": "^5.0.0-beta.19 || ^5.0.0",
- "vite-node": "1.0.0",
+ "tinypool": "^0.8.2",
+ "vite": "^5.0.0",
+ "vite-node": "1.3.1",
"why-is-node-running": "^2.2.2"
},
"bin": {
@@ -8442,8 +8299,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
- "@vitest/browser": "*",
- "@vitest/ui": "*",
+ "@vitest/browser": "1.3.1",
+ "@vitest/ui": "1.3.1",
"happy-dom": "*",
"jsdom": "*"
},
@@ -8512,15 +8369,6 @@
"node": ">=18"
}
},
- "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": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
@@ -8662,28 +8510,6 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
},
- "node_modules/xss": {
- "version": "1.0.14",
- "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.14.tgz",
- "integrity": "sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==",
- "peer": true,
- "dependencies": {
- "commander": "^2.20.3",
- "cssfilter": "0.0.10"
- },
- "bin": {
- "xss": "bin/xss"
- },
- "engines": {
- "node": ">= 0.10.0"
- }
- },
- "node_modules/xss/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==",
- "peer": true
- },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/web/package.json b/web/package.json
index b7734e3ab..01716f940 100644
--- a/web/package.json
+++ b/web/package.json
@@ -17,8 +17,10 @@
"@hookform/resolvers": "^3.3.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-aspect-ratio": "^1.0.3",
+ "@radix-ui/react-context-menu": "^2.1.5",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
+ "@radix-ui/react-hover-card": "^1.0.7",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.1.3",
@@ -28,37 +30,42 @@
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
+ "@radix-ui/react-toggle": "^1.0.3",
+ "@radix-ui/react-toggle-group": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.7",
"apexcharts": "^3.45.1",
"axios": "^1.6.2",
"class-variance-authority": "^0.7.0",
- "clsx": "^2.0.0",
+ "clsx": "^2.1.0",
"copy-to-clipboard": "^3.3.3",
"date-fns": "^2.30.0",
"idb-keyval": "^6.2.1",
"immer": "^10.0.3",
"lucide-react": "^0.294.0",
- "monaco-yaml": "^5.1.0",
+ "monaco-yaml": "^5.1.1",
"next-themes": "^0.2.1",
"react": "^18.2.0",
"react-apexcharts": "^1.4.1",
"react-day-picker": "^8.9.1",
+ "react-device-detect": "^2.2.3",
"react-dom": "^18.2.0",
"react-hook-form": "^7.48.2",
"react-icons": "^4.12.0",
"react-router-dom": "^6.20.1",
- "react-use-websocket": "^4.5.0",
+ "react-swipeable": "^7.0.1",
+ "react-tracked": "^1.7.11",
+ "react-transition-group": "^4.4.5",
+ "react-use-websocket": "^4.7.0",
"recoil": "^0.7.7",
"sonner": "^1.4.0",
"sort-by": "^1.2.0",
"strftime": "^0.10.2",
- "swr": "^2.2.4",
+ "swr": "^2.2.5",
"tailwind-merge": "^2.1.0",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.8.0",
"video.js": "^8.6.1",
"videojs-playlist": "^5.1.0",
- "vis-timeline": "^7.7.3",
"vite-plugin-monaco-editor": "^1.1.0",
"zod": "^3.22.4"
},
@@ -69,13 +76,14 @@
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@types/react-icons": "^3.0.0",
+ "@types/react-transition-group": "^4.4.10",
"@types/strftime": "^0.9.8",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
- "@vitejs/plugin-react-swc": "^3.5.0",
+ "@vitejs/plugin-react-swc": "^3.6.0",
"@vitest/coverage-v8": "^1.0.0",
"autoprefixer": "^10.4.16",
- "eslint": "^8.53.0",
+ "eslint": "^8.55.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest": "^27.6.0",
"eslint-plugin-prettier": "^5.0.1",
@@ -85,12 +93,12 @@
"fake-indexeddb": "^5.0.1",
"jest-websocket-mock": "^2.5.0",
"jsdom": "^23.0.1",
- "msw": "^2.0.10",
+ "msw": "^2.2.1",
"postcss": "^8.4.32",
- "prettier": "^3.1.0",
- "tailwindcss": "^3.3.5",
+ "prettier": "^3.2.5",
+ "tailwindcss": "^3.4.1",
"typescript": "^5.2.2",
- "vite": "^5.0.0",
- "vitest": "^1.0.0"
+ "vite": "^5.1.4",
+ "vitest": "^1.3.1"
}
}
diff --git a/web/postcss.config.js b/web/postcss.config.js
index 2e7af2b7f..2aa7205d4 100644
--- a/web/postcss.config.js
+++ b/web/postcss.config.js
@@ -3,4 +3,4 @@ export default {
tailwindcss: {},
autoprefixer: {},
},
-}
+};
diff --git a/web/public/fonts/Inter-VariableFont_slnt,wght.ttf b/web/public/fonts/Inter-VariableFont_slnt,wght.ttf
new file mode 100644
index 000000000..e72470871
Binary files /dev/null and b/web/public/fonts/Inter-VariableFont_slnt,wght.ttf differ
diff --git a/web/src/App.tsx b/web/src/App.tsx
index 46fcc5b64..9bbb666f8 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -1,12 +1,8 @@
import Providers from "@/context/providers";
import { BrowserRouter, Routes, Route } from "react-router-dom";
-import { useState } from "react";
import Wrapper from "@/components/Wrapper";
-import Sidebar from "@/components/Sidebar";
-import Header from "@/components/Header";
-import Dashboard from "@/pages/Dashboard";
+import Sidebar from "@/components/navigation/Sidebar";
import Live from "@/pages/Live";
-import History from "@/pages/History";
import Export from "@/pages/Export";
import Storage from "@/pages/Storage";
import System from "@/pages/System";
@@ -15,29 +11,27 @@ import Logs from "@/pages/Logs";
import NoMatch from "@/pages/NoMatch";
import Settings from "@/pages/Settings";
import UIPlayground from "./pages/UIPlayground";
+import Events from "./pages/Events";
+import { isDesktop, isMobile } from "react-device-detect";
+import Statusbar from "./components/Statusbar";
+import Bottombar from "./components/navigation/Bottombar";
function App() {
- const [sheetOpen, setSheetOpen] = useState(false);
-
- const toggleNavbar = () => {
- setSheetOpen((prev) => !prev);
- };
-
return (
-
-
-
+
+ {isDesktop && }
+ {isDesktop && }
+ {isMobile && }